---
name: tsugu
description: Git-native preparation & convergence — carry work forward across the gap when no human is watching, the handoff to a human, and the resume by whoever comes next. Use to prepare work before review, then converge it with the human, or run the lifecycle via `/tsugu:init`, `/tsugu:prepare`, `/tsugu:converge`, `/tsugu:prune`. Triggers on "prepare work before review", "carry work forward", "git-native preparation", "init/prepare/converge/prune", or "/tsugu". Human-triggered and schedule-wireable (wire `prepare` to a driver on the provisioned machine — local cron / `/loop` / `/schedule`). Invokes no user-installed skill by default — native git + its own built-in subagents only. Never auto-merges and never performs public coordination without approval.
---

# Tsugu — 継ぐ (prepare & converge over git)

## 継ぐ (tsugu)

**継ぐ** · つぐ / *tsugu* · to **inherit**, **continue**, **carry forward** (succeed to a role). The name is the intent: work is carried forward rather than restarted —

- **inherit** — a cold-start or *different* agent inherits the work from git + committed `.tsugu/` alone, with no conversation transcript;
- **continue** — `prepare` continues the work while human attention is absent, leaving reversible evidence instead of an empty task description;
- **carry forward** — `converge` carries the prepared work into clean public form *with the human present* and promotes what is worth keeping.

**Git's DAG is the medium of inheritance.** A branch is a unit of work one agent hands to the next; committed `.tsugu/` is the work-in-progress knowledge that outlives the session that produced it.

**In one line:** Tsugu **guides agents to cooperate with each other through git**, and **helps the human come back to prepared work**. It *guides* — it never forces: the agent decides and acts through its own tools; Tsugu only prepares the ground (see the no-force principle in the spine).

