The document store persists artifacts across sessions. It’s a flat-file, git-backed key-value store with per-repo scoping and an optional shared namespace.

Overview

Documents are plain files in a git repository. Every changed write is committed, so full history is available via git log in the store directory; no-op writes (identical content) are skipped. Files are browsable and greppable with standard tools. Operations go straight to disk, not through the daemon, so there’s no latency or availability dependency on it.

Scoping

By default documents are scoped to the current repo, and sessions on the same repo share a namespace. The repo path is canonicalized (symlinks resolved), so different spellings of the same repo resolve to the same namespace.

Use --shared to access a global store that isn’t scoped to any repo:

  gr store put --shared prompts/review.md "Review this code..."
gr store get --shared prompts/review.md
gr store ls --shared
  

Use --repo to name the repo explicitly (handy outside a session). It accepts either a filesystem path or a repo ID — the <name>-<hash> identifier gr store ls -a prints in its repo column — so a value from ls -a round-trips straight back into --repo:

  gr store list --repo ~/Code/my-project      # filesystem path
gr store get notes/example.txt --repo my-project-a1b2c3d4   # repo ID from `ls -a`
  

An unresolvable --repo value (neither a path nor a known ID) fails with a clear unknown repo error instead of a misleading document not found.

Operations

Put

  # Store inline content
gr store put design/api.md "# API Design\n\nEndpoints: ..."

# Store from file
gr store put design/api.md --file ./api-design.md

# Store from stdin
echo '{"score": 85}' | gr store put results/score.json
  

Get

  gr store get design/api.md
  

Outputs the raw document body to stdout.

List

  gr store list                 # list all documents in the current repo's store
gr store list design/         # list documents under a prefix
gr store ls                   # alias
gr store list --all           # list across all repos
  

Append

  gr store append logs/builds.jsonl '{"status":"pass","ts":"2026-06-16"}'
echo '{"run":2}' | gr store append logs/builds.jsonl
gr store append logs/builds.jsonl --file ./result.json
  

Creates the document if absent, then appends the content plus a newline — useful for JSONL logs where each entry is one JSON line.

Remove

  gr store rm design/api.md
  

Removes the document and commits the deletion.

Key format

Keys are slash-separated paths and should include a file extension to indicate content type:

  design/api.md
logs/builds.jsonl
tribunal/2026-06-15.json
notes/architecture.md
  

Validation rules:

  • Must not be empty
  • Must not start with / or -
  • Must not contain .., .git, or . as path components
  • Must not contain control characters, NUL bytes, or backslashes
  • Must not contain git pathspec characters (*, ?, [, :)
  • Must not be store.lock

Storage location

ScopePath
Per-repo<data_dir>/store/<repo-name>-<hash>/
Shared<data_dir>/store/shared/

Each store directory is a git repository initialized by graith. The git user is graith <graith@localhost>.

Patterns

Design documents

Share design decisions across agent sessions:

  gr store put design/auth-rewrite.md --file ./auth-design.md
# Any session on the same repo can read it:
gr store get design/auth-rewrite.md
  

Build/test logs

Accumulate results in JSONL format:

  gr store append logs/test-runs.jsonl '{"session":"fix-auth","status":"pass","duration":"45s"}'
gr store append logs/test-runs.jsonl '{"session":"add-tests","status":"fail","duration":"12s"}'
  

Cross-repo artifacts

Use --shared for artifacts that span repos:

  gr store put --shared prompts/code-review.md "Review this code for..."
gr store put --shared config/tribunal-rubric.json '{"dimensions":["correctness","style"]}'
  

Research notes

Persist findings that should survive session deletion:

  gr store put research/auth-middleware.md "$(cat <<'EOF'
# Auth Middleware Investigation

The token refresh logic in middleware.go:145 has a race condition.
Two goroutines can both see an expired token and both attempt refresh.

Fix: use sync.Once or a mutex around the refresh call.
EOF
)"
  

Browsing in the apps

The macOS and iOS apps include a read-only document store browser. Open it from the toolbar (the document icon): it lists every document the connected daemon knows about — per-repo stores plus the shared store — grouped by store, and shows a selected document’s body. On macOS with more than one paired host, pick the host from its Host selector.

It’s read-only for now — write via gr store put / rm / append from the CLI. Writing from the apps is a planned follow-up.