Cookbook
Real-world recipes for putting CTXone into a developer workflow. Every recipe is self-contained and copy-pasteable.
Table of contents
Section titled “Table of contents”- Prime your project README on every git push
- Daily digest of what changed in the last 24 hours
- Shell prompt that shows session savings
- Capture a scripted fact in a shell variable
- Experiment on a branch, diff, then merge
- Team-shared memory via Postgres
- Bulk-import facts from a file
- Live-watch commits in a second terminal
- CI check: fail the build if a decision doesn’t have a recorded reason
Prime your project README on every git push
Section titled “Prime your project README on every git push”Keep pinned memory in sync with your README so agents always see the current canonical project context.
#!/bin/bashset -e
if ! command -v ctx >/dev/null; then exit 0 # silently skip if ctx isn't installedfi
if ! ctx doctor >/dev/null 2>&1; then exit 0 # silently skip if hub isn't runningfi
ctx prime ./README.md --pin --source project > /dev/nullecho "ctxone: primed README as pinned project context"Make it executable:
chmod +x .git/hooks/pre-pushNow every time you git push, the README’s H1/H2 sections are re-stored as
pinned memory under /memory/pinned/project/*. Because prime is idempotent
by source, re-running doesn’t create duplicates.
Variation: to prime multiple docs:
ctx prime ./README.md --pin --source readmectx prime ./docs/ARCHITECTURE.md --pin --source architecturectx prime ./docs/DECISIONS.md --source decisions # searchable, not pinnedDaily digest of what changed in the last 24 hours
Section titled “Daily digest of what changed in the last 24 hours”A cron job that asks “what happened yesterday?” and emails or posts it.
#!/bin/bashset -e
SINCE=$(date -u -v-1d +"%Y-%m-%dT%H:%M:%SZ") # macOS# SINCE=$(date -u -d '1 day ago' +"%Y-%m-%dT%H:%M:%SZ") # Linux
DIGEST=$(ctx log -n 200 --format json | \ jq -r --arg since "$SINCE" ' .[] | select(.timestamp > $since) | "- [\(.intent.category)] \(.intent.description) (\(.agent_id))" ')
if [ -z "$DIGEST" ]; then echo "No activity in the last 24 hours." exit 0fi
echo "CTXone activity since $SINCE:"echoecho "$DIGEST"Wire it to cron:
# crontab -e7 9 * * * /usr/local/bin/ctxone-daily-digest.sh | mail -s "CTXone digest" [email protected]Why --format json | jq: the Hub returns structured commit data with
intent category, description, agent ID, and timestamp. jq filters to
yesterday and pretty-prints. No string scraping.
Shell prompt that shows session savings
Section titled “Shell prompt that shows session savings”Put cumulative token savings in your shell prompt so you see it every time you hit Enter.
_ctxone_prompt_info() { local saved=$(ctx stats --format json 2>/dev/null | jq -r '.session_tokens_saved // "—"') if [ "$saved" != "—" ] && [ "$saved" != "null" ]; then echo "ctx:${saved}" fi}
PROMPT='%F{blue}$(_ctxone_prompt_info)%f %~ $ 'Result:
ctx:1706 ~/projects/myapp $The 2>/dev/null silently hides output when the Hub is down — your prompt
keeps working regardless.
Performance note: ctx stats makes one HTTP call per prompt render. If
that’s too much, cache for 10 seconds:
_ctxone_cached_saved() { local cache=/tmp/ctxone_saved.$USER if [ -f "$cache" ] && [ $(($(date +%s) - $(stat -f %m "$cache" 2>/dev/null || stat -c %Y "$cache"))) -lt 10 ]; then cat "$cache" else ctx stats --format json 2>/dev/null | jq -r '.session_tokens_saved // "—"' > "$cache" cat "$cache" fi}Capture a scripted fact in a shell variable
Section titled “Capture a scripted fact in a shell variable”Use --format id to grab the path or commit id of a newly-stored fact.
# Remember a fact and capture its pathpath=$(ctx remember "Deployment finished for build #4721" \ --importance high \ --context ops \ --format id)
echo "stored at $path"# stored at sg_a1b2c3d4e5f6 (commit id)To capture the path instead of the commit id, parse the JSON directly:
result=$(ctx remember "..." --format json)path=$(echo "$result" | jq -r .path)commit=$(echo "$result" | jq -r .commit_id)Then you can forget it later:
ctx forget "$path" --reason "deploy rolled back"This is the loop that enables transactional scripts: remember, check, optionally forget on failure.
Experiment on a branch, diff, then merge
Section titled “Experiment on a branch, diff, then merge”Try a risky memory change (bulk prime, reorganization) on a branch without touching main.
# Snapshot current state as a branchctx branch experiment
# Work on the branchctx --branch experiment prime ./big-proposal.md --pin --source proposalctx --branch experiment remember "New naming convention: verb-noun" --context conventions
# See what changed vs mainctx diff main experiment
# Try recalling on the experiment branchctx --branch experiment recall "naming"
# If you like it: merge (there's no merge command yet — use Repository::merge# via the engine directly, or just keep writing to the experiment branch)
# If you don't: switch backexport CTX_BRANCH=mainTip: use CTX_BRANCH env var to avoid typing --branch experiment on
every command during a session.
Team-shared memory
Section titled “Team-shared memory”Run the Hub against a Postgres instance so multiple developers (or multiple machines) see the same memory graph.
# Start the Hub pointing at Postgresexport DATABASE_URL=postgres://ctxone:secret@db.internal:5432/ctxonectx serve --http --storage postgresOr via Docker:
services: db: image: postgres:16 environment: POSTGRES_USER: ctxone POSTGRES_PASSWORD: secret POSTGRES_DB: ctxone volumes: - ctxone-pg-data:/var/lib/postgresql/data ports: - "5432:5432"
hub: image: ghcr.io/ctxone/ctxone:latest command: ["ctxone-hub", "--http", "--port", "3001", "--storage", "postgres"] environment: DATABASE_URL: postgres://ctxone:secret@db:5432/ctxone depends_on: [db] ports: - "3001:3001"
volumes: ctxone-pg-data:Each team member points their CLI at the shared Hub:
export CTX_SERVER=http://hub.internal:3001ctx remember "..." # writes to the shared graphSeparation: use branches to give each agent or project its own namespace:
ctx --branch team/backend remember "..."ctx --branch team/frontend remember "..."Caveat: Postgres auth in the Hub is single-tenant right now. For multi-tenant deployments with per-team isolation, wait for a future release or run separate Hub instances.
Bulk-import facts from a file
Section titled “Bulk-import facts from a file”Prime imports markdown structured by headings. For unstructured plain-text facts (one per line), loop:
# facts.txt: one fact per linewhile IFS= read -r fact; do [ -z "$fact" ] && continue ctx remember "$fact" --importance medium --context imported --format iddone < facts.txtOr from a JSONL file with explicit metadata:
# facts.jsonl: one JSON object per line# {"fact":"...","importance":"high","context":"..."}while IFS= read -r line; do fact=$(echo "$line" | jq -r .fact) imp=$(echo "$line" | jq -r '.importance // "medium"') ctx=$(echo "$line" | jq -r '.context // "imported"') ctx remember "$fact" --importance "$imp" --context "$ctx" > /dev/nulldone < facts.jsonl
echo "Imported $(wc -l < facts.jsonl) facts"Or pipe a single fact from another command:
# Pipe from curlcurl -s https://example.com/status | ctx remember - --context status
# Pipe from stdin interactivelyecho "Craig makes the best spaghetti" | ctx remember - --importance low --context triviaLive-watch commits in a second terminal
Section titled “Live-watch commits in a second terminal”Open two terminals. In the first:
ctx tailIn the second, do anything that writes:
ctx remember "test fact"ctx prime ./README.mdctx demoEach commit appears in the tail terminal within the poll interval (default
2000ms, override with --interval 500 for snappier feedback).
Use case: a pair-programming session where one person runs ctx tail
and the other uses Claude Code. You watch the memory graph update in
real time.
CI check: decision reasoning
Section titled “CI check: decision reasoning”Enforce that every Checkpoint commit has reasoning attached. Runs in CI
and fails if a decision was made without explanation.
#!/bin/bashset -e
BAD=$(ctx log -n 1000 --format json | jq -r ' [.[] | select(.intent.category == "Checkpoint") | select((.reasoning // "") == "") | .id] | join("\n")')
if [ -n "$BAD" ]; then echo "ERROR: Checkpoint commits without reasoning:" echo "$BAD" exit 1fi
echo "OK: all checkpoints have reasoning"Wire it into your CI pipeline. The Hub needs to be reachable from the CI runner — run it as a sidecar container or use a shared hosted instance.
More ideas
Section titled “More ideas”- Session replay: use
ctx log+ctx recallto reconstruct a session’s memory state at a past moment - Memory audit: periodic
ctx searchfor stale or wrong facts, thenctx forget - Cross-tool sync: a Git pre-commit hook that uses
ctx searchto find related past decisions and prints them as a reviewer checklist - Agent authority chains: write each agent to a namespaced branch
(
agents/alice,agents/bob) soctx blameshows which agent decided what
If you build something, open a PR adding it here.