Skip to main content

The simplest way to context engineer. Minimal streaming CLI clients for Claude and Gemini.

Project description

Simple

The simplest way to context engineer.

Minimal, streaming CLI clients for Claude and Gemini that keep your conversations in plain JSON files.

What is this?

Simple is a pair of thin Python scripts that talk to the Anthropic and Google GenAI APIs. No frameworks, no agents, no abstractions you don't need. Just a prompt, a streaming response, and a JSON file you can version, diff, edit, and pipe.

The entire idea: your conversation is a file. You build context by editing that file. That's it. That's the context engineering.

Features

  • Streaming output — responses print token-by-token as they arrive
  • Conversation persistence — every exchange is saved to a plain JSON file you own
  • Resume any conversation — pass the JSON file back in to continue where you left off
  • Pipe-friendly — reads from stdin, writes content to stdout, writes diagnostics to stderr
  • Colored output — reasoning in gray (stderr), content in cyan (stdout), auto-disabled when piped
  • Conflict detection — refuses to overwrite a conversation file modified by another process
  • Symlink to switch models — symlink claude.py as opus or haiku to change the default model

Installation

git clone https://github.com/rodolfovillaruz/simple.git
cd simple
pip install anthropic google-genai

Set your API keys:

export ANTHROPIC_API_KEY="sk-ant-..."
export GEMINI_API_KEY="..."       # or GOOGLE_API_KEY, per google-genai docs

Usage

Start a new conversation

python claude.py
# Type your prompt, then press Ctrl+D to submit
echo "Explain monads in one paragraph" | python claude.py
python gemini.py

Resume an existing conversation

python claude.py .prompt/some-conversation.json

The JSON file contains the full message history. Edit it with any text editor to reshape context before your next turn.

Pipe a file as context

cat code.py | python claude.py conversation.json

Switch models

# By flag
python claude.py -m claude-opus-4-6

# By symlink
ln -s claude.py opus
./opus
Symlink name Default model
claude.py (default) claude-sonnet-4-6
claude-opus / opus claude-opus-4-6
claude-haiku / haiku claude-haiku-4-5
gemini.py (default) gemini-3.1-pro-preview

Options

usage: claude.py [-h] [-n] [-v] [-m MODEL] [-t MAX_TOKENS] [-i] [conversation_file]

positional arguments:
  conversation_file         JSON file to resume (omit to start fresh)

options:
  -n, --dry-run             Build the prompt but don't send it
  -v, --verbose             Show model name and prompt preview
  -m, --model MODEL         Override the default model
  -t, --max-tokens TOKENS   Cap the response length
  -i, --interactive         Interactive REPL mode

Conversation format

Conversations are stored as a JSON array of message objects, the same shape both APIs understand:

[
  {
    "role": "user",
    "content": "What is context engineering?"
  },
  {
    "role": "assistant",
    "content": "Context engineering is the practice of ..."
  }
]

You can create these files by hand, merge them, truncate them, or generate them with other tools. Simple doesn't care. It reads the array, appends your new message, streams the response, and appends that too.

Project structure

.
├── claude.py       # Claude CLI client
├── gemini.py       # Gemini CLI client
├── common.py       # Shared utilities (streaming, I/O, conversation management)
├── Makefile        # Formatting, linting, typing
└── .prompt/        # Default directory for conversation files (auto-used if present)

Development

make fmt      # Format with black/isort
make lint     # Lint with pylint/flake8
make type     # Type-check with mypy
make all      # All of the above

Why?

Most LLM tools add layers between you and the model. Simple removes them. The conversation is a file. The prompt is stdin. The response is stdout. Everything else is up to you.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

raw_llm-1.0.0.tar.gz (11.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

raw_llm-1.0.0-py3-none-any.whl (10.6 kB view details)

Uploaded Python 3

File details

Details for the file raw_llm-1.0.0.tar.gz.

File metadata

  • Download URL: raw_llm-1.0.0.tar.gz
  • Upload date:
  • Size: 11.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for raw_llm-1.0.0.tar.gz
Algorithm Hash digest
SHA256 1bdd791a7908cae76668a8f3e684bb295dafc2d41ecf1c6a3ab6b4a531481db1
MD5 e98236053f48ddb1450e81ed2df074a6
BLAKE2b-256 689b25c2ee8728a66de22e096e31f94ec12521f943bb37b2d3bc23144a70daa1

See more details on using hashes here.

File details

Details for the file raw_llm-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: raw_llm-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 10.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for raw_llm-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 18f3a6711147673825f638b03d25f8848a2c41dd27d19b0a50550b979fced92e
MD5 5451107e56ca04d79692c4dd623d187f
BLAKE2b-256 73fef7b123bb0e5a091a9ab5a20456a522028f61d75f7186d5058cbe4cc89bbe

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page