# Stateroot

> Cross-harness continuity for AI coding agents: persistent project state, shared memory, and handoffs via the `stateroot` CLI. Use when working in a project that has a `.stateroot/` directory — consume the auto-injected identity/resume digest on the first usable prompt, run `stateroot resume --harness <id>` only if that digest is missing (unpiped; never `| head` / `| tail` / line limits — the full digest is the state of record), `stateroot checkpoint` after every state-changing step, check the failed-approaches log before attempting an approach, and run `stateroot handoff write` before ending a session or switching agent harnesses.

- Skill: `cogniztech/stateroot-2` (Agent Skill, multi-file: 12 files)
- Install (CLI): `npx skillmds@latest add cogniztech/stateroot-2`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cogniztech/stateroot-2/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: CognizTech (https://skillmd.com/u/cogniztech)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/cogniztech/stateroot-2

---


# StateRoot

StateRoot gives a project one persistent state of record that any agent harness (Claude Code, Codex, Cursor, OpenCode, Kimi Code, OpenClaw, Hermes, StateSmith) can attach to. This skill is the behavioral contract for working in a stateroot project. Follow it mechanically, every session.

## When To Use

1. the project root contains a `.stateroot/` directory, or `stateroot status` reports an attached project
2. starting, continuing, or handing off work in such a project

## When Not To Use

Do not use this skill when:
1. the project is not stateroot-initialized and the user has not asked to initialize it (suggest `stateroot init` instead)
2. the task is unrelated to project work (casual Q&A, one-off questions)

## Hard Rules

### 0) Shared rules (constitution)

StateRoot keeps a **shared rules pool** — same idea as skills and learnings. Product-intent ships by default. Rules from other harnesses (Cursor `.mdc`, Codex/Claude `AGENTS.md`/`CLAUDE.md`, …) are pulled in on `stateroot rules sync` (also run by `init` / `install`).

Before any architectural or behavioral change, read `stateroot rules show product-intent`. Preserve product intent. Do not replace agent judgment with classifiers, approval gates, or generic architecture. Do not add friction "because it seems safer." Follow imported harness rules in the pool as well (`stateroot rules list`).

### Keep the tool fresh (updates)

When the digest notes **Update available: \<tag\>**, run `stateroot self-update` — it re-arms harness wiring automatically. Otherwise run `stateroot self-update --check` occasionally; the CLI and this skill improve often. Never update mid-task: finish the step, checkpoint, then update.

### Capabilities are pooled — delegate, never refuse

Skills and capabilities are shared across harnesses. When the user asks for a capability you lack natively (image generation, docs of another vendor, a harness-specific automation, …):

1. check the digest's **Shared Capabilities** section or `stateroot skill list` for a `reference_only` capability another harness owns
2. answer with the path, not a refusal: "I can't natively — but codex can. Say the word and I delegate."
3. on an explicit ask, delegate the bounded microtask: `stateroot delegate --to <harness> --skill <slug> --task "<task>"` — then inspect the produced outputs; do not replay the foreign transcript
4. never claim another harness's capability as your own: say *which* harness would do it

### Identity changes are soul changes — never learnings, never memory

When the user asks to change the agent's personality, voice, name, character, or boundaries (anything about **who you are** or **how you speak**):

1. that is a **soul** change, full stop — not a learning (taste for *work*), not a memory (facts about the *project*)
2. write it to the canonical soul: `stateroot soul propose --stdin` (pipe the updated soul) or `soul edit` — it lands in `~/.stateroot/soul/SOUL.md` with a history snapshot
3. soul sync then pushes it to every harness's native persona files (openclaw, hermes) — the change propagates to all harnesses at their next session
4. the digest identity hash changes on adoption, so every harness re-anchors with a FULL injection automatically

### 1) Session start -> consume identity, resume only as fallback

At the start of every session in a stateroot project, before doing any work:
1. consume the auto-injected StateRoot digest (persona + USER.md + work body) when the harness put it in context. Automatic harnesses inject on session-start and/or the first prompt. Do not wait to be asked who you are.
2. only run the harness-specific resume (e.g. `stateroot resume --harness cursor` / `--harness codex` / `--harness claude` / `--harness kimi`) — or `scripts/resume.sh --harness <id>` — if **no** identity/resume digest appeared. Manual resume is the last fallback, not the primary reliability mechanism. Degraded harnesses (Hermes, Copilot, Crush) need this fallback. **Hook-less sessions (IDE/ACP integrations fire no hooks) never receive the digest — there resume at session start is required, not a fallback, and `stateroot resume --force` after any context compaction re-anchors identity.**
3. treat that **entire** output — current handoff, hot-apex memory, context pack — as the project state of record
4. **never truncate resume or the hook digest.** Run the command as-is. Do not pipe it through `head`, `tail`, `less`, `sed`, `awk`, `cut`, `wc`, or any line/byte limiter. Do not add `--budget`. The CLI already sized the digest. A clipped resume is a corrupted state of record.
5. do not run resume again in the same session unless the user explicitly asks (`--force` reprints)
6. do not re-derive project state by scanning the tree when resume already answers the question

### 2) State-changing step -> checkpoint

After completing ANY step that changes project state (files written, decisions made, milestones reached, blockers discovered, approaches abandoned):
1. run `scripts/checkpoint.sh --note "<what changed and why>" [--files a,b]`
2. keep the note specific: what changed, why, and what it unblocks
3. checkpoint the finished step BEFORE starting the next one; never batch several finished steps into one checkpoint

### 3) Before attempting an approach -> check failed approaches

Before attempting any non-trivial approach:
1. run `scripts/search.sh "failed approach <topic>"` (wraps `stateroot memory recall`) or read `failed_approaches` in the current handoff
2. if a matching failure exists, do not repeat it — state explicitly why the new attempt differs

### The flagship flow: plan in one harness, implement in another

When the user asks you to make a plan that another harness will implement — or any time a plan should outlive your session:

1. **Record the plan in the shared store, never only in your harness's native plan location** (`~/.claude/plans/`, `~/.cursor/plans/`, plan-mode files):
   - write the plan body and run `stateroot plan record --stdin --title "<title>"` (pipe the body), or `--from <your-harness>`
   - on harnesses with native plan mode: author in plan mode as usual, then record the same body into the store before exiting plan mode (`--file <path>` exists to ingest that existing plan-mode file)
   - never author a plan markdown inside the project repo just to hand it off — repo docs are project artifacts; the shared store carries the plan and the executor reads it with `stateroot plan show <id>`
2. **Hand it off**: `stateroot handoff write --from <you> --to <target harness> --objective "…" --task "Execute recorded plan <id> (stateroot plan show <id>)" [...]` — the store auto-attaches the approved/active plan's `plan_ref` to the handoff
3. The executor's digest then says **"execute this plan; do not re-plan or re-explore"** — approve with `stateroot plan approve <id>` when the user has reviewed. For parallel work, materialize one sibling fork per plan with `stateroot fork <root> --worktree <path> --plan <id>`, then activate that plan **inside its fork worktree**. Activation is one-per-checkout, not one-per-project: independent forks activate independently.
4. Harness-native plans written in native plan mode DO federate in automatically at session boundaries (as drafts) — but the record-then-handoff path is immediate and deliberate; use it when the plan is meant for another harness NOW

### Integrating parallel forks (appointed coordinator)

When fork lineages are ready to fold into the trunk and the user appoints you to coordinate the integration:

1. `stateroot merge --prepare <fork>… --json` freezes the trunk tip and every fork tip and returns a durable attempt: `ready` when clean, `attention` with exact conflict paths/kinds when not. Preparing changes no refs or worktrees.
2. `ready` → `stateroot merge --continue <attempt>` publishes one N+1-parent root (frozen refs are CAS-revalidated first).
3. `attention` → the attempt record names a machine-local **reconciliation worktree**: the accumulated clean fold with every text conflict rendered with standard markers (`trunk (accumulated fold)` vs `fork <name>`). Edit and test **in that worktree**, then `stateroot merge --continue <attempt> --evidence "<tests you ran>"`. Continue refuses while markers remain and refuses stale frozen refs — prepare again after any source moved. Never resolve by silently picking a side; the reconciled worktree IS the resolution.
4. `stateroot merge --status <attempt> --json` is read-only; `--abort <attempt>` removes only attempt-local state.
5. Merged fork worktrees are marked `cleanup_pending` (the merge never waits on deletion); `stateroot merge --cleanup <fork>…` is bounded and idempotent.
6. `stateroot merge <fork>…` without `--prepare` still runs the one-shot deterministic fold; conflicts report paths and create no root.

### 2b) Work-state lineage -> automatic snap

Lineage does not depend on you remembering: `stateroot checkpoint` and the turn-end (`stop`) hook automatically snap the working tree whenever **project files** actually changed (`.stateroot/` bookkeeping alone never creates a root). Automatic snaps run with a bounded scan budget — a dependency-heavy tree skips the root but never the checkpoint; `stateroot doctor` names the heavy paths and the exact ignore lines, and an explicit `stateroot snap` always performs the deliberate full scan.
1. explicit milestones: run `stateroot snap [--reason "..."]` to record a root on demand under `refs/stateroot`
2. use `stateroot log` / `stateroot show <root>` to inspect lineage; `stateroot diff` / `stateroot compare` for deltas
3. use `stateroot revert <root>` only for verified restoration (append-only — creates a new root)
4. use `stateroot fork <root>` when divergent work should branch from an earlier root; integrate finished forks with `stateroot merge` (see Integrating parallel forks)
5. handoff carries session continuity — it does **not** replace snap/revert/fork lineage

### 4) Session end / usage limit / harness switch -> handoff

Before ending a session, when approaching usage limits, or when the user asks to switch harness:
1. prefer a **flag-first** one-liner: `scripts/handoff.sh write --from <resolved-current-harness> [--to <harness>] --objective "…" --task "…" --context-summary "…" [--next "…"]` — one command, no temp JSON
2. omit `--to` for continuity-only; use it only when orchestrating a cross-harness switch; when continuity suffices and hooks may not run, `stateroot handoff finalize` is acceptable — or rely on session_end/stop hook finalize when it ran
3. resolve `--from` to the actual current harness id; never copy a placeholder or infer it from an environment variable
4. include the durable objective, immediate task (`--task`, not `immediate_task`), detailed continuity narrative, decisions, next actions, and truthful failures; the CLI auto-captures recent verified conversation when author content is absent
5. use `--input <handoff.json>` only when the payload is too large for flags; never write under `.stateroot/handoffs/` by hand
6. thin fields warn; they do not refuse the write — continuity beats form-filling
7. do not paste giant state or transcript dumps into `--note`; `--note` is only a legacy short-summary fallback
8. never invent a second approval story — learnings, soul, skills, memory, and distill activate immediately

### 5) Never edit `.stateroot/` directly

All reads and writes of project state go through the CLI. Do not open, edit, move, or delete files under `.stateroot/` with file tools or shell commands — the CLI maintains revisions, indexes, and outbox consistency.

### 6) Offline behavior

The CLI is offline-safe: when the server is unreachable it queues operations in the local outbox and still exits successfully. Therefore:
1. checkpoint and hand off anyway — never skip a checkpoint because of connectivity
2. do not re-issue the same queued operation in a retry loop
3. never hand-edit outbox files

## Command Reference

| Command | When | Notes |
|---|---|---|
| `stateroot resume [--harness H]` | last fallback at session start | prints the **full** digest when hooks did not inject. Never pipe through `head`/`tail` or any limiter |
| `stateroot checkpoint --note "..." [--files a,b]` | after any state-changing step | appends an episodic record and updates handoff state |
| `stateroot handoff write --from CURRENT_HARNESS [--to H] [--task …] [--context-summary …] [--next …]` | session end / harness switch | prefer flags near limits; `--to` optional (routing only); `--input` for large payloads |
| `stateroot handoff finalize [--from H]` | hook missed / quota exit | observed continuity from verified transcript; no routing |
| `stateroot handoff list` / `stateroot handoff show` | inspect prior handoffs | read-only; list is newest-first with the current packet pinned at top |
| `stateroot handoff repair` | corrupt `current.json` | quarantines corrupt bytes (hash-stamped), restores the newest valid history packet, or says none exists — never fabricates |
| `stateroot delegate --to H --task "…"` | detached subagent in another harness (async-only) | cli-mode harnesses only; spawn returns a `running` record immediately — observe via `stateroot delegate list` / `status <id>` and the `## Recent Delegations` digest section; nothing is ever killed or blocked; depth-capped — a subagent cannot delegate further |
| `stateroot ext list` | extensions discovered on PATH | any `stateroot-<name>` executable on PATH runs as `stateroot <name>` — you can add commands yourself by writing one |
| `stateroot projects` / `--json` / `--prune` | every initialized project on this machine | the discovery half of cross-project work: list projects here (name, path, phase, active plan), then work the one requested; same listing via the `projects_list` MCP tool |
| `stateroot session sync` / `list` / `show` | canonical session store | pi/DSH sessions → `.stateroot/local/sessions/` (local-only, idempotent) |
| `stateroot session transfer <id> --to pi\|dsh` | resume a session in another harness | writes a real native session file; fidelity report (native/adapted/dropped); `--dry-run` previews |
| `stateroot plan record` / `list` / `show` / `approve` / `activate` / `done` / `abandon` | central plan artifact + lifecycle | plan/implement split: the planner records a draft, the user approves, the executor's digest points at `.stateroot/plans/<id>.md` with an execute directive — do not re-plan; the digest never carries the body |
| `stateroot memory recall <query> [--limit N]` | find decisions, failures, memories | FTS over memory, wiki, episodic, transcripts |
| `stateroot memory sync [--harness H] [--dry-run]` | federate harness memory into the pool | pulls claude/codex/openclaw memories in as `observed` wiki pages / episodic; dedups by content hash, preserves conflicts; `--push` writes a curated brief into managed harness memory files |
| `stateroot snap [--reason R]` | explicit milestones (checkpoints and turn ends auto-snap real changes) | records verified root under `refs/stateroot` |
| `stateroot log` / `stateroot show <root>` | inspect lineage | current root, transitions, coverage |
| `stateroot diff` / `stateroot compare A B` | inspect tree deltas | verified git diff between roots |
| `stateroot revert <root>` | verified restoration | append-only — creates a new root |
| `stateroot fork <root>` | divergent work | branch lineage from an earlier root |
| `stateroot merge <fork>…` / `--prepare` / `--continue` / `--status` / `--abort` / `--cleanup` | fold fork lineages into the trunk | one N+1-parent root; conflicts get a reconciliation worktree — see Integrating parallel forks |
| `stateroot rules list` / `show` / `sync` | shared rules pool | product-intent always on; harness rules imported |
| *(no stateroot pack command)* | — | resume already injects the observed context pack. Do not invent a truncated pack |
| `stateroot learn record "…"` | durable project taste | judgment rule, not a fact — see Learnings below |
| `stateroot learn record --user "…"` | durable global taste | follows the user across projects |
| `stateroot learn record --workspace "…"` | org/workspace taste | shared across projects in the same workspace |
| `stateroot learn record --domain <slug> "…"` | domain taste | shared across repos bound to that domain slug |
| `stateroot learnings list` / `--user` / `--workspace` / `--domain` | read before writing | update rather than duplicate |
| `stateroot skill install [--harness H]` | install this skill into harness dirs | writes stubs from `assets/` |
| `stateroot status` / `stateroot doctor` | diagnose auth, connectivity, project state | doctor checks outbox depth and sync health, handoff corruption (`handoff repair` is the recovery), skipped automatic snapshots, large unignored generated dirs, and editor extension state |
| `stateroot editor status` / `editor reconcile` | VS Code/Cursor extension state | status is read-only (installed vs release-declared version); reconcile installs/updates from the verified release VSIX, never downgrades |
| `stateroot init` | one-time per project | creates `.stateroot/`, registers the workspace, installs harness integrations, seeds objective/memory/first handoff from repo docs (observed; `--synthesize` opts into unverified LLM enrichment) |

## Failure Modes

| Symptom | Meaning | Action |
|---|---|---|
| `command not found: stateroot` | CLI not installed | tell the user to install the `stateroot` CLI and put it on PATH; do not attempt workarounds |
| "not a stateroot project" | no `.stateroot/` in this tree | suggest `stateroot init`; never create `.stateroot/` manually |
| write reported as queued | offline | normal — the outbox syncs later; continue working |
| conflict / stale revision on write | another harness wrote concurrently | re-run `stateroot resume`, then retry the operation once |
| thin or missing handoff on resume | previous harness wrote an incomplete handoff | note the gap in your next checkpoint; do not fabricate history |

## Output Discipline

1. after resume: tell the user the objective, current state, and next actions in 2-3 sentences. That summary does **not** replace reading the full digest — you must ingest every section, including the observed context pack.
2. after checkpoint or handoff: confirm in one line what was recorded
3. never paste raw `.stateroot/` file contents into the transcript — quote CLI output instead
4. never clip CLI state commands (`resume`, `status`, `doctor`, `log`, `handoff show`) with `head`/`tail`/pagers. If a tool UI offers "limit output", disable it for these commands.

## References And Assets

Read as needed:
- `references/protocol.md` — checkpoint cadence, handoff packet fields, offline outbox semantics
- `references/learnings.md` — quality bar, examples, anti-examples for `learn record`
- `references/harnesses.md` — per-harness install layout
- `assets/` — harness stub templates used by `stateroot skill install`
- `scripts/` — thin wrappers: `resume.sh`, `checkpoint.sh`, `handoff.sh`, `search.sh`

## Learnings (taste — not memory)

Learnings are durable **preferences**: how the next harness should judge a choice when two valid options exist. They are the StateRoot equivalent of CommandCode taste. They are not a wiki, not a layout dump, and not a fact log.

`learn_record` always writes a learning. Facts go to `memory` / `memory_save` (curated MEMORY.md). Procedures go to `skill_propose`. Pull long-term knowledge with `memory_recall` or `wiki_show` — page bodies are not dumped into the digest.

### Layers

- **Global (user):** `stateroot learn record --user "…"` or MCP `learn_record` with `scope: "user"` — communication, recurring methods, design/engineering judgment, boundaries that follow this human across repos.
- **Workspace:** `stateroot learn record --workspace "…"` or MCP `scope: "workspace"` — org-wide bars shared across projects in the same workspace registry id.
- **Domain:** `stateroot learn record --domain <slug> "…"` or MCP `scope: "domain:<slug>"` — taste shared across repos bound to that domain slug in the project manifest.
- **Project:** `stateroot learn record "…"` or MCP `learn_record` with `scope: "project"` — this repo's quality bars, preferred patterns, anti-patterns.

Read first: `stateroot learnings list`, `stateroot learnings list --user`, `stateroot learnings list --workspace`, and `stateroot learnings list --domain <slug>`. Update rather than duplicate.

### When to write

1. the user corrects you
2. the user states a durable preference
3. first session after `stateroot init`, if a layer is empty — seed **2–7 evidenced judgments**, then stop. Evidence means a user correction, a real failure, or completed work this session — never a decision or intention you formed moments ago. Seed at wrap-up or between tasks; the user's task always outranks seeding
4. you just followed a rule the next harness would otherwise miss

### When not to write

- inventory ("this is a TypeScript/Python monorepo", "uses uv") → `memory_save` / `memory` if it must persist at all
- facts (deadline, version, port, "the dashboard is graphite") → `memory_save` (or `memory` add/replace)
- slogans ("write good code", "be careful", "prefer evidence")
- intentions ("ask before planning", "write the plan file now") — a decision you just made is not a learning
- session recap, directory listings, one-off notes
- anything already in `learnings list`
- anything re-read from an empty store — an empty layer is a terminal answer; do not re-poll it

### Format (required)

One `learn record` call per learning. The note must stand alone so another harness can apply it without this session:

`<judgment>. <when it applies / what to do / what never to do>.`

Good:

- `Prefer small, reviewable diffs over rewrites. Touch only files that implement the asked change; do not restyle or restructure adjacent code.`
- `Server-side tools must never include arbitrary command execution. exec belongs on the client.`
- `Always read .gitignore before exploring a codebase so ignored trees do not pollute context.`
- `When two designs are valid, prefer the restrained, practical one. Do not add architecture from another project without fitting this one.`

Bad:

- `Laiq is a TypeScript/Python monorepo` — fact
- `prefer evidence over assertion` — too thin; no when, no never
- `the deploy uses systemd` — inventory

First session after init: seed whichever layer is empty **with this quality bar** at wrap-up or between tasks — never before or instead of the user's first request. Later harnesses inherit and must keep both current.

