Skip to content

Cookbook

Real-world recipes for putting CTXone into a developer workflow. Every recipe is self-contained and copy-pasteable.

  1. Prime your project README on every git push
  2. Daily digest of what changed in the last 24 hours
  3. Shell prompt that shows session savings
  4. Capture a scripted fact in a shell variable
  5. Experiment on a branch, diff, then merge
  6. Team-shared memory via Postgres
  7. Bulk-import facts from a file
  8. Live-watch commits in a second terminal
  9. 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.

.git/hooks/pre-push
#!/bin/bash
set -e
if ! command -v ctx >/dev/null; then
exit 0 # silently skip if ctx isn't installed
fi
if ! ctx doctor >/dev/null 2>&1; then
exit 0 # silently skip if hub isn't running
fi
ctx prime ./README.md --pin --source project > /dev/null
echo "ctxone: primed README as pinned project context"

Make it executable:

Terminal window
chmod +x .git/hooks/pre-push

Now 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:

Terminal window
ctx prime ./README.md --pin --source readme
ctx prime ./docs/ARCHITECTURE.md --pin --source architecture
ctx prime ./docs/DECISIONS.md --source decisions # searchable, not pinned

Daily 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.

/usr/local/bin/ctxone-daily-digest.sh
#!/bin/bash
set -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 0
fi
echo "CTXone activity since $SINCE:"
echo
echo "$DIGEST"

Wire it to cron:

# crontab -e
7 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.


Put cumulative token savings in your shell prompt so you see it every time you hit Enter.

~/.zshrc
_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:

Terminal window
_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.

Terminal window
# Remember a fact and capture its path
path=$(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:

Terminal window
result=$(ctx remember "..." --format json)
path=$(echo "$result" | jq -r .path)
commit=$(echo "$result" | jq -r .commit_id)

Then you can forget it later:

Terminal window
ctx forget "$path" --reason "deploy rolled back"

This is the loop that enables transactional scripts: remember, check, optionally forget on failure.


Try a risky memory change (bulk prime, reorganization) on a branch without touching main.

Terminal window
# Snapshot current state as a branch
ctx branch experiment
# Work on the branch
ctx --branch experiment prime ./big-proposal.md --pin --source proposal
ctx --branch experiment remember "New naming convention: verb-noun" --context conventions
# See what changed vs main
ctx diff main experiment
# Try recalling on the experiment branch
ctx --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 back
export CTX_BRANCH=main

Tip: use CTX_BRANCH env var to avoid typing --branch experiment on every command during a session.


Run the Hub against a Postgres instance so multiple developers (or multiple machines) see the same memory graph.

Terminal window
# Start the Hub pointing at Postgres
export DATABASE_URL=postgres://ctxone:secret@db.internal:5432/ctxone
ctx serve --http --storage postgres

Or via Docker:

docker-compose.yml
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:

Terminal window
export CTX_SERVER=http://hub.internal:3001
ctx remember "..." # writes to the shared graph

Separation: use branches to give each agent or project its own namespace:

Terminal window
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.


Prime imports markdown structured by headings. For unstructured plain-text facts (one per line), loop:

Terminal window
# facts.txt: one fact per line
while IFS= read -r fact; do
[ -z "$fact" ] && continue
ctx remember "$fact" --importance medium --context imported --format id
done < facts.txt

Or from a JSONL file with explicit metadata:

Terminal window
# 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/null
done < facts.jsonl
echo "Imported $(wc -l < facts.jsonl) facts"

Or pipe a single fact from another command:

Terminal window
# Pipe from curl
curl -s https://example.com/status | ctx remember - --context status
# Pipe from stdin interactively
echo "Craig makes the best spaghetti" | ctx remember - --importance low --context trivia

Open two terminals. In the first:

Terminal window
ctx tail

In the second, do anything that writes:

Terminal window
ctx remember "test fact"
ctx prime ./README.md
ctx demo

Each 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.


Enforce that every Checkpoint commit has reasoning attached. Runs in CI and fails if a decision was made without explanation.

scripts/check-decision-reasoning.sh
#!/bin/bash
set -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 1
fi
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.


  • Session replay: use ctx log + ctx recall to reconstruct a session’s memory state at a past moment
  • Memory audit: periodic ctx search for stale or wrong facts, then ctx forget
  • Cross-tool sync: a Git pre-commit hook that uses ctx search to 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) so ctx blame shows which agent decided what

If you build something, open a PR adding it here.