Skip to main content

The transactional memory layer for AI coding agents — your context survives crashes, compaction, and session loss

Project description

Context Guard

CI PyPI

The transactional memory layer for AI coding agents — your context survives crashes, compaction, and session loss.

Leer en español

Aqui un tutorial (también en español) para usuarios no técnicos y novatos


The problem

Long-running agent sessions degrade. Context drift, "lost in the middle," completion hallucination (the agent believes it finished before it verified anything), and — the one that actually loses work — a crash or a compaction mid-task that leaves the repository half-edited with no way back.

context-guard is not another agent framework and it does not write code. It is a small, deterministic state machine that sits between an agent and a project: a manifest on disk that survives the agent's process ending, a strict PLAN → EXECUTE → VERIFY → ARCHIVE pipeline the agent cannot skip phases in, and a transaction log that can be rolled back. If the session dies, the manifest is what the next session reads to pick up exactly where the last one left off — that persistence, not the pipeline shape, is the point.

Quickstart

Five commands: plan a change, get a human to sign off on it, advance into execution, claim a task, and check where things stand.

# (1) start a change — this begins PLAN and scaffolds the artifacts
cg new redis-cache

# fill in the plan — an agent writes this, not you
cat > .context-guard/changes/redis-cache/objective.md <<'EOF'
# Objective: Add Redis caching
Cache the top-N query results behind a 60s TTL.
EOF
cat > .context-guard/changes/redis-cache/tasks.md <<'EOF'
- [ ] 1.1 Add the redis client dependency
- [ ] 1.2 Wrap the query path with a cache lookup
EOF

# (2) a human reviews objective.md and tasks.md, then approves
cg approve

# (3) the recorded approval unlocks EXECUTE
cg commit --next-phase EXECUTE

# (4) claim the next task atomically — safe with several agents at once
cg next-task

# (5) one-shot rehydration after a crash, a compaction, or a new session
cg status

Every line above runs as written against a fresh directory; nothing here is illustrative shorthand.

Install

Two lines, once per machine:

uv tool install context-guard-cli
cg setup

No uv? pipx install context-guard-cli works the same way. Both install into an isolated environment and put cg on PATH globally — the whole point, since cg setup configures your machine once, not once per project. pip install context-guard-cli also works, as a fallback for a plain Python install with no uv/pipx available. Do not use uv pip install context-guard-cli: that installs into whichever venv is currently active — a single project's, if you happen to be inside one — not onto the machine, which silently defeats the point of a global cg setup.

cg setup detects Claude Code, OpenCode and Antigravity, installs the slash commands, and puts cg approve behind each one's permission prompt — see Adapters. It prints every file it touched, and running it again changes nothing.

Per project there is no install step: cg new writes the phase documents into .context-guard/phases/ the first time you start a change.

Optional — the MCP server, for hosts with no shell (Claude Desktop is the case it exists for): cg setup --with-mcp registers it. Every adapter works completely without it; MCP is an alternative transport, not a requirement.

Contributing (development has the rest):

git clone https://github.com/fdomerlo/context-guard.git
cd context-guard && uv venv && uv pip install -e ".[dev]"
git config core.hooksPath .githooks   # activates the pre-commit gate below

Upgrading

uv tool upgrade context-guard-cli && cg setup

The second command is not optional. cg setup copies commands, skills and permission snippets into your host configs; upgrading the package does not touch those copies, so a new version's adapter fixes only reach a machine once cg setup runs again. It is idempotent — safe to run any time.

Phase files already materialised in a project (.context-guard/phases/) are never overwritten, by design: a project keeps the phases it was started with, including your edits. Delete a phase file and run cg new to pull the current version.

How it works

PLAN  →  EXECUTE  →  VERIFY  →  ARCHIVE

Each change (.context-guard/changes/<name>/) moves through this pipeline one phase at a time, enforced by code, not by convention:

  • begin refuses to start a phase that is not the manifest's lock_phase — the DAG is checked before work starts, not only when it is claimed done.
  • commit validates the phase's artifacts (objective.md + tasks.md for PLAN, review-report.md + verify-report.md for VERIFY) contain no leftover [PENDING] marker before advancing lock_phase.
  • begin on a fresh PLAN auto-scaffolds five markdown files — objective.md, snapshot.md, tasks.md, review-report.md, verify-report.md — each starting as [PENDING], so the agent edits templates instead of inventing a shape from scratch.
  • rollback restores the exact manifest snapshot taken when the phase began.
  • Session and write locks are OS-level (O_CREAT|O_EXCL), with liveness-checked stale detection, so two agents on the same change do not silently race each other.
  • Task claims carry a lease (claim-task / next-task / doctor --fix), so several agents can work one change concurrently without two of them picking the same task.
  • --change <name> scopes every command to one change. Several changes active and no --change given is an error naming them — never a silent guess at "the first one."

