{"id":47268016,"url":"https://github.com/rlippmann/context-compiler","last_synced_at":"2026-05-26T07:02:19.394Z","repository":{"id":341774260,"uuid":"1171381527","full_name":"rlippmann/context-compiler","owner":"rlippmann","description":"Deterministic state engine for managing conversation state and constraints in LLM applications.","archived":false,"fork":false,"pushed_at":"2026-05-13T04:59:06.000Z","size":1807,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-19T05:52:55.958Z","etag":null,"topics":["ai","ai-infrastructure","conversation-state","llm","llm-tools","python-library","state-machine"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/context-compiler/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rlippmann.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-03T06:58:57.000Z","updated_at":"2026-05-13T04:56:52.000Z","dependencies_parsed_at":"2026-04-16T07:02:15.686Z","dependency_job_id":null,"html_url":"https://github.com/rlippmann/context-compiler","commit_stats":null,"previous_names":["rlippmann/context-compiler"],"tags_count":32,"template":false,"template_full_name":null,"purl":"pkg:github/rlippmann/context-compiler","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rlippmann%2Fcontext-compiler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rlippmann%2Fcontext-compiler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rlippmann%2Fcontext-compiler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rlippmann%2Fcontext-compiler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rlippmann","download_url":"https://codeload.github.com/rlippmann/context-compiler/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rlippmann%2Fcontext-compiler/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33508317,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T03:12:49.672Z","status":"ssl_error","status_checked_at":"2026-05-26T03:12:47.976Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","ai-infrastructure","conversation-state","llm","llm-tools","python-library","state-machine"],"created_at":"2026-03-15T07:31:13.222Z","updated_at":"2026-05-26T07:02:19.387Z","avatar_url":"https://github.com/rlippmann.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Context Compiler\n\n[![PyPI version](https://img.shields.io/pypi/v/context-compiler)](https://pypi.org/project/context-compiler/)\n[![Python versions](https://img.shields.io/pypi/pyversions/context-compiler)](https://pypi.org/project/context-compiler/)\n[![License](https://img.shields.io/pypi/l/context-compiler)](https://pypi.org/project/context-compiler/)\n\nSome behaviors require explicit host-side state machinery.\n\nContext Compiler is a deterministic host-side state layer for LLM applications.\nIt handles explicit state transitions for premise and policies so that mutation\nrules are fixed and repeatable.\n\n## What prompting and reinjection can do\n\nPrompting and reinjection are useful. In many real systems, reinjecting saved\nstate text is enough to keep instructions and policies persistent across turns.\n\nContext Compiler adds host-owned transition rules for behaviors that plain text\nreinjection does not implement by itself: replace `X` only if `X` exists, block\nconflicting changes and ask for confirmation, and restore saved state plus\npending confirmations from checkpoints.\n\n## What prompting cannot do by itself\n\nPrompt text (including reinjected state text) helps, but it does not give your\napp controlled rules for when state can change. By itself, it does not provide:\n\n- rules your app controls for state changes\n- replacement precondition checks (`use X instead of Y` when `Y` may be absent)\n- confirmation flows that must complete before anything else changes\n- clear decisions about when a change is blocked\n- reliable checkpoint restore for both saved state and pending confirmation flow\n\n## What Context Compiler provides\n\nContext Compiler provides fixed host-side state machinery:\n\n- deterministic directive handling for explicit user state changes\n- clarification instead of silent overwrite for blocked/ambiguous changes\n- pending confirmation flows that must resolve before anything else changes\n- checkpoint export/import for restoring saved state and pending confirmation flow\n- structured saved state that the host can pass to the model\n\nThe model generates responses. The compiler owns state transitions.\n\n## How the compiler metaphor works\n\nContext Compiler treats important instructions as structured state instead of\ntemporary prompt text.\n\nLike a compiler, it parses input, validates it, applies fixed rules, and\nproduces a stable representation the host can use. It is not source-code\ncompilation and not a reasoning model.\n\n## Does it work?\n\nYes, on the current scored demo set.\n\n- Scope: evaluated across **7 models** and **3 provider paths** (`ollama`, `openai`, `openai_compatible`).\n- Scored checks (**6 demos per model**; Demo 6 excluded): baseline **26 / 42**, compiler **42 / 42**, compiler+compact **42 / 42**.\n- Across tested models, compiler-mediated paths pass all scored scenarios; baseline behavior is model-dependent.\n\nInterpretation guide:\n- Demos `01`-`05` and `07` focus on persistence and policy-following behavior.\n- Demos `08`/`09` focus on rules for when state is allowed to change.\n- Demos `08`/`09` show what prompt text does not implement by itself.\n- Plain reinjection can produce plausible responses, but it does not check whether replacement is allowed or wait for confirmation before saving changes.\n\n→ [Full results and demo output](demos/README.md)\nCanonical matrix: [docs/demos-results.md](docs/demos-results.md)\n\n## Quickstart\n\n```bash\npip install context-compiler\ncontext-compiler\ncontext-compiler --with-preprocessor\ncontext-compiler --json \u003c input.txt\n```\n\n`context-compiler` launches the interactive REPL.\n\n`--with-preprocessor` enables the experimental preprocessor before each REPL turn\n(simple rule-based checks plus conservative validation). For near-miss inputs,\nthe preprocessor does not rewrite the text. It passes the input to the engine,\nand the engine can return `clarify`.\n\n`--json` enables machine-readable NDJSON output for non-interactive usage\n(one complete JSON object per processed input line).\n\nPreload options keep saved rules separate from in-progress confirmation state:\n- `--initial-state-json` / `--initial-state-file` load saved state\n  (via exported state JSON).\n- `--initial-checkpoint-json` / `--initial-checkpoint-file` restore full\n  continuation checkpoint (saved state + pending confirmation state).\n\nREPL commands (controller layer, not engine directives):\n- `state` shows current saved state.\n- `preview \u003cinput\u003e` runs deterministic dry-run without mutating live state.\n- `step \u003cinput\u003e` is an explicit alias of normal bare-input step behavior.\n\nBare REPL input behavior remains unchanged.\n\nOr in code:\n```python\nfrom context_compiler import DECISION_CLARIFY, DECISION_UPDATE, create_engine\n\nengine = create_engine()\n\nuser_input = \"prohibit peanuts\"\ndecision = engine.step(user_input)\n\nif decision[\"kind\"] == DECISION_CLARIFY:\n    show_to_user(decision[\"prompt_to_user\"])\nelif decision[\"kind\"] == DECISION_UPDATE:\n    messages = build_messages(engine.state, user_input)\n    render(call_llm(messages))\nelse:\n    render(call_llm(user_input))\n```\n\n## Installation\n\nRequirements:\n- Python 3.11+\n\nInstall:\n```bash\npip install context-compiler\n```\n\nPackaging notes:\n- Base install includes core engine modules and `examples/` artifacts.\n- LLM demos require: `pip install \"context-compiler[demos]\"`.\n- Optional preprocessor support: `pip install \"context-compiler[experimental]\"`.\n- Integration-oriented dependency support: `pip install \"context-compiler[integrations]\"`.\n- LiteLLM Proxy example dependency bundle: `pip install \"context-compiler[litellm_proxy]\"`.\n- Host runtimes (for example, Open WebUI) are not installed by `integrations`.\n\n### Development\n\n```bash\nuv sync --group dev\nuv run pytest\n```\n\n---\n\n## FAQ\n\n**Is this just prompt reinjection?**\nReinjection helps with persistence, and it remains useful. Context Compiler\nhandles a different problem: rules for when state is allowed to change.\n\nExamples:\n- replacement semantics (`use X instead of Y`) when `Y` may not exist\n- contradiction detection before applying a mutation\n- lifecycle enforcement (for example, you cannot change an unset premise)\n- pending clarification flows that must be resolved before other mutations\n\nIn short: reinjection carries state forward; Context Compiler decides when your\napp should change state.\n\n**Isn’t this just prompt engineering?**\nIt complements prompt engineering, but solves a different problem. Prompting\nshapes model behavior. Context Compiler enforces state rules and updates state\nonly through explicit directives.\n\n---\n\n## 10-Second Example\n\nUser sets a constraint once:\n\n```text\nUser: prohibit peanuts\n```\n\nOutcome: policy state includes `\"peanuts\": \"prohibit\"`.\n\nLater in the conversation:\n\n```text\nUser: how should I make this curry?\n```\n\nYour host sends the saved policy state with this later request, so the model is\nconstrained by explicit state (`peanuts: prohibit`) instead of relying on memory\nof earlier conversation text.\n\n---\n\n## Deterministic behavior (examples)\n\nContext Compiler makes mutation rules explicit so behavior stays repeatable.\n\n**Explicit directive**\n```text\nset premise concise replies\n```\n- Base model: silently accepts / rewrites\n- Context Compiler: applies a repeatable state update\n\n**State-dependent operation**\n```text\nclear state\nuse podman instead of docker\n```\n- Without explicit state transition rules: behavior depends on host/model handling\n- Context Compiler: returns `clarify` before changing state\n\n**Lifecycle enforcement**\n```text\nclear state\nchange premise to formal tone\n```\n- Without explicit transition checks: behavior depends on host/model handling\n- Context Compiler: asks for clarification and keeps saved state unchanged\n\n---\n\n## Architecture\n\n```text\nUser Input\n     │\n     ▼\nContext Compiler\n     │\n     ▼\nDecision\n     │\n     ▼\nHost Application\n ├─ clarify → ask user\n ├─ passthrough → call LLM\n └─ update → authoritative state mutated; host may call LLM with compiled state\n```\n\nThe compiler owns state updates and never calls the LLM.\nYour app decides whether to call the model based on the returned `Decision`.\n\n---\n\n## Decision API\n\nEach user message produces a `Decision`.\n\n```python\nclass Decision(TypedDict):\n    kind: Literal[\"passthrough\", \"update\", \"clarify\"]\n    state: dict | None\n    prompt_to_user: str | None\n```\n\nMeaning:\n\n| kind        | host behavior                                 |\n|:-----------:|-----------------------------------------------|\n| passthrough | forward user input to LLM                     |\n| update      | authoritative state mutated; host may call LLM with updated state |\n| clarify     | show `prompt_to_user` and do not call the LLM |\n\n---\n\n### API Reference\n\n| API | Description |\n|---|---|\n| `create_engine(state=None)` | Create a new compiler engine; optional `state` provides initial authoritative state (validated/canonicalized). |\n| `step(user_input)` | Parse one user turn and return a deterministic `Decision`. |\n| `compile_transcript(messages: Transcript)` | Replay a transcript from a fresh engine and return either final state or a confirmation prompt. |\n| `engine.apply_transcript(messages: Transcript)` | Replay a transcript onto the current engine state and return either final state or a confirmation prompt. |\n| `engine.state` | Read current authoritative in-memory state snapshot. |\n| `engine.has_pending_clarification()` | Return whether a confirmation-required clarification is currently pending. |\n| `get_premise_value(state)` | Read the current premise value from a state snapshot. |\n| `get_policy_items(state, value=None)` | Read policy items from a state snapshot (all, `use`, or `prohibit`). |\n| `engine.export_json()` | Export authoritative state as JSON (`str`) for state transport/persistence. |\n| `engine.import_json(payload)` | Load/restore authoritative state from exported JSON (`str`). |\n| `engine.export_checkpoint()` | Export resumable checkpoint object (`Checkpoint`). |\n| `engine.import_checkpoint(payload)` | Restore full checkpoint (`Checkpoint`) and return `None`. |\n| `engine.export_checkpoint_json()` | Export checkpoint as canonical JSON (`str`). |\n| `engine.import_checkpoint_json(payload)` | Restore checkpoint from JSON (`str`) and return `None`. |\n\n### Controller API (Reusable Outside REPL)\n\nThese controller APIs are public package exports and can be used directly\nin app code (not just inside the REPL).\n\n| API | Description |\n|---|---|\n| `step(engine, user_input)` | Run one turn through the engine and return `StepResult` (`output_version`, `mode`, `decision`, `state`). |\n| `preview(engine, user_input)` | Run deterministic dry-run preview and return `PreviewResult` (`output_version`, `mode`, `decision`, `state_before`, `state_after`, `diff`, `would_mutate`). Live engine state is restored after preview. |\n| `state_diff(state_before, state_after)` | Return a structural `StructuralDiff` (`changed`, premise before/after, policies added/removed/changed). |\n\nDecision-kind constants are also exported for host branching readability:\n- `DECISION_PASSTHROUGH`\n- `DECISION_UPDATE`\n- `DECISION_CLARIFY`\n\n---\n\n## State Model\n\nThe compiler keeps a current state snapshot that your app can trust.\n\n- Premise is a single value that can be set or replaced\n- Policies are per-item (`use` or `prohibit`)\n- State changes only through explicit directives\n- No inference or semantic reasoning\n\nIdentical input sequences always produce identical state.\n\nThe internal structure of the state is intentionally opaque to host applications.\n\n---\n\n## Checkpoint Contract\n\n`export_json()` / `import_json()` and checkpoint APIs serve different boundaries:\n\n- `export_json()` / `import_json()` transport **authoritative state only**\n- checkpoint APIs transport **serialized continuation**:\n  - authoritative state\n  - pending confirmation flow state\n\nCheckpoint object shape:\n\n```json\n{\n  \"checkpoint_version\": 1,\n  \"authoritative_state\": {\n    \"premise\": \"concise replies\",\n    \"policies\": {\n      \"docker\": \"use\"\n    },\n    \"version\": 2\n  },\n  \"pending\": {\n    \"kind\": \"replacement\",\n    \"replacement\": {\n      \"kind\": \"use_only\",\n      \"new_item\": \"kubectl\",\n      \"old_item\": null\n    },\n    \"prompt_to_user\": \"...\"\n  }\n}\n```\n\nNotes:\n\n- `pending` is `null` when no continuation is waiting for confirmation.\n- `pending` captures confirmation-required operations (for example replacement flows).\n- `old_item` may be `null` for `\"use_only\"` when confirming “use X instead?” without an existing exact policy to replace.\n- imported policy keys are normalized during `import_json` / checkpoint authoritative-state restore.\n- if a policy key normalizes to `\"\"`, the payload is invalid and is rejected.\n- this keeps import-time state integrity aligned with directive-time behavior where empty policy items are not allowed.\n- checkpoint restore is full and deterministic: authoritative state and pending continuation are restored together.\n- checkpoint validation is all-or-nothing; invalid payloads raise and no partial restore occurs.\n- `checkpoint_version` is independent of authoritative state `version` and must be bumped when checkpoint contract shape changes (especially `pending`).\n\nWhen to use checkpoint APIs:\n\n- stateless host/integration boundaries where engine instances are short-lived.\n- resume after interruption without losing pending clarification flow.\n- preserve pending confirmation flow state (`pending`) across process/request boundaries.\n\n---\n\n### When to use `premise`\n\nThe `premise` is intended for **persistent context that changes how all answers should be interpreted**, especially when it:\n\n- applies across many turns\n- significantly changes what solutions are valid\n- cannot be fully captured as simple `use` / `prohibit` policies\n\nExamples:\n\n- “Current medications: …”\n- “Outdoor event; no seating available”\n- “GDPR data handling requirements apply”\n- “System is deployed across multiple regions”\n- “Limited time available”\n\nIn these cases, the premise acts as an **authoritative context anchor** that the host supplies to the model on every turn.\n\nUse policies instead when the constraint is explicit and enforceable:\n\n- “prohibit foods that may cause GI upset”\n- “use handheld foods”\n- “prohibit storing personal data beyond immediate use”\n- “prohibit introducing new external dependencies”\n- “use single-step preparation methods”\n\n### Example domains\n\nHosts define what policy items and premise mean in context. Common patterns:\n\n- safety-oriented constraints (for example, prohibited materials or tools)\n- authority/evidence constraints (for example, cite only approved sources)\n- software workflow constraints (for example, require `uv`, prohibit `npm`)\n- accessibility/environment constraints (for example, no audio-only outputs)\n\nContext Compiler enforces explicit directive/state mechanics. Domain reasoning\nstill belongs to the host and model workflow.\n\n---\n\n## Directive Examples\n\nSet and change premise:\n\n```text\nUser: set premise concise replies\nUser: change premise to concise bullet points\n```\n\nPer-item policies:\n\n```text\nUser: use docker\nUser: prohibit peanuts\n```\n\nReplacement:\n\n```text\nUser: use podman instead of docker\n```\n\nRemoval and reset:\n\n```text\nUser: remove policy peanuts\nUser: reset policies\nUser: clear state\n```\n\nConflicting directives trigger clarification instead of changing state.\n\nFor full directive grammar and edge-case behavior, see [DirectiveGrammarSpec.md](docs/DirectiveGrammarSpec.md).\n\n---\n\n## Examples\n\n- [examples](examples/) — minimal usage patterns and core integration primitives\n- [demos](demos/) — concrete scenarios showing how behavior differs with and without the compiler\n- [integrations](examples/integrations/) — production-style host integrations (OpenWebUI, LiteLLM, etc.)\n\nIntegration note: current OpenWebUI example pipes return deterministic local\nacknowledgements for directive-only `update` decisions instead of forwarding\nthose turns to the downstream LLM.\n\n---\n\n## Guarantees\n\n- State changes only through explicit user directives or confirmation.\n- Identical input sequences produce identical compiler state.\n- Model responses never modify compiler state.\n- Ambiguous directives trigger clarification instead of changing state.\n\nThese invariants are verified through behavioral tests and Hypothesis-based property tests.\n\n---\n\n## Optional: LLM Preprocessor (Experimental)\n\nAn optional host-side preprocessor can conservatively convert some natural-language instructions\ninto canonical directives before compilation.\n\nIt is designed to be conservative and must be used with validation:\n\n- reject-first; directive-adjacent unsafe forms abstain instead of rewriting\n- all outputs must be validated with `parse_preprocessor_output(...)`\n- no directive grammar expansion\n- raw outputs must not be passed directly to the compiler\n\nSee [LLM preprocessor](docs/llm-preprocessor.md) and\n[`experimental/preprocessor/`](experimental/preprocessor/) for details.\n\n\n## Advanced topics\n\n- [Multiple engines](docs/multi-engine.md)\n\nFor a full documentation map, see [docs/README.md](docs/README.md).\n\n---\n\n## Design Rationale\n\n- [Design philosophy](docs/DesignPhilosophy.md)\n\n---\n\n## Design Notes\n\nMore detailed design and milestone documents are available in:\n\n- [Project overview](docs/DescriptionAndMilestones.md)\n- [Directive grammar specification](docs/DirectiveGrammarSpec.md)\n\n---\n\n## Conformance Fixtures\n\nCross-language conformance tests are defined in [`tests/fixtures/`](tests/fixtures/).\nThese fixtures serve as the behavioral contract for compiler semantics across implementations.\n\n---\n\n## License\n\nApache-2.0.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frlippmann%2Fcontext-compiler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frlippmann%2Fcontext-compiler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frlippmann%2Fcontext-compiler/lists"}