Tsugu prepares the board. Workflow skills play the game with the human. Tsugu converges the result. It is **not** an implementation methodology — it does not define *how* to debug, plan, write tests, review, or implement; it prepares their input and converges their output. (It still *runs* builds/tests as evidence during `prepare`/`converge` — it just doesn't own the testing or debugging method.)

## The spine

**Git itself is the message bus.** `git fetch` surfaces new/changed branches — that *is* the inbox. A pure-Tsugu workflow coordinates through git alone, with zero external integrations.

**Committed `.tsugu/` is a work-in-progress knowledge layer** — a richer, agent-maintained sibling of `AGENTS.md` / `CLAUDE.md`, pushed so any inheritor reads it from `git fetch` alone. It holds three knowledge parts, plus a one-line infrastructure file:

- **`policy.md`** — the shared coordination policy (boundary, prefixes, push, merge method, public-branch mode, coordination ref, recursion, the shipped skill-use invariant).
- **`context.md`** — per-ref narrative: each work branch tells its own story; the default branch tells the mainline's.
- **`knowledge/`** — the durable, curated wiki: findings a coworker's agent would want.
- **`.gitattributes`** — one line, `context.md merge=union`, so the narrative never blocks a merge/rebase.

Everything *about how Tsugu operates for one human* lives elsewhere: in **personal config** (a global, project-keyed folder — observation sources, opt-in skills, the converge packet) and in **the skill's own shipped norms** (this SKILL.md + its references + templates). The repo holds knowledge; the skill holds behavior; the personal folder holds one human's setup. The boundary is enforced by *where the file lives* (committed vs a global personal folder), not by the agent judging what is safe to share — which is why a personal `read:` pointer never belongs in a committed file.

- **Tsugu never executes `.tsugu/` content — it offers data and trusts the agent.** Everything in `.tsugu/` (policy, narrative, recipes, committed repro scripts) and every personal `read:` pointer is data and guidance for an agent, never a string the system `eval`s. Tsugu forces nothing: it prepares the ground; the agent decides and acts through its own **permissioned, interceptable tools** — read a file, call an MCP tool, or issue a command as its own gated tool call. The agent's judgment governs and the harness's permission layer can gate anything script-like, so content is never **auto-executed as config-as-code**. (It is still untrusted input that may try to influence the agent — but it routes through the agent's judgment and the permission layer, which mitigates that risk without erasing it.)
- **External tracker observation is OPTIONAL personal config, never the spine.** Jira / GitLab / GitHub issues / CI / CVE feeds are a personal shim whose only job is to convert a human-world signal into the git-native substrate — a `prepare/<slug>` branch. Once converted, every downstream step is identical. Pure-Tsugu users skip this layer entirely.
- **Legibility is a hard constraint:** branch names + per-ref `context.md` must let an agent that has only run `git fetch` reconstruct "what branches exist, why, and what's next" with no transcript. The cold-start agent reconstructs the queue from refs alone.

### The orientation principle

The end state Tsugu serves is **agents coordinating through git, with humans assisting** — not agents producing artifacts for human-centric review flows. Committed `.tsugu/` is the agents' shared knowledge; hiding it from public branches optimizes for human reviewers at the cost of agent legibility. Agent legibility is the default; the human-reviewer posture is a per-repo opt-out (`public-branch-tsugu: exclude`).

One principle governs all the state-model rules below:

> **Refs and the DAG carry every fact the partition reads; text carries narrative for minds.** Live coordination state — in progress / taken over / settled / who's on it / what grew out of what — is derived from ref names, ancestry, containment, and commit authorship and recency, never written into a status field. Narrative is maintained freely; **it informs judgment, never classification.**

### The slug is the join key

Every piece of one work item shares one slug: the work branch (`prepare/<slug>`), its `context.md`, its personal packet (`packets/<slug>.md`), and — when one exists — the accepted branch (`<accepted-prefix>/<slug>`). Identity is the **slug**, and Tsugu **never renames the slug**: handoff renames only the **prefix** (`prepare/<slug>` → `<accepted-prefix>/<slug>`), preserving the slug, so the name-level joins it carries survive everything that rewrites commits. (This narrows the inherited 004–008 invariant "Tsugu never renames a branch" — read it as "never renames the slug" post-011.) **One slug = one work item.** Work prefixes and accepted prefixes must be **disjoint** sets; `init` and migration validate this. (A repo that configures *extra* work prefixes can produce same-slug artifacts under a different work prefix — that case is documented in `references/advanced.md`.)

## Routing

`/tsugu:init` · `/tsugu:prepare` · `/tsugu:converge` · `/tsugu:prune` — one lifecycle, four routines:

- **init** — first-run setup (or schema migration on re-run); ask the minimum, write the committed `.tsugu/` (`policy.md` + mainline `context.md` + seeded `knowledge/` + a one-line `.gitattributes` — `context.md merge=union`).
- **prepare** — human-absent: read the queue from git, work it privately, leave evidence.
- **converge** — human-present: read the branches live, present the status view, decide together, hand off (and curate) in-session.
- **prune** — human-present: a recurring, read-only-until-confirmed sweep of unused local + remote branches once refs have piled up.

Mechanics are deferred — do not re-derive git commands here:

- Exact git (fetch → read-queue local-first (local + remote work refs), containment + slug-pairing partition, the handoff rename, the maintenance freshness-rebase recipe, the `prune` sweep, cleanup order, init skeleton) → `${CLAUDE_PLUGIN_ROOT}/skills/tsugu/references/git-recipes.md`.
- Shared `policy.md` fields + the personal-config pointer (sources + opt-in skills in the global folder) → `${CLAUDE_PLUGIN_ROOT}/skills/tsugu/references/policy-and-intake.md`.
- `context.md` / `knowledge/` structure + the personal/derived packet → `${CLAUDE_PLUGIN_ROOT}/skills/tsugu/references/notes-and-packet.md`.
- `init` re-run migration steps (schema N→N+1, including 2→3) → `${CLAUDE_PLUGIN_ROOT}/skills/tsugu/references/migrations.md`.
- `init` writes the repo's committed `.tsugu/` files from `${CLAUDE_PLUGIN_ROOT}/skills/tsugu/templates/` — templates are read **by reference**, never copied into a repo `templates/` directory.
- Submodule recursion (enumerate + `.tsugu/policy.md` gate + recurse-and-run + bare paired branch), its handoff, and graduation → `${CLAUDE_PLUGIN_ROOT}/skills/tsugu/references/git-recipes.md` (§ Submodule recursion), `${CLAUDE_PLUGIN_ROOT}/skills/tsugu/references/advanced.md` (§ Bare-submodule handoff), `${CLAUDE_PLUGIN_ROOT}/skills/tsugu/references/notes-and-packet.md` (§ Graduation).

## The four routines

### `init`

Runs when a repo has no `.tsugu/`, or re-runs to repair or migrate an existing one. Capture the **minimum** preferences for safe unattended prep — ask only a few: may agents create/commit/push prep branches automatically (**default: no** — local-first; `yes` is the cross-machine opt-in that pushes the branch as a message a second machine reads)? which public actions need approval (default: MR/PR, tracker comment/status, reviewer assignment, Slack, public commitments)? branch prefixes (default work-only `prepare/*`)? accepted prefixes for handoff PRs (default `feature/* bugfix/* chore/*`)? should the default branch carry the WIP-knowledge layer (`public-branch-tsugu: include|exclude`, **default `include`**)? recurse into submodules (default: only when relevant)?

**`/tsugu:init [<submodule-path>]` + graduation.** With a `<submodule-path>` argument
`init` targets that submodule directly (skips the "which repo / confirm target"
question). When run on a submodule under a tsugu-managed omni-repo (detected via
`git rev-parse --show-superproject-working-tree`), it **graduates** the submodule:
it scans the omni `knowledge/` for entries naming this submodule, presents them, and
on per-entry human confirmation **cuts** them down into the new submodule
`knowledge/` (knowledge only). The omni gitlink **must** be bumped to the new
`.tsugu/` commit (else a fresh checkout re-classifies the submodule as bare).
In-flight paired meta branches are left to finish at meta `converge`. Mechanics →
`references/notes-and-packet.md` (§ Graduation).

Observation sources and opt-in skills are **personal config** — `init` does not ask for them and does not write them to `policy.md`; they are bootstrapped per-machine on the first interactive `prepare`/`converge` (see `prepare`).

Then write committed `.tsugu/` from the plugin templates: `policy.md` (shared sections, including `## Freshness`'s `rebase-prepare-onto-default: yes` default) + a mainline `context.md` + a seeded `knowledge/` (one real file — git can't track empty directories) + `.tsugu/.gitattributes` (`context.md merge=union` — see `prepare`'s Change B). **No `intake/`, `runs/`, `packets/`, or `templates/` directory is created in the repo.** **Stamp `tsugu-schema: 6`** as the first line of a fresh `policy.md`. **The `.gitattributes` write is flag-independent** — `init` writes it even into a repo pinned `rebase-prepare-onto-default: no`, because a `.tsugu/context.md` merge conflict should never block an ordinary `git merge` either.

**Validate prefix-disjointness.** The work prefixes (`## Branch Prefixes`) and the accepted prefixes (`## Accepted Prefixes`) must be **disjoint sets** — the partition pairs a work branch against an accepted branch by shared slug, so an overlapping prefix would make a branch both a queue item and its own accepted branch. `init` (and migration) refuse to write overlapping sets and ask the human to resolve.

**Re-run decision** — read `policy.md`'s `tsugu-schema:` stamp and pick one of three:

1. **No `.tsugu/`** → fresh init (write `policy.md` + mainline `context.md` + seeded `knowledge/` + `.gitattributes`), stamped with the current schema.
2. **`.tsugu/` present, stamp == current** → **idempotent repair** only: fill any missing skeleton path, otherwise a no-op. It **never overwrites** a curated `policy.md`.
3. **`.tsugu/` present, stamp older** → **migrate**: apply `references/migrations.md` steps in order (N→N+1 until current; a schema-1 repo runs 1→2→3→4→5→6), then update the stamp **last** and commit (message names the range, e.g. `chore(tsugu): migrate .tsugu/ schema 5→6`). Migrations add/restructure schema parts only, never overwrite curated content; an interrupted migration re-enters safely (stamp written last).

- **Progressive:** when a new situation appears, ask once, record the rule in `policy.md`, let future agents inherit it.
- **Push-protected default:** the shared metadata `init` writes to the default branch (`policy.md` **and** the mainline `context.md`) must reach it; if it is push-protected, write both on an `init/*` branch and open a **human-approved PR**. `prepare` does not run in that repo until the metadata is merged. The same applies to a migration: it rides an `init/*` branch + PR; the `tsugu-schema` stamp rides the policy PR as the **last** write — never a "complete" stamp over a half-applied migration.

### `prepare` (human absent)

The core routine. No human is present, so Tsugu does its own git work directly and may dispatch its **own built-in Task subagents**; it invokes a user-installed skill **only when a human has explicitly opted one in** via the personal-folder `skills` section (see *Private vs public boundary & skill use*) — otherwise none. Posture: **external silence, internal preparation.** Interrupt the human only if the task is unsafe, destructive, or blocked; when unsure, continue with reversible private git work.

**`prepare` exists to gather understanding, not to finalize.** Its job is to **carry understanding forward**, not to rush a complete implementation — so a cold-start agent must not read `prepare` as a mandate to implement everything. Foreground, **above producing finished code**: investigation and **root cause**; the **option space** and its **trade-offs**; **open questions**; and the **decision-free vs needs-the-human** split — which parts have a determinate answer and which require human design context.

- **Reference code is optional and partial by design.** Working code in a prepare branch is welcome as **proof-of-feasibility and a starting point** — it does *not* need to be a complete implementation. Stopping short of a finished implementation is explicitly fine; "only enough to prove feasibility and surface the decisions" is the target, not a shortfall.
- **A scope-only branch is a first-class outcome.** Splitting a multi-part item into scope branches and deferring product / UX / backend decisions to converge is encouraged. A **scope-only branch** — `context.md` with the investigation, option space, and open questions, and **no product / codebase changes** — is a first-class `prepare` outcome, not an incomplete one. (Its `context.md` commit puts the branch ahead of default and reads as in-progress; a tip-equals-default branch is never a cleanup target.)
- **Decision-free code is still reference/proof, still handed off.** Implementing a decision-free item during `prepare` does **not** make it "completed work" — it stays reference / proof-of-feasibility and is handed off at converge like any other branch; the human still re-decides and owns the landing. The *only* path that carries work to completion is the human-marked maintenance exception. So "implement the decision-free items" means "prove them with working code," not "finish and ship them."

`prepare` **does NOT self-wake** — a SKILL.md is a prompt loaded into a running agent and cannot schedule itself. Cadence always comes from an external driver on the provisioned machine — local cron / `/loop` / `/schedule`.

1. **Fetch first** (`git fetch --prune <remote>`), resolving `<remote>` + `<default>`, so the remote half of every read below is fresh — the queue itself is read **local + remote** (step 3), not remote-tracking only.
2. Read `policy.md` + guidance from the **fetched default ref** (yields the work + `## Accepted Prefixes`, `## Push`, `public-branch-tsugu`, `coordination-ref`, `stale-after`, among others).
3. **Read the queue from work-prefix refs, local + remote** (plus `knowledge/` from the coordination ref). There is no committed note layer — the queue *is* the set of work branches. Under local-first, work **stays on local** `prepare/*` by default, so discovery must read local work refs too; remote work refs are still read **regardless** of the push default (a leftover or opt-in-pushed remote `prepare/*` must still be seen). Mechanics (the local + remote union by slug) → `references/git-recipes.md`.

   **Partition each work branch `<work-prefix>/<slug>` by two ref-level facts, checked in order** — there is **no written branch state**:

   | Fact | State | Disposition |
   | --- | --- | --- |
   | tip contained in `<remote>/<default>` (or its remote aliases) | **settled** — the work landed | skip; `prune` cleanup candidate |
   | a slug-paired branch (by name) exists under a configured `## Accepted Prefixes` **OR** any **non-default, non-work** branch contains the tip | **taken over** — a human now owns the work (carried onto their own branch, or a slug-paired handoff) | skip as a candidate; surfaced at `prune`/`converge` (see *taken-over*, Change C) |
   | none of the above | **in progress** | candidate: read `context.md`, judge from the narrative |

   **Takeover by containment (Change B).** A `prepare/<slug>` is **taken over** when its tip is **contained** by a **branch** that is neither the default (nor its aliases `<remote>/<default>` / `<remote>/HEAD`) nor a work-prefix ref (local *and* remote `<work-prefix>/*`). This **generalizes** 011's accepted-prefix slug-pairing to a **human's own-named branch** (`isaac/fix-thing`) — the #52 gap where slug-pairing alone could not see the take. **Slug-name pairing stays** as the complementary catch for the squashed / rewritten take (where the human's branch no longer contains the tip but the name still pairs). The precise check — fresh `git fetch --prune` first, `git for-each-ref --contains` scoped to `refs/heads`/`refs/remotes`, the `<remote>/` prefix normalized before matching, default aliases + local-and-remote work refs excluded — lives in `references/git-recipes.md` (do not re-derive here). **Git-native, script-free:** this is one native `git for-each-ref --contains` plus inline filtering, documented as a recipe, **not a shipped script** (tsugu ships no scripts).

   **Classification is per-ref (per-tip), not per-slug.** The local + remote union-by-slug is a **display** merge only; the settled / taken-over / in-progress predicates each run on a **specific tip**. When the local `prepare/<slug>` and a stale `<remote>/prepare/<slug>` **diverge**, classify **each ref by its own tip**: a stale remote tip contained by a human branch is *taken over*, but a **newer local** in-progress tip that nothing contains stays workable — never mark the local in-progress ref taken-over from the remote tip's containment. The slug-level view shows both, flagged.

   Containment is `git merge-base --is-ancestor` / `git for-each-ref --contains` against remote-tracking refs (mechanics → `references/git-recipes.md`). Five notes, condensed:

   - **Handoff *is* a takeover; slug-pairing is the complementary catch.** Containment by **any** non-default, non-work branch is the **takeover** signal (Change B) — and that branch may equally be an **accepted-prefix** ref (a `converge` handoff) **or** a human's own branch (`isaac/fix-thing`): either way a human now owns the work and tsugu stops managing it. There is no separate *pending* classification competing with takeover. Slug-pairing stays only as the **complementary** catch for the squashed / rewritten take — where the rewrite severed containment but the accepted branch's name still pairs (ref names are write-once identity, so the pairing survives any commit rewrite the forge does). Both paths land in the **same** disposition: skip as a candidate, surface at `prune`/`converge`, never auto-delete.
   - **Core assumes merge commits.** Tsugu **recommends merge commits — do not squash-merge tsugu-managed branches**; preserved history is what makes settlement containment-derivable. Accept is **mode-agnostic** (the work branch is renamed to the accepted branch in **both** `include` and `exclude` mode — see converge / Change B), so settlement reads off the **accepted branch's** containment in default in both modes. Because that disposition can only be read *while the slug-paired accepted ref survives*, **recommend disabling the forge's auto-delete-head-branch for tsugu accepted branches**. *A landing that rewrites history (squash, rebase-before-merge, force-push) — or, in `exclude` mode, the human stripping `.tsugu/` into a fresh published branch before merging — breaks containment-derived settlement; the item then settles via `prune`'s possibly-landed (no containment) — confirm bucket; see `references/advanced.md`.*
   - **No marker — the partition + conservative judgment guard (see B1a).** Default handoff writes **no** marker (it renames and stops). A scheduled `prepare` is kept off handed-off work by the two-fact partition: **containment** (a merge-commit landing → settled) or **slug-pairing** (the retained accepted branch, **enumerated local + remote** → taken over). For a **non-containment landing** (a rewrite, or an `exclude`-strip) the retained accepted branch still pairs by slug; the advanced narrative backstop is only a **legibility** note on the accepted branch, **not** a resume-guard (a note there can't reach a surviving remote `prepare/<slug>`). The one signal-less residual is the accepted ref **deleted** *and* B3 not yet run, so a stale remote `prepare/<slug>` survives: held to the **same 004–008 guarantee level** — `prepare`'s judgment leans conservative (leave the stale branch for `converge`; reversible; never auto-merges), and running **B3 promptly** removes the ref (once no ref survives, the item just leaves the partition — the work is already in `<default>`). *Judgment, not a written status, governs.*
   - **Out-of-band PR closure (a forge-side decline, outside `converge`).** Distinct from the `drop` disposition (§ converge step 4): the human closes the PR and deletes the accepted branch *on the forge*, dissolving the slug pairing. **If a work ref still survives** (e.g. the stale remote `prepare/<slug>`, B3 not yet run), the item **resurfaces at the next `converge`** for re-decision — never auto-resumed by a scheduled `prepare`. **If no ref survives**, it simply leaves the partition (nothing to resurface).
   - **Recency claims + zero-commit exemption.** Claims are **derived from commit recency** (see Multi-agent): the `context.md` rewrite commit's author and timestamp *are* the claim. A branch whose tip still equals the default tip is **never classified by the table** — it is interrupted work or a **request-by-branch** (a human pushed `prepare/look-into-X` as the ask), never a cleanup target; it carries no recency until someone commits to it.

4. **Freshness-rebase the in-progress set before working it (Change A).** Read `## Freshness`'s `rebase-prepare-onto-default` from the fetched policy: fresh-init default is `yes`; **absent reads as `no`** (fail-safe) — `yes` only from an explicit field. When it reads `yes`, rebase each **in-progress**, **local**, checked-out `<work-prefix>/<slug>` onto the fetched `<remote>/<default>` before working it, forcing the merge backend so `.gitattributes` union drivers apply:

   ```bash
   git rebase --merge <remote>/<default>   # per in-progress LOCAL <work-prefix>/<slug>, on its own checkout — never the two-arg form, which would switch the shared checkout
   ```

   **The rebase set is the in-progress set, minus one exclusion.** Settled and taken-over branches are not worked at all, so nothing to refresh; **bare-submodule paired work branches are excluded from this automatic rebase** — rebasing one rewrites its SHAs, which dangles the paired meta branch's gitlink and the SHA recorded in its `context.md`; repairing the pair needs a coordinated gitlink-bump commit that only `converge`'s human-present pair handling can do coherently. `prepare` leaves bare-submodule pairs at their pre-rebase tip and surfaces them as "behind default" at the next `converge`, like any other unrefreshed branch. A **remote-only** in-progress ref (possible only under `push-prepare-branches: yes`) is materialized to a local branch first, then rebased the same way.

   **Conflict posture — deterministic, human-absent (Change B).** `.tsugu/context.md` carries `merge=union` (written by `init` to `.tsugu/.gitattributes`), so a *content* conflict there concatenates both sides and never stops the rebase — this is exactly why the backend above is forced to `--merge` (the legacy `apply` backend ignores `.gitattributes`). Any conflict the rebase **does** stop on is therefore real — a source-file conflict, or a *structural* `.tsugu/context.md` conflict union can't cover (modify/delete, etc.) — and the rule is fixed: `git rebase --abort`, restoring the pre-rebase tip exactly; `prepare` will **skip working that branch this run** rather than pile fresh commits onto a stale base. **No committed status or narrative write records the abort** — committing one would rewrite the claim's author-date and violate the no-status-field invariant; the fact is left to be **derived** at the next `converge` (behind default, did not fast-forward). Mechanics → `references/git-recipes.md`.

   **Delivery — local-first pushes nothing; cross-machine is pinned and divergence-guarded (Change D).** Under the local-first default the rebase touches only the local branch — zero external effect. Under `push-prepare-branches: yes`, the refreshed branch is pushed with a **pinned** `--force-with-lease=<branch>:<sha>` (`<sha>` = that branch's remote tip captured at step 1's fetch — **never** the bare `--force-with-lease`, whose expected value re-pins to whatever the ref advanced to and so stops guarding the tip reasoned about), and only once an **ancestor check run before the rebase** confirms the pre-rebase local tip contains that fetched remote tip; on failure (pre-fetch divergence) `prepare` **skips the branch entirely — no rebase, no work, no push** — and surfaces it for `converge`. A branch's first push (no prior remote ref) needs no lease. Mechanics (the ancestor-guard command, the first-push carve-out) → `references/git-recipes.md`.

   **Recency stays claim-neutral (Change C).** See *Multi-agent*, below, for the author-date recency read this refresh must not disturb.

5. **Bootstrap personal config (interactive only).** Personal config lives in a global, project-keyed folder (`~/.claude/tsugu/<project-key>/`; `<project-key>` derives from the repo's absolute common git dir, so every worktree of one repo shares one folder per machine — see `references/policy-and-intake.md`). It does not transfer across machines, so each machine seeds its own. When a section is absent **and** the run is interactive, ask **once**, separately for the two sections:

   - **sources** — *"Any observation sources to read besides git? A file path, MCP tool name, or where to look. I resolve the `read:` pointer with my own permissioned tools, never auto-executing it from config."*
   - **skills** — *"Any user-installed skills you trust me to use here during human-absent `prepare`? (default: none.)"*

   Record each answer in the personal folder; **a negative answer is recorded as a confirmed-negative marker** (`sources: git-native (confirmed)` / `skills: none (confirmed)`) so it is never re-asked — an unset section is distinct from a confirmed-empty one. When **headless/non-interactive**, never block: fall back to git-native (no sources, no opt-in skills) and surface "personal config unconfigured on this machine" at the next `converge`. Then **resolve** each configured source's `read:` pointer with your normal permissioned tools — read a file, call an MCP tool, or (only where a command is genuinely needed) issue it as your own gated tool call; Tsugu never directly executes the pointer string. **A source signal becomes a `prepare/<slug>` branch directly** — there is no committed note first.

6. Open work branches or worktrees **with native git** (`git worktree add`), naming them with the **work prefixes configured in `policy.md`** (default `prepare/*`) — discovery filters by the configured prefixes, so a hardcoded prefix that differs would be invisible to the next cold start. Then reproduce, inspect, run tests, try reversible patches.
7. Dispatch your **own review/investigate subagents** (built-in Task agents) when a change deserves a second pass before the human sees it — they work **inside the `prepare/<slug>` branch / its worktree**, recording findings in the work branch's `context.md` (and promoting durable findings to `knowledge/`), not as a separate same-slug branch. This is Tsugu working in private git space; it is distinct from the human-triggered review-loop, which the human triggers — Tsugu never runs it for them.
8. Maintain **`context.md`** on the work branch (pure narrative — rewrite the inherited mainline form into the branch's own story; that first rewrite commit *is* the claim). Promote durable, shareable findings into `.tsugu/knowledge/`. Refresh the convergence **packet** (`packets/<slug>.md`) in the **personal folder** — it is a personal/derived view, never committed.
9. **Commit the work branch (`<work-prefix>/<slug>`) — local-first.** `prepare` is **local-first by default**: commit the local work branch and **keep work local** — **push only when `push-prepare-branches: yes`**, a **cross-machine opt-in**. Read `## Push`'s `push-prepare-branches:` from the fetched policy **schema-aware**: when the field is **absent**, the default is `yes` if the repo is still `tsugu-schema: 4`, else `no` (any migrated repo, schema 5 or later, defaults `no`; the 4→5 migration pins the explicit `yes` into existing repos so behavior never flips silently). If `yes`, `git push --set-upstream <remote> <branch>` — in the **cross-machine** case pushing is what lets a *second machine's* agent inherit the work (there, the branch *is* the message); on one machine the local branch already *is* the queue. If pushing is set but otherwise **not** permitted by the boundary, commit locally and stop for approval (or use the policy-defined alternative) — never push past an explicit boundary.

   **Auto-push invariant (Change D).** `prepare` **auto-pushes only the `<work-prefix>/*` branch it is working**, and only when `push-prepare-branches: yes`. It **never auto-pushes** an accepted-prefix or human-named branch — publishing those is the human's act (011's B3, print-only). The sole exception — a cross-machine **agent-to-agent** push with no human present — is **deferred** to *Multi-agent: reserved*; absent that opt-in the invariant holds unconditionally, so "the agent pushes an already-converged local branch" cannot happen.
10. **Recurse into submodules (omni-repo).** After working this repo's own queue,
    **if this repo's own `## Recursion` permits descent** (default: only when
    relevant), enumerate submodules and gate each on a **readable `.tsugu/policy.md`**
    (three outcomes: HAS / BARE / **INVALID** — a `.tsugu/` without a readable
    `policy.md` is surfaced, never treated as bare) — that gate, not the submodule's
    own policy, decides recurse-vs-meta-drive. A **HAS-`.tsugu/`** submodule takes the
    **recurse-and-run** path — run this whole `prepare` routine inside it
    (`git -C <submodule>`) using the submodule's own policy + personal-config intake;
    it runs at its own schema (never force-migrated). For a **bare** submodule, the
    branch still lands **in the submodule** but **meta** policy governs it and the
    findings ride a **paired meta `prepare/<slug>`** (gitlink bump + `context.md`).
    The branch always lands at the lowest repo owning the **code**; `.tsugu/`
    knowledge lands at the lowest repo that **has** a `.tsugu/`. **Ask, don't guess:**
    when a bare submodule's default branch is ambiguous or a rule isn't covered by
    meta policy, ask the human if interactive, else leave the item unbranched for the
    next `converge`. Mechanics → `references/git-recipes.md` (§ Submodule recursion).

### `converge` (human present)

The human-attention phase. **Tsugu presents and yields, then completes the decided disposition in-session — it invokes no skill here.** The human triggers the skill they want by keyword ("let's brainstorm this", "debug it", "/review-loop"); the ecosystem takes over. `converge` runs decision *and* completion in one human-present session.

1. **Fetch-first** (same read path as `prepare`): resolve `<remote>` + `<default>`, `git fetch --prune <remote>`, read the queue **local-first — the local + remote work refs (the same union as `prepare`)**. **Read each tsugu branch live** (its `context.md` + DAG state) to assemble the picture — a `converge` on machine B reconstructs the full state from `git fetch` alone **when the work was pushed (the cross-machine `push-prepare-branches: yes` opt-in)**, never from machine A's packet. Any cache stays personal/ephemeral (the chat session or the global folder), never a committed `.tsugu/` artifact.
2. **Ask which branch.** List the candidate work branches (those the partition classifies as in progress, enumerated across **all** configured work prefixes (default `prepare/*`)), each with a one-line `context.md` summary and packet hint, and ask the human which to converge. An explicit branch argument (`/tsugu:converge <branch>`) skips the question. Alongside the candidates, show two more sections:
   - a separate **awaiting-merge section** — decided branches are not candidates, but listing them surfaces an orphaned accepted branch (pushed, then the session died before its PR opened); when `gh` is available, flag awaiting-merge items lacking an open PR. Also flag a possible **name collision** — an accepted tip sharing no history with the same-slug work it claims to carry — **in both modes** (accept renames the work branch to the accepted branch in include *and* exclude, so this check is no longer `include`-only). Work-vs-accepted *divergence* no longer arises: the rename means there is no separate work branch to diverge from the accepted one.
   - **a stale flag on the candidate list, not a separate block** — a candidate whose last activity predates `stale-after` (default 30 days; recorded progressively in `policy.md` by `converge` on first use) is shown with a **"stale" marker** and handled by the normal accept / park / drop / continue dispositions. Staleness is **derived** (last-commit timestamp, the same recency mechanism as claims); there is no dedicated converge cleanup block. The queue-wide read-only sweep of unused branches now lives in `/tsugu:prune`. **A scheduled `prepare` never cleans on its own.**
   - **behind-default + divergence, per candidate (Change E1)** — two more derived, read-only facts shown alongside the summary: **behind default by N commits** (`git rev-list --count <branch>..<remote>/<default>`), the same kind of marker as *stale*; and, for a pushed repo, **local/remote work-ref divergence** — local `prepare/<slug>` and `<remote>/prepare/<slug>` have diverged (neither contains the other), the exact state that made a scheduled `prepare` **skip** the branch under Change D's divergence gate. Surfacing it here is what that gate promised: without it the human would see "behind by N" and never learn *why* the branch stopped auto-refreshing. A current, undiverged candidate shows nothing extra.
3. Regenerate the **personal packet** live from the branches and lay it out alongside the prepared branches/worktrees and a summary of what was tried / worked / failed / evidence / remaining uncertainties; surface open questions (including any personal config unconfigured on this machine).

   Steps 1–3 touch **no git or shared state** — they make no commits, no pushes, no public coordination; regenerating the personal packet writes only a derived, ephemeral view in the personal folder (not a shared artifact, so it is not a meaningful side effect). In that sense running `/tsugu:converge` just to look is a first-class use — **looking and leaving is the morning status view**: how many prepared branches are workable today, what awaits merge, what's stale. Choosing nothing and leaving is a valid outcome; **all shared/git side effects begin only at step 4's disposition**.
4. **Decide *with* the human, then complete the disposition in-session:**

   - **Refresh first — the first per-branch decision on a behind-default candidate (Change E2–E4), before any disposition.** For each candidate E1 flagged behind default, ask before accept/park/drop — *"`<slug>` is N commits behind default. Refresh onto current default first? **[Y/n]**"* — default **Y**. Worded "refresh first," not "before handoff," because it precedes **all** dispositions, not just accept. On a busy repo this MAY be **batched** once at the top of the session — *"M of K candidates are behind default. Refresh all before review? [Y/n], or decide per-branch"* — falling back to the per-branch prompt only where a conflict stops it. This offer is **not gated by `prepare`'s `rebase-prepare-onto-default` flag** — the flag only governs the human-absent, routine rebase; here a human is present, sees the fact, and answers explicitly, so it runs regardless of the flag and is never a silent behavior change.
     - **Always the local WORK branch, never the accepted name.** The refresh operates on `prepare/<slug>` — minting `<accepted-prefix>/<slug>` before the human has chosen accept would leave an accepted-named branch nobody accepted, breaking B1's invariant that the accepted-prefix name *means* accepted (and would misclassify it as taken-over next pass). Same-machine, the local branch already exists — just refresh it; a **cold-start** converge (only `<remote>/prepare/<slug>` exists locally) materializes the **work** name first, never the accepted one:
       ```bash
       git switch --create prepare/<slug> <remote>/prepare/<slug>   # WORK name only, never <accepted-prefix>/<slug>
       git rebase --merge <remote>/<default>                        # refresh (conflict handling below)
       ```
       On **Y**, refresh, then continue to the disposition on the now-current `prepare/<slug>`; on **n**, proceed with the branch as-is (011 classic). Accept mints the accepted name **only at accept** (B1, below); park leaves the refreshed `prepare/<slug>` as-is; drop deletes it (the refresh was harmless, nothing was published).
     - **Conflict handling is human-present (Change E3) — different from `prepare`'s deterministic B2.** A `.tsugu/context.md` *content* conflict still resolves via `merge=union`, auto, lossless — identical to `prepare`. A **real** conflict (a source file, or a structural `context.md` conflict union can't cover) is **never blind-aborted**: surface it live and let the human **resolve it**, or `git rebase --abort` and **park** the item as a normal disposition. Nothing is forced.
     - **Pushed-repo reconcile, gated by divergence origin — never a clobber.** In a `push-prepare-branches: yes` repo the refresh rewrites only the local branch, so it now diverges from the remote's pre-rebase tip. What converge offers depends on **which** divergence E1 surfaced, checked the same ancestor test Change D's gate uses (did the pre-refresh local tip contain the fetched remote tip?): **refresh-created divergence** (pre-refresh local *contained* the fetched remote tip — this refresh is what moved it) means the rebase replayed the remote's commits, so converge **prints** (never runs) the pinned `git push --force-with-lease=<branch>:<sha> <remote> <branch>` for the human to run — B3's print-only posture, mainly useful after **park**; **pre-existing divergence** (pre-refresh local did **not** contain the fetched remote tip — the exact state Change D's gate skipped) means a force-push would discard remote work, so converge **never** prints a reconcile command for this case — it surfaces *"local and remote have diverged; integrate the remote work before handoff"* and leaves reconciliation to the human.
     - **The bare-submodule pair (excluded from `prepare`'s auto-rebase, Change A3) is refreshed here, coherently, human-present** — the submodule branch and its paired meta gitlink/`context.md` SHA move **together** under 011's paired-meta handoff form, exactly the human-present moment A3 deferred it to.
     - **Freshness only — still no build, no verify, no push, no PR** on a default handoff. 013 only adds this offered rebase step; completion stays exactly where 011 put it — the human's, or the maintenance exception below.
   - **Accepted — default handoff (mode-agnostic):** accept is a **minimal handoff** — **rename** `prepare/<slug>` → `<accepted-prefix>/<slug>` and **stop**. The agent does **NOT** build/test, rewrite `context.md` to a mainline narrative, push, or open a PR — completion is the human's. (Freshness is handled separately, by the Refresh-first offer above — accept itself performs no rebase.) (One *optional* exception to "no write": when a **history-rewriting landing is anticipated**, the advanced narrative backstop MAY add a one-line *"handed off — may have landed via squash/rebase"* **legibility** note to `context.md` — it is not a resume-guard; see the backstop note below and `references/advanced.md`.)
     - **B1 — rename (move, not a copy), cold-start safe.** The move renames only the **prefix**, preserving the slug. On the machine that prepared it: `git branch -m prepare/<slug> <accepted-prefix>/<slug>`. On a cold-start machine where only `<remote>/prepare/<slug>` exists: materialize the local WORK branch first — `git switch --create prepare/<slug> <remote>/prepare/<slug>` — then rename it exactly as the same-machine case does — `git branch -m prepare/<slug> <accepted-prefix>/<slug>` — never minting the accepted name directly from the remote-tracking ref (the *move* completes when the human deletes the remote `prepare/<slug>` — B3). `prepare/<slug>` does **not** survive beside the accepted branch — it is a **move, not a copy**. `<accepted-prefix>` comes from `policy.md`'s `## Accepted Prefixes` (default `feature/* bugfix/* chore/*`). **Before renaming/creating, check no `<accepted-prefix>/<slug>` already exists** (local or remote) — a collision means the slug is already in flight; surface it rather than clobber.
     - **B1a — the handoff-pending window needs no new marker.** Between the local rename and the human's remote reconcile (B3), `<remote>/prepare/<slug>` still exists, so a scheduled `prepare` could rediscover it. The **existing two-fact partition** already guards this, checked in order: (1) **containment** — after a merge-commit landing the work tip is contained in default → settled → skipped; (2) **slug-pairing** — the local `<accepted-prefix>/<slug>` from B1 pairs immediately (the partition enumerates accepted-prefix branches across **local + remote** refs), remotely once the human pushes (B3). No new marker is added. (A *second machine* running `prepare` in the pre-push window — when the accepted branch is local-only on the converge machine — is the **deferred multi-agent concurrency case**, see *Multi-agent*; single-agent / single-machine is fully guarded.) The residual (a history-rewriting landing **and** the accepted branch deleted) is held to the **same 004–008 guarantee level**: with the accepted ref gone, `prune`'s *possibly-landed* bucket **can't** derive it (that bucket needs a *surviving* accepted ref) — so the recourse is `prepare`'s **conservative judgment** (leave it for `converge`, never auto-resume) plus **B3** removing the stale ref. (Where the accepted ref is instead **retained**, `prune`'s possibly-landed-confirm bucket is the clean recourse.)
     - **B2 — mode-agnostic.** The rename is identical under `public-branch-tsugu: include` and `exclude`; the exclude-mode by-path **clean-cut** accept path is **removed**. The `.tsugu/` exploration commits **ride along** on `<accepted-prefix>/<slug>`; since the human owns everything after handoff, the human decides whether to strip `.tsugu/` when *they* open their public PR. (This narrows `exclude`: it still governs whether `.tsugu/` rides the default branch, but converge no longer cuts a `.tsugu/`-free handoff branch.)
     - **B3 — remote reconcile is a prompt, never a silent op.** After the local rename the remote still has the stale `prepare/<slug>` and lacks the accepted branch. The agent **surfaces the commands for the human** (resolving `<remote>`) and **prints these** — it does **not** run them:
       ```bash
       git push --set-upstream <remote> <accepted-prefix>/<slug>
       git push <remote> --delete prepare/<slug>
       ```
       **Local-first note (Change A):** under the default local-first policy there is **no remote `prepare/<slug>`** to delete (it was never pushed), so B3 shrinks to just the accepted-branch push. The remote-prepare-delete line above survives only in a **cross-machine opt-in** repo (`push-prepare-branches: yes`), where 011's full B3 applies unchanged.
     - **B4 — prune reminder.** Close the handoff with: *"handed off; once you've pushed `<accepted-prefix>/<slug>` and the work lands, run `/tsugu:prune` to sweep the stale `prepare/<slug>` and the settled branch."* No branch is prunable **at handoff time** (the human hasn't pushed yet and nothing has landed), so this points at `prune` for *later*; it asserts no current count.
     - **B5 — no settlement tracking; the old completion tail is dissolved.** After the rename the local `prepare/<slug>` no longer exists; the item leaves the queue once the remote work ref is gone (B3). `converge` keeps **no** named completion tail — promotion moves to curation (the orthogonal `promote`, below) and cleanup moves to `/tsugu:prune`. Whether `<accepted-prefix>/<slug>` later lands is **the human's** concern; its settled-ness is read **later, by `prune`** (via containment, or its possibly-landed bucket where history was rewritten), never actively tracked here. State stays derived, never a status field.
   - **Maintenance exception — human-marked tasks may complete (default stays handoff).** The **complete** path (rename first → then bring the accepted branch current and verified to ready-to-merge per the maintenance recipe in `references/git-recipes.md`) is unlocked **only when the human has explicitly marked the task as maintenance-type** — never the agent's call. Two designation channels: (1) **human-authored task-source designation**, captured at intake and recorded **verbatim** in the branch's `context.md` narrative (e.g. *"human-marked maintenance (security upgrade) — completion authorized; source: <where the human marked it>"*) — the agent **must not synthesize** the designation from the work's content (a diff that *looks* like a dependency bump is not self-authorization); (2) **live at converge**, the present human says "this one's maintenance — take it to completion." **Provenance fallback:** if the agent cannot tell whether a label was applied by a human or by automation, it does **not** treat it as authorization — it falls back to channel 2 (ask live); **ambiguous provenance defaults to handoff, never completion.** The complete path still **renames first** (B1, so `prepare/<slug>` is gone either way), still surfaces the B3 prompt and the B4 prune pointer, and **Tsugu still never auto-merges** — "ready-to-merge" means accepted-branch readiness (rebased + verified), not a clean public diff; an `exclude`-mode repo's human still strips `.tsugu/` when they open the public PR. The agent **never self-classifies** a task as mechanical; absent an explicit human marking → default handoff (B). Cleanup of the resulting branches is deferred to `/tsugu:prune`.
   - **Accepted (bare-submodule paired branch) — also a handoff.** Under handoff-only
     there is no agent-driven two-repo landing transaction. At submodule converge the
     submodule's `prepare/<slug>` is simply **renamed to a human work branch**
     (`<accepted-prefix>/<slug>`) **in the submodule**, and stops —
     the **meta repo no longer manages it** (to the meta repo it is just "a human work
     branch now exists in the submodule"; no agent-driven gitlink re-point). The cross-repo landing (gitlink
     bump, both PRs) is **the human's** when they finish the work. The existing **paired
     meta `prepare/<slug>`** is **not auto-managed** here — it remains a normal candidate
     classified by the **same existing meta partition** (containment, then slug-pairing;
     no new marker) that surfaces at the **meta** repo's own `converge` (and at `prune`).
     The maintenance exception still applies per-repo if the human marked that work
     maintenance-type. Full procedure → `references/advanced.md` (§ Bare-submodule
     handoff). Drop / park / continue each act on **both** branches of the pair. Note:
     meta `converge` does **not** aggregate HAS-`.tsugu/` submodules' own queues —
     converge those by running `/tsugu:converge` inside each submodule.
   - **taken-over — suppress-and-surface, human-confirmed cleanup (Change C).** A `prepare/<slug>` whose tip a **non-work, non-default branch** contains is **probably redundant** (a human carried the work onto their own branch), but containment is **not proof** — a scratch/experiment branch or a sibling item based *on top of* the tip also contains it. So the disposition **never silently drops and never auto-deletes**: the agent **does not auto-resume** it, but it is **surfaced** at `prune`/`converge` for the human to **confirm or reject** — a real takeover → cleanup; a false-positive (build-on-top, sibling item) → the human says "keep working" and it returns to *in-progress*. A scheduled (human-absent) `prepare` simply **leaves it for `converge`**. On confirmation the redundant ref is removed **local *and* remote, both human-confirmed** — local too, because a wrong guess would destroy the queue identity (slug + `context.md`-as-claim) of still-in-progress work.
   - **drop:** record *why* in the branch's `context.md` narrative ("dropped — do not resume: <why>"; agents read the narrative before touching any candidate), remove worktrees, delete the branch when safe. (Renamed from `reject`; the "record why" narrative is retained.)
   - **park:** update `context.md`'s narrative with what is needed to resume, and the personal packet. No status to set — a parked branch is simply a candidate whose narrative says "blocked on X".

   **`continue` is implicit.** Every branch the human does **not** act on is already "continue" — it stays an in-progress candidate. Steps 1–3 above (the looking-and-leaving morning status view) touch no git or shared state, so a `converge` that decides nothing leaves every branch continuing by default. `continue` is therefore **not** a named verb; its only active form is the human triggering a workflow skill on the branch *now* ("let's brainstorm this", "/review-loop") — which Tsugu does not fire itself.

   **Findings curation is an orthogonal converge checklist item.** Promoting durable findings is **not** a sibling disposition in a pick-one list — **curation is orthogonal**, a converge checklist item (not a fifth verb): it rides *any* disposition ("**drop** the branch yet **promote** the lesson" is valid) and may also run standalone during the morning view. When there is nothing worth promoting it is a no-op. **Flow:** surface (a) this work's durable findings (from the branch's `context.md` / knowledge additions) **and** (b) existing `.tsugu/knowledge/` entries → ask the human **which should be organised into the agent md** (`CLAUDE.md` / `AGENTS.md`) → the **agent drafts** the edit → the **human approves** (moving findings into human-facing docs is public coordination → ask first).

   **The `knowledge/` ↔ agent-md boundary (a finding lives in exactly one place).** The two stores are not interchangeable and promote runs **one direction only**: `knowledge/` holds **WIP / still-evolving / cross-cutting** findings (the working wiki); the agent md (`CLAUDE.md` / `AGENTS.md`) holds **durable, human-endorsed conventions**. **Promote = move, not copy** — graduate `knowledge/` → agent md once a finding has stabilised into a durable convention the human endorses, then **remove it from `knowledge/`** (at most leave a pointer); there is no reverse direction. A **write-gate** keeps not-yet-durable or already-recorded facts out, and promote-as-move keeps a finding in **exactly one place**, never both. (Details → `references/notes-and-packet.md`.)

   **Invariant.** None of accept / park / drop / continue / promote sets a *status field*. Each produces a branch action (accept/drop), a narrative write (park, drop's reason), or a knowledge write (promote); state stays **derived** from refs, the DAG, containment, and recency. *Narrative informs judgment, never classification.*
5. **Wait for approval before any public coordination** — opening/merging the PR is the human's act; **Tsugu never auto-merges**.

The packet may **hint** which workflow skill fits ("ready for planning", "this bug needs debugging", "this can go to review-loop") but must not fire it.

### `prune` (human present)

A **fourth** routine — **not** part of the per-item lifecycle the way `prepare` / `converge` are; it is a **recurring cleanup pass** the human runs when refs have piled up. A queue-wide, **human-present** sweep of unused branches (**local + remote**) — the home for the destructive cleanup that per-branch `converge` (now handoff-only, no tail) and a never-cleaning scheduled `prepare` leave to accumulate. **Small: a view + approve-delete, not a new workflow.**

1. **Listing is read-only until the human confirms.** Like the morning view, steps before deletion touch no state — `prune` lists what is removable and **why**, derived from refs / DAG / containment / recency. **`prune` is human-present and deletes nothing without per-item human confirmation** (running it just to look is fine). A narrative hint like "do not resume" is **surfaced for the present human to confirm**, never an auto-classifier that deletes on its own. *Judgment by a present human, not classification by a status field.*
2. **What `prune` lists, and how each is handled** — **conservative by default**; under the handoff model the human owns the branch after the rename, so most categories are **surface-and-confirm**:

   | Category | Derivation | Handling |
   | --- | --- | --- |
   | **settled** | tip contained in `<remote>/<default>` — the human merged with history intact | **delete on confirm** (low risk — provably landed). Local + remote. The main post-handoff target |
   | **taken-over (redundant prepare)** | a `prepare/<slug>` (local or remote) whose tip a **non-work, non-default** branch contains — a human carried the work onto their own branch | **surface + confirm each** (like *possibly-landed*) — never auto-delete; the containment signal can false-positive on a build-on-top branch. On confirm, delete local + remote. **Precedence:** if `<remote>/<default>` contains the tip it is **settled** (above); the broad partition state *taken-over* has **two sources** (foreign containment **and** slug-pairing), but **only the foreign-containment source enters this prune bucket** (a non-default branch contains the tip). The slug-pairing **squash/rewrite** source is **not** containment-derivable — it surfaces as *possibly-landed* (below), never this row |
   | **leftover worktree** | a worktree dir whose branch is already deleted | **delete on confirm** (just a stale checkout dir) |
   | **possibly-landed (no containment)** | a surviving `<accepted-prefix>/<slug>` whose tip is **not contained** in default and whose landing **can't be confirmed by containment** (squash / rebase / `.tsugu/`-strip) — whether its remote counterpart was deleted **or** the ref was *retained* per the rewrite/strip recommendation. **This is also the home of the squash/rewrite *taken-over* source** (no containment signal — only slug-pairing) | **surface + confirm each** — `prune` cannot prove it landed, so it asks; never auto-deletes on a guess. On confirm, also delete any **paired stale `prepare/<slug>`** work ref (local + remote, human-confirmed) — the slug pairing carries its cleanup since containment cannot |
   | **dropped** | the branch's `context.md` says "do not resume" | **surface + confirm** — the backstop for branches converge's `drop` recorded but could not delete (a remote ref, a deferred cleanup) |
   | **orphaned accepted** | a pushed accepted branch with no open PR and no recent activity | **surface read-only + confirm** — often the human's **live** work branch, so never auto-eligible |

   Deletion is **per-item or batch**, on explicit confirmation. **Remote deletes: `prune` runs `git push <remote> --delete <branch>` after explicit per-item human confirmation** — the confirmation *is* the approval. This differs from converge **B3**, which only *prints* the remote-delete command (mid-handoff, precondition not yet met). The unifying rule: **no remote delete without explicit human approval**. Cleanup order is the established one: `git worktree remove` **before** `git branch --delete`.
3. **Conservative — never deletes unfinished work.** `prune` **never deletes** in-progress, recent, or unsettled work. **Stale in-progress** branches (older than `stale-after`, but not landed) — including **scope-only** branches (Change A), handled identically — are **surfaced read-only** and marked *"not deletable here — decide at `converge`."* `prune` only *points*; the resume / park / drop decision happens in `converge`'s normal candidate flow.

Mechanics (containment + slug-pairing reads; the delete-on-confirm vs surface-and-confirm categories; remote delete after per-item confirm) → `${CLAUDE_PLUGIN_ROOT}/skills/tsugu/references/git-recipes.md` (§ Prune sweep).

## Private vs public boundary & skill use

Recorded per-repo in `.tsugu/policy.md`:

```text
Git branch / pushed branch / committed .tsugu/    →  agent may do freely
MR / PR / tracker / Slack / reviewer assignment   →  human approval required
```

**Tsugu invokes NO user-installed skill by default** — present or absent. It uses **native git directly** (worktrees via `git worktree add`, branch/cleanup via plain git / `gh`) and its **own built-in capabilities** (Task subagents, Codex-as-a-tool, Claude's own reasoning). The only asymmetry is *what Tsugu does on its own*:

- **Human absent** (`prepare`): work the git tree, dispatch own built-in subagents.
- **Human present** (`converge`): present and yield, then complete the decided disposition; the human triggers workflow skills by keyword.

Workflow skills (planning, debugging, TDD, finishing-a-development-branch, review-loop) are **human-triggered and optional** — Tsugu never runs them for the human. **Per-machine opt-in (personal config, not shipped behavior):** a human MAY, in their personal folder's `skills` section, list specific user-installed skills Tsugu may use during human-absent `prepare` *in that repo on that machine*. The shipped skill stays skill-agnostic.

## Multi-agent: reserved

Tsugu today is a **single agent + its built-in subagents**. The discovery layer is honored (fetch, partition the queue from refs + the DAG, process it); concurrent arbitration is **not built**.

- **Claims are derived from commit recency, keyed off author-date — no claimed-by/claimed-at fields exist.** Beginning active work means rewriting `context.md`, and that commit's **author-date** *is* the claim. A work branch with recent commits is treated as taken; a stale last commit = free to pick up. When agents share one git identity (one human, two machines — the primary scenario), authorship cannot distinguish them and the rule **degrades to pure recency**, acceptable for a courtesy yield. **No lock backs this.**
- **Recency reads author-date, never committer-date.** The read is `git log -1 --format=%aI <ref>` / `git for-each-ref --sort=-authordate` (author-date), not the committer-date equivalents — a rebase rewrites committer-date to now on every replayed commit but leaves author-date untouched, so `prepare`'s freshness-rebase never fakes a fresh pickup signal for a genuinely stale branch. The same author-date read backs `converge`'s `stale-after` staleness marker.
- **No arbitration, no locks** (deferred to a future multi-agent iteration, which would formalize the staleness window). Two agents grabbing the same branch at once is undefined today (doesn't arise with one agent).
- **Cross-machine `prepare/*` push is the opt-in reserved here.** Under local-first (Change A) `prepare` keeps work local by default; `push-prepare-branches: yes` exists for genuine **cross-machine agent collaboration** (machine A prepares, machine B inherits via `git fetch`). The auto-push invariant's **sole exception** — an agent pushing a coordination ref *for another agent* with no human present — is this deferred case; it is not built further here, the knob is the opt-in.
- The substrate (committed + pushed `.tsugu/`, branch-as-message, per-ref `context.md`, ref-and-DAG-derived state) is **forward-compatible** with multi-peer coordination; this design introduces nothing that assumes a single agent.

## Scheduling & recursion

**Scheduling.** `prepare` is meant to run on a cadence, wired by an external driver **the human starts** — a local cron, or `/loop` (cloud `/schedule` works too). But the skill **cannot self-wake** — the driver is always external. The skill depends on no scheduler. **Recommended default locus:** the **provisioned machine** — the one holding **both** the personal-folder source config (the `read:` pointers, never committed) **AND** the MCP/connector credentials, typically the local homelab — since `prepare`'s useful signals come from interactively-authenticated sources and neither dependency transfers across machines. An **unprovisioned** cloud/headless run is still allowed but not the default: it **degrades to git-native** (it works the queue derivable from refs; no tracker/source intake), and the two gaps surface differently — **source config missing** → detectable at any *same-machine* `converge` (the existing "personal config unconfigured on this machine" notice); **credentials missing / MCP auth fails** → reported in the run's **own output only** (the driver's log on that machine), **not** auto-surfaced at a later `converge` — no committed or cross-run diagnostic is persisted (state stays single-layer), and `converge` gains no source-probing scope. The distinction is **provisioning, not cloud-vs-local**: a cloud machine independently provisioned with both does **not** degrade.

**Recursion (omni-repo).** A single repo and an omni-repo are the **same
abstraction**. After working its own queue, `prepare` enumerates submodules and gates
each on a **readable `.tsugu/policy.md`** (HAS / BARE / **INVALID** — a `.tsugu/`
without a readable `policy.md` is surfaced, not treated as bare): a HAS-`.tsugu/`
submodule takes the **recurse-and-run** path (its own policy + intake, its own
schema); a bare submodule is **meta-driven** with
the branch in the submodule and findings on a **paired meta branch** (gitlink bump +
`context.md`). The branch always lands at the lowest repo owning the **code**;
`.tsugu/` knowledge at the lowest repo that **has** a `.tsugu/` (else it bubbles up).
The **parent's own `## Recursion`** toggle governs whether it descends at all ("only
when relevant"); descent into a bare level goes **one level deep** (direct child
only). **Context placement rule:** write context at the **lowest repo level where it
stays true**; promote upward into `.tsugu/knowledge/` only when it spans repos.
Mechanics → `references/git-recipes.md` (§ Submodule recursion); handoff →
`references/advanced.md` (§ Bare-submodule handoff); graduation →
`references/notes-and-packet.md` (§ Graduation).