Threat Model

Read this before you rely on context-guard for anything you actually care about.

The pipeline enforcement (begin/commit validating the DAG and the artifacts) is real code, not a system prompt suggestion — an agent using the cg tool cannot accidentally skip a phase or advance past [PENDING] artifacts. But that enforcement is cooperative: it only binds an agent that calls cg in the first place. An agent with a shell can write directly to manifest.json, or simply not use the tool at all, and nothing in the process stops it.

The one command that is explicitly human-only is cg approve. It records the sign-off commit --next-phase EXECUTE requires. The name it records (--by, defaulting to the OS user) is audit metadata, not authentication: it says who to ask about this approval later, and an agent could pass any string it liked. The command itself is just as cooperative as the rest: an agent with a shell can run cg approve itself, and nothing in cg prevents that. The actual hard control does not live in cg at all — it is your harness's permission prompt on the cg approve command, configured per host in docs/adapters/*/PERMISSIONS.md. That prompt runs outside the agent's process, which is the only place a control that does not depend on the agent's cooperation can live. approve is deliberately not exposed as an MCP tool, for the same reason: an MCP tool is a channel the permission prompt does not see.

The pre-commit hook is the one layer that runs entirely outside the agent's process — git invokes it regardless of what the agent chose to do — but it is a perimeter check on file count, not a guarantee about correctness, and it ships with an audited bypass (CONTEXT_GUARD_BYPASS=1) by design: an unconditional block just gets --no-verifyd, which leaves no trace at all.

CLI reference

Command Purpose
cg new <name> --context <path> Create a change and begin PLAN
cg list --context <path> List active changes and their phase
cg begin --phase <PHASE> --context <path> Start a transaction for the given phase
cg approve [--by <who>] [--hotfix --reason "<text>"] Human-only: record the sign-off commit into EXECUTE requires
cg commit --next-phase <PHASE> --context <path> Validate the current phase's artifacts and advance the DAG
cg rollback --context <path> Restore the manifest snapshot taken at begin
cg checkpoint --summary "<text>" --context <path> Persist a session summary for warm-boot resume
cg claim --context <path> Acquire the session lock, taking over a stale one if needed
cg release --context <path> --agent-id <id> Release the session lock (ownership-checked)
cg claim-task --task-id <id> --context <path> Claim one task with a lease
cg release-task --task-id <id> --agent-id <id> --context <path> Release a claimed task
cg next-task --context <path> Claim and return the next unclaimed pending task
cg check-completion --context <path> Deterministic count of checked-off tasks
cg validate --context <path> Lint session artifacts: existence, size cap, language
cg status --context <path> One-shot summary for rehydration after context loss
cg doctor --context <path> [--fix] Diagnose (or repair) stale claims and locks
cg archive --context <path> Move a completed change to changes/archive/
cg migrate --context <path> Convert a legacy state-guard or context-guard 1.x layout in place

Every command accepts --format json. cg and context-guard are the same binary under two entry points.

MCP server

context-guard-mcp exposes eight tools over stdio — the four transactional ones plus four read-only ones for hosts with no shell (Claude Desktop is the case these exist for):

begin_transaction, commit_transaction, rollback_transaction, save_checkpoint, get_status, check_completion, validate, next_task.

cg approve is not an MCP tool. See Threat Model above.

Multi-change

State lives under .context-guard/changes/<name>/, one manifest and lock set per change, so several changes can be planned and executed independently in the same project. cg new <name> creates one; cg list shows what is active; cg archive moves a finished one to changes/archive/. cg migrate converts both legacy layouts — state-guard's state.ini and context-guard 1.x's flat .context-guard/ — in place and idempotently, preserving any recorded human approval it finds.

Pre-commit hook

