Deterministic conversational state engine for LLM applications.
Project description
Context Compiler
A deterministic directive engine that converts explicit user instructions into structured conversational state for LLM applications.
LLMs are good at reasoning but unreliable at maintaining consistent state. Constraints drift, corrections compete, and long conversations accumulate contradictions.
The Context Compiler introduces a deterministic state layer that governs authoritative conversational state independently of the model.
The model performs reasoning and generation while the compiler manages premise and policies. Once accepted, directives remain authoritative until explicitly corrected or reset.
Quickstart
pip install context-compiler
context-compiler
Or in code:
from context_compiler import create_engine
engine = create_engine()
user_input = "prohibit peanuts"
decision = engine.step(user_input)
if decision["kind"] == "clarify":
show_to_user(decision["prompt_to_user"])
elif decision["kind"] == "update":
messages = build_messages(engine.state, user_input)
render(call_llm(messages))
else:
render(call_llm(user_input))
Installation
Requirements:
- Python 3.11+
Install:
pip install context-compiler
Packaging notes:
- Base install includes core engine modules and
examples/artifacts. - LLM demos require:
pip install "context-compiler[demos]". - Optional preprocessor support:
pip install "context-compiler[experimental]". - Integration-oriented dependency support:
pip install "context-compiler[integrations]". - LiteLLM Proxy example dependency bundle:
pip install "context-compiler[litellm_proxy]". - Host runtimes (for example, Open WebUI) are not installed by
integrations.
Development
uv sync --group dev
uv run pytest
Why “Compiler”?
Context Compiler treats explicit user directives as inputs to a deterministic process.
Instead of relying on the LLM to remember constraints across a conversation, user instructions are compiled into structured state before the model runs.
The idea is similar to a traditional compiler: user directives are translated into a structured representation that the rest of the system can rely on.
10-Second Example
User sets a constraint once:
User: prohibit peanuts
Outcome: policy state includes "peanuts": "prohibit".
Later in the conversation:
User: how should I make this curry?
The host supplies the authoritative state to the model so the constraint persists across turns.
Deterministic behavior (examples)
LLMs interpret intent. Context Compiler enforces it.
Explicit directive
set premise concise replies
- Base model: silently accepts / rewrites
- Context Compiler: applies a deterministic state update
State-dependent operation
clear state
use podman instead of docker
- Base model: generic explanation
- Context Compiler: rejects (“No exact policy found for 'docker'…”)
Lifecycle enforcement
clear state
change premise to formal tone
- Base model: conversational rewrite guidance
- Context Compiler: clarifies (“No premise exists yet…”)
Architecture
User Input
│
▼
Context Compiler
│
▼
Decision
│
▼
Host Application
├─ clarify → ask user
├─ passthrough → call LLM
└─ update → call LLM with compiled state
The compiler governs authoritative state and never calls the LLM.
The host decides whether to call the model based on the returned Decision.
Decision API
Each user message produces a Decision.
class Decision(TypedDict):
kind: Literal["passthrough", "update", "clarify"]
state: dict | None
prompt_to_user: str | None
Meaning:
| kind | host behavior |
|---|---|
| passthrough | forward user input to LLM |
| update | forward input with updated state |
| clarify | show prompt_to_user and do not call the LLM |
API Reference
| API | Description |
|---|---|
create_engine(state=None) |
Create a new compiler engine; optional state provides initial authoritative state (validated/canonicalized). |
step(user_input) |
Parse one user turn and return a deterministic Decision. |
compile_transcript(messages: Transcript) |
Replay a transcript from a fresh engine and return either final state or a confirmation prompt. |
engine.apply_transcript(messages: Transcript) |
Replay a transcript onto the current engine state and return either final state or a confirmation prompt. |
engine.state |
Read current authoritative in-memory state snapshot. |
get_premise_value(state) |
Read the current premise value from a state snapshot. |
get_policy_items(state, value=None) |
Read policy items from a state snapshot (all, use, or prohibit). |
engine.export_json() |
Export current state as JSON for persistence/transport. |
engine.import_json(payload) |
Load/restore state from exported JSON payload. |
State Model
The compiler maintains an authoritative state snapshot.
- Premise is a single value that can be set or replaced
- Policies are per-item (
useorprohibit) - State changes only through explicit directives
- No inference or semantic reasoning
Identical input sequences always produce identical state.
The internal structure of the state is intentionally opaque to host applications.
When to use premise
The premise is intended for persistent context that changes how all answers should be interpreted, especially when it:
- applies across many turns
- significantly changes what solutions are valid
- cannot be fully captured as simple
use/prohibitpolicies
Examples:
- “Current medications: …”
- “Outdoor event; no seating available”
- “GDPR data handling requirements apply”
- “System is deployed across multiple regions”
- “Limited time available”
In these cases, the premise acts as an authoritative context anchor that the host supplies to the model on every turn.
Use policies instead when the constraint is explicit and enforceable:
- “prohibit foods that may cause GI upset”
- “use handheld foods”
- “prohibit storing personal data beyond immediate use”
- “prohibit introducing new external dependencies”
- “use single-step preparation methods”
Directive Examples
Set and change premise:
User: set premise concise replies
User: change premise to concise bullet points
Per-item policies:
User: use docker
User: prohibit peanuts
Replacement:
User: use podman instead of docker
Removal and reset:
User: remove policy peanuts
User: reset policies
User: clear state
Conflicting directives trigger clarification instead of changing state.
For full directive grammar and edge-case behavior, see DirectiveGrammarSpec.md.
Examples
Guarantees
- State changes only through explicit user directives or confirmation.
- Identical input sequences produce identical compiler state.
- Model responses never modify compiler state.
- Ambiguous directives trigger clarification instead of changing state.
These invariants are verified through behavioral tests and Hypothesis-based property tests.
Evidence
Behavioral correctness (key examples)
Concrete behavioral comparisons (base model vs compiler) are available here:
These demonstrate deterministic clarification, state enforcement, and conflict handling.
Cross-model evaluation
- Models tested:
llama3.1:8b,gpt-4o-mini,gpt-4.1,gpt-5,claude-sonnet-4,claude-opus-4 - Pass-rate summary: baseline (LLM only)
2–4 / 6; with compiler6 / 6; with compiler + compaction6 / 6.
Efficiency
- Context reduction in long conversations: up to
99% - Prompt size reduction: about
50%
Additional results
- SWE curated results (compiler vs baseline) — cross-model evaluation on 6 tasks showing mostly positive deltas
Optional: LLM Preprocessor (Experimental)
An optional host-side preprocessor can convert natural-language instructions into canonical directives before compilation.
It is designed to be conservative and must be used with validation:
- heuristic-first, with LLM fallback when needed
- all outputs must be validated with
parse_precompiler_output(...) - raw outputs must not be passed directly to the compiler
See LLM preprocessor and
experimental/preprocessor/ for details.
Advanced topics
For a full documentation map, see docs/README.md.
Design Notes
More detailed design and milestone documents are available in:
Conformance Fixtures
Cross-language conformance tests are defined in tests/fixtures/.
License
Apache-2.0.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file context_compiler-0.6.6.tar.gz.
File metadata
- Download URL: context_compiler-0.6.6.tar.gz
- Upload date:
- Size: 302.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
988841542a2c9a36ca80475e2f97e99ba80b72b6576dd384668d3b8fda57981b
|
|
| MD5 |
08a84c9ddad4bdbd25516371798c48be
|
|
| BLAKE2b-256 |
3576fe1c6351332cf57a16dd788daddc72f567f88b4f5de73046ffea46066ae8
|
Provenance
The following attestation bundles were made for context_compiler-0.6.6.tar.gz:
Publisher:
publish-pypi.yml on rlippmann/context-compiler
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
context_compiler-0.6.6.tar.gz -
Subject digest:
988841542a2c9a36ca80475e2f97e99ba80b72b6576dd384668d3b8fda57981b - Sigstore transparency entry: 1331086275
- Sigstore integration time:
-
Permalink:
rlippmann/context-compiler@26a9333abbc62b7b34ec1db75553366c0e0b4559 -
Branch / Tag:
refs/tags/v0.6.6 - Owner: https://github.com/rlippmann
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@26a9333abbc62b7b34ec1db75553366c0e0b4559 -
Trigger Event:
release
-
Statement type:
File details
Details for the file context_compiler-0.6.6-py3-none-any.whl.
File metadata
- Download URL: context_compiler-0.6.6-py3-none-any.whl
- Upload date:
- Size: 56.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a2f69000156740d64cef791747bcc19b8635d958fc91c1762475d8c6dba1b615
|
|
| MD5 |
419a4d96cd1bc9ef6a0f7643ca26726e
|
|
| BLAKE2b-256 |
d629ce883152c2ab60f262cb87920a5281431bf43b181468d52f2cf5d469c983
|
Provenance
The following attestation bundles were made for context_compiler-0.6.6-py3-none-any.whl:
Publisher:
publish-pypi.yml on rlippmann/context-compiler
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
context_compiler-0.6.6-py3-none-any.whl -
Subject digest:
a2f69000156740d64cef791747bcc19b8635d958fc91c1762475d8c6dba1b615 - Sigstore transparency entry: 1331086342
- Sigstore integration time:
-
Permalink:
rlippmann/context-compiler@26a9333abbc62b7b34ec1db75553366c0e0b4559 -
Branch / Tag:
refs/tags/v0.6.6 - Owner: https://github.com/rlippmann
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@26a9333abbc62b7b34ec1db75553366c0e0b4559 -
Trigger Event:
release
-
Statement type: