Skip to main content

Raw LLM

The simplest way to context engineer.

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

PyPI version Python versions License: MIT

What is this?

Raw LLM 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

From PyPI

pip install raw-llm

This installs the claude, sonnet, opus, haiku, and gemini commands globally.

From source

git clone https://github.com/rodolfovillaruz/raw-llm.git
cd raw-llm
pip install .

Development install

git clone https://github.com/rodolfovillaruz/raw-llm.git
cd raw-llm
pip install -e ".[dev]"

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

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

Resume an existing conversation

claude .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 | claude conversation.json

Switch models

# By flag
claude -m claude-opus-4-6

# By command name
opus
haiku
sonnet
Command Default model
claude / sonnet claude-sonnet-4-6
opus claude-opus-4-6
haiku claude-haiku-4-5
gemini gemini-3.1-pro-preview

Options

usage: claude [-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. Each message carries the standard API fields plus metadata that Raw LLM writes automatically:

[
  {
    "role": "user",
    "content": "What is context engineering?",
    "timestamp": "2025-01-15T10:23:45.123456+00:00"
  },
  {
    "role": "assistant",
    "content": "Context engineering is the practice of ...",
    "timestamp": "2025-01-15T10:23:47.654321+00:00",
    "usage": { "input": 18, "output": 312 },
    "model": "claude-sonnet-4-6"
  }
]
Field Added to Description
timestamp every turn UTC time the message was appended (ISO-8601)
usage assistant input and output token counts for that turn
model assistant Model that produced the response

Metadata fields are stripped automatically before the conversation is sent to the API, so you can safely edit or add them without breaking future turns.

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

Project structure

.
├── src/
│   └── raw_llm/
│       ├── claude.py       # Claude CLI client
│       ├── gemini.py       # Gemini CLI client
│       └── common.py       # Shared utilities (streaming, I/O, conversation management)
├── pyproject.toml          # Package configuration and entry points
├── 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. Raw LLM removes them. The conversation is a file. The prompt is stdin. The response is stdout. Everything else is up to you.

License

MIT

Metadata

Release files for raw-llm 1.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for raw-llm 1.1.1
File Size Uploaded Provenance Actions
raw_llm-1.1.1.tar.gz 14.4 kB Without provenance Details for raw_llm-1.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for raw-llm 1.1.1
File Interpreter ABI Platform Actions
raw_llm-1.1.1-py3-none-any.whl Python 3 none any Details for raw_llm-1.1.1-py3-none-any.whl

Total release size: 28.5 kB

Release files / raw_llm-1.1.1.tar.gz

Download URL raw_llm-1.1.1.tar.gz
Size 14.4 kB
Tags Source
SHA-256 checksum
How to use checksums
71527eef165b47ae90ed434042f807aaefcb70d8d0ba227af94bacb9e5f87e70
BLAKE2b-256 checksum
How to use checksums
ebc004c15429d926e43a712457f463fcb5cd1373a97feb3452184dc35d2fcd33
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.20

Release files / raw_llm-1.1.1-py3-none-any.whl

Download URL raw_llm-1.1.1-py3-none-any.whl
Size 14.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6f5dfec93537ae42207b5ac80fe297cb57814af313785bb37bb56a78c9988068
BLAKE2b-256 checksum
How to use checksums
6439e04389f039a8c53dd2bf2d672a69db11cd0bd2674ef0b7a338acd8d257ff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.20

Security for raw-llm 1.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page