.githooks/pre-commit rejects commits touching more than a threshold number of files when no change shows the protocol was engaged (a completed phase or an open transaction). Activate it once per clone with git config core.hooksPath .githooks.

  • Threshold: hook.file_threshold in a change's manifest, or the CONTEXT_GUARD_FILE_THRESHOLD environment variable, which wins over the manifest. Across several active changes, the strictest configured value applies.
  • files_in_scope: staged files outside an executing change's declared scope produce a warning, never a block.
  • Bypass: CONTEXT_GUARD_BYPASS=1 CONTEXT_GUARD_BYPASS_REASON='...' git commit .... Every bypass is appended to .context-guard/bypass.log with a timestamp and the file list — the door stays open, but nobody walks through it unrecorded.

Exit codes

Code Name Meaning
[0] EXIT_OK Success.
[1] EXIT_GENERIC Corrupt manifest, or no session at this context/change.
[2] EXIT_LOCK_HELD Another agent holds the lock or claim. Retryable with backoff.
[3] EXIT_LOCK_CONTENDED Lost the takeover race for a stale lock. Retryable.
[4] EXIT_VALIDATION Missing artifact, leftover [PENDING], oversized artifact, or non-English text.
[5] EXIT_BAD_TRANSITION The phase requested is not the DAG's current lock_phase. Do not retry.
[6] EXIT_APPROVAL_REQUIRED commit into EXECUTE with no recorded cg approve. Only a human resolves it.

Adapters and permission configuration

Thin, per-harness wrappers ship inside the package under context_guard/_data/hosts/{claude-code,opencode,antigravity}/ — each points at phases/{plan,execute,verify}.md rather than duplicating them. How to put cg approve behind each harness's permission prompt is documented in docs/adapters/, one PERMISSIONS.md per host, alongside the manual smoke-test checklist in docs/adapters/VERIFY.md. cg setup installs the right one for each detected host.

How this compares

context-guard is not a spec-writing tool, and it is not trying to be one.

context-guard spec-kit Kiro bare AGENTS.md
Generates specs/plans from a prompt No Yes Yes No
IDE-native experience No (CLI + MCP) Depends on host Yes No
Enforces phase order in code, not prose Yes No Partial No
Atomic manifest, survives a crash mid-phase Yes No No No
OS-level locking for concurrent agents Yes No No No
Human-approval gate before execution Yes No No No

What we do that they do not: runtime enforcement of a state machine that outlives the agent's process. What they do that we do not: everything about turning a prompt into a good spec in the first place. Use context-guard together with whichever of them already generates your objective.md — it was designed to consume one, not to write one.

Development

git clone https://github.com/fdomerlo/context-guard.git
cd context-guard && uv venv && uv pip install -e .
python -m unittest discover -s tests

Framework: unittest. Every fix ships with an adversarial test that reproduces the bypass it closes; see tests/test_adversarial_*.py for the pattern. No fixtures on disk outside tempfile.mkdtemp().

License

MIT — see LICENSE.

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

context_guard_cli-2.2.0.tar.gz (149.0 kB view details)

Uploaded Source

Built Distribution

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

context_guard_cli-2.2.0-py3-none-any.whl (61.8 kB view details)

Uploaded Python 3

File details

Details for the file context_guard_cli-2.2.0.tar.gz.

File metadata

  • Download URL: context_guard_cli-2.2.0.tar.gz
  • Upload date:
  • Size: 149.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for context_guard_cli-2.2.0.tar.gz
Algorithm Hash digest
SHA256 83cd751acc2f7e980eea3d46dbc8e48de8fc34c928b8319bc707c51b34e8313d
MD5 6a3f8f40d8a819d44d2841690e1dde29
BLAKE2b-256 ab2b8920ebc57a017a59df1e365605a72c63208ec9191b8fbda02cdb31f28e4c

See more details on using hashes here.

Provenance

The following attestation bundles were made for context_guard_cli-2.2.0.tar.gz:

Publisher: publish.yml on fdomerlo/context-guard

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file context_guard_cli-2.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for context_guard_cli-2.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 abef8e9033bd1ed58d87d3ac75758555a9a70b03dacefe34fb2952b633a56631
MD5 398839ee9eadd0b8baf6b05bcf19c107
BLAKE2b-256 1c8f29fcdaab316619844b7ba95ec19201bb7ceec7b1100e950143c614193730

See more details on using hashes here.

Provenance

The following attestation bundles were made for context_guard_cli-2.2.0-py3-none-any.whl:

Publisher: publish.yml on fdomerlo/context-guard

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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