Skip to content
Back to skills

Signoff

ASecurity

End-of-session — update memory, write journal entry, clean up

  • 17 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 2, 2026
ai-agentsgobashgit

Works with

  • cursor

Security analysis

A100/100

Scanned September 20, 2026

npx -y skills add mmnto-ai/totem --skill signoff --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Signoff?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Signoff
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mmnto-ai-signoff/badge)](https://www.skillsdirectory.com/skills/mmnto-ai-signoff)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: signoff
description: End-of-session — update memory, write journal entry, clean up
---

<!-- totem:skill-start -->

End-of-session wrap-up. Post-Proposal-282 (ADR-106), journals + handoffs live in the per-repo `.totem/orchestration/<agent-id>/` tree (gitignored) — NOT the substrate. Substrate stays as a frozen archive for forensic reads; the active surface is local.

0. **Crown gate — derive FIRST (Prop 305 §8; operator-ruled 2026-08-13; non-cohort scope amended by operator word 2026-08-14, recorded on the mmnto-ai/totem-strategy#488 R-table).** **Journal rule first — every seat, every repo:** restate your OWN chain's still-open `owed:` lines only — lines where YOU are the waiter and `@holder:` names the counterparty who owes (naming yourself as `@holder:` makes a note-to-self the parser silently skips) — and never another seat's carryforward: the parser keys each edge's waiter to the journal-owning seat, so a copied line mints a live foreign edge in YOUR chain (a line self-held at its origin is a skipped note-to-self THERE and a LIVE edge in yours) that persists until your own next journal drops it. (Canonical rulings home: mmnto-ai/totem-status#127.) **Then the gate ladder:** read the `totem:agent-bus` marker in this repo's AGENTS.md and check the step-2a cohort table below. No declared marker (absent, or missing `role`/`seat` — the parity sensor's not-declared set) AND this repo's basename is NOT in the cohort table = **non-cohort consumer**: the crown gate does not apply — run your full signoff. No declared marker but the repo IS in the table = a cohort repo that has not normalized: treat as crown **vacant** (fail-closed — the ruled default). Marker declared: derive `primary=` fresh — that seat is the crown; declared but no `primary=` = crown **vacant**. Vacant (either arm) is a legitimate state: surface upkeep stages/defers, mail the operator, and no seat self-promotes (transfer is the operator's word, Prop 305 §8.1; vacancy legitimacy §8.4b). **Before comparing yourself to `primary=`, verify your OWN identity — the signon S0 check applies at signoff too:** your seat derives per step 2a, and a mis-scoped or inherited `TOTEM_SELF_AGENT` naming a foreign seat must not make this session the crown; a foreign or ambiguous self-identity is fail-closed — no crown decision, no upkeep mutations — until the identity is fixed. If you are NOT the crown, your signoff is seat-anchored + own-lane: skip the surface-upkeep MUTATIONS — derived-cache/corpus rebuilds, GH board writes, cohort-wide upkeep walks, and step 4's shared-tree branch cleanup (crown-scoped there by name) — while every OTHER managed step (1–3, 5–6) still runs for every seat, and read-only derivation stays open to all: derive, then report staleness to the crown by mail.

1. **Update memory.** Update auto-memory files (e.g. `MEMORY.md`, topic memories) with any new state — version shipped, tickets closed, key decisions, banked feedback or doctrine signals.

2. **Write a journal entry to the per-repo orchestration path.** Filename convention: `<model>-NNNN-<short-topic-slug>.md` (e.g., `claude-0057-phase-4-resolver-shipped.md`).

   **Resolve the path two steps:**

   a. **Identify your agent-id** from the current repo's basename. The hardcoded map (Proposal 282 § Scope item 3 — the prose twin of `COHORT_AGENT_MAP` in `@mmnto/totem`, which a test holds it to; the roster of record is the cohort-roles matrix in the strategy doctrine):

   | Repo (`git rev-parse --show-toplevel` basename) | Claude agent-id                     | Gemini agent-id   | Kimi agent-id     |
   | ----------------------------------------------- | ----------------------------------- | ----------------- | ----------------- |
   | `totem`                                         | `totem-claude`                      | `totem-gemini`    | `totem-kimi`      |
   | `totem-strategy`                                | `strategy-claude`                   | `strategy-gemini` | `strategy-kimi`   |
   | `liquid-city`                                   | `lc-claude`                         | `lc-gemini`       | `lc-kimi`         |
   | `arhgap11`                                      | `arhgap11-claude`                   | `arhgap11-gemini` | _(not seated)_    |
   | `totem-status`                                  | `status-claude`                     | `status-gemini`   | `status-kimi`     |
   | `totem-playground`                              | _(orphan stream — no native agent)_ | _(orphan stream)_ | _(orphan stream)_ |

   This table is the BOOTSTRAP FALLBACK, not the roster: three of the roster's five vendor columns plus two archived repositories, and it rots when a seat is added — three of its four Kimi cells read "not seated" for weeks after those seats were seated (filled here; mmnto-ai/totem#2865). The core map it twins carries the four Kimi seats (mmnto-ai/totem#2875), and the table-to-map sync test holds the two as an equality, so a Kimi seat resolves on a fresh clone with no seat dir, no `TOTEM_SELF_AGENT` and no `config.json` `host_agents`. `totem mail --derive-seat` is the derivation; no cell here overrides it. Seat discovery is dir-derived (mmnto-ai/totem#2141): any `.totem/orchestration/<agent-id>/` directory registers that seat for this repo, UNIONED with the basename map above so roster siblings stay visible on fresh clones where the gitignored tree is partial (precedence: `TOTEM_SELF_AGENT` env > `config.json` `host_agents` > seat dirs ∪ basename map). Override hook: a `host_agents: string[]` field in `.totem/orchestration/config.json` still **replaces** the derived answer — but omitting a PRESENT seat dir attaches a loud warning naming the omitted seat (the dir is the registration; config-exclusion is not a decommission mechanism). The returned list of agent-ids is used by consumers (e.g., `totem mail`) to filter cross-repo handoffs — messages addressed to any agent-id in the list belong to this repo's session.

   **Visiting case.** If your own agent-id does not appear in your row — the cell for your vendor reads `_(not seated)_` or an orphan-stream value, or the table has no column for your vendor at all — you are visiting a repo that doesn't natively host your agent. Resolve the journal path to `<repoRoot>/.totem/orchestration/<your-home-agent-id>/journal/`, where `<your-home-agent-id>` is your own agent-id (e.g., a `strategy-claude` session always writes as `strategy-claude` regardless of which repo it's visiting; concretely, `strategy-claude` visiting `totem-status` — whose row seats `status-claude`, not `strategy-claude` — writes to `totem-status/.totem/orchestration/strategy-claude/journal/`). The journal records the visiting agent's session state — the host repo doesn't need a native agent of your vendor to be a valid write target.

   b. **Resolve the journal directory** via `resolveOrchestrationPaths(repoRoot, agentId).journal` from `@mmnto/totem`. Returns the absolute path to `<repoRoot>/.totem/orchestration/<agent-id>/journal/` when the tree exists. If `source === 'none'` (the tree does not exist yet in this repo) the resolver returns `null` for every path field — in that case, construct the path manually as `<repoRoot>/.totem/orchestration/<agent-id>/journal/` and create the directory first via `mkdir -p`; the path is gitignored and safe to create.

3. **No commit, no push.** `.totem/orchestration/` is gitignored — local filesystem write is the entire operation. No more substrate rebase-retry loops; the cross-agent write-collision class is eliminated by the single-writer-per-path invariant (you only ever write into your own `<agent-id>/` subtree).

4. **Clean up stale local branches — CROWN ONLY where the crown gate applies (step 0; in a non-cohort repo the gate does not apply and this step simply runs — the named design choice per the mmnto-ai/totem-strategy#488 R8 ruling).** The cleanup mutates the SHARED per-repo working tree — cohort upkeep, not own-lane (worktree-pinned branches refuse deletion, so it is collision-safe, but ownership is the point, not safety). A non-crown cohort seat skips this step and reports any `[gone]` branches to the crown (or, crown vacant, the operator) by mail instead.

   ```bash
   git for-each-ref --format='%(refname:short) %(upstream:track)' refs/heads | while read -r branch track; do
     [[ "$track" == "[gone]" ]] && git branch -D -- "$branch"
   done
   ```

5. **Prune + compact your own ECL cursor (retention + processed-mark GC).** Delete your own `outbox/` dispatches older than the retention window (**N = 14 days**) per ECL outbox-retention doctrine (`mmnto-ai/totem-strategy:doctrine/ecl-discipline.md` § 4.4), THEN compact your `processed/` cursor per § 4.5 / ADR-106 § A2. The outbox is transport, not archive — a dispatch's durable content already lives in its home (rulings → ADRs / issues, work-state → the GH board, session history → `journal/`), so the aged courier file is disposable (gitignored + local). The `processed/` cursor is the read-side twin: a mark whose inbound dispatch its sender already swept shadows nothing, so it is safely collectable. The operator should never have to janitor the mail substrate.

   **Mechanism:** `totem ecl-gc --apply --compact` — self-resolves your agent-id (same precedence as step 2a: `TOTEM_SELF_AGENT` env > `config.json` `host_agents` > seat-dir ∪ basename map). It **prunes** only `<repoRoot>/.totem/orchestration/<your-agent-id>/outbox/` (a self-resolving binary structurally cannot prune a peer), then **compacts** only your own `processed/` marks that shadow nothing. Compaction is cursor-coupled, not age-based, and deletes ONLY against a provably-complete poll — full expected cohort roster present, zero scan warnings, not truncated — else it retains everything (uncertain ⇒ retain). Dry-run by default; `--apply` deletes. Neither phase touches `journal/`. Report the pruned + collected counts. **Exit codes:** `0` clean · `1` some deletes failed (janitorial sensor) · `2` usage/agent-unresolvable · `3` compaction ABORTED loudly (fail-loud, never a silent skip) — no cohort roster declared, the roster is incomplete on this machine, or its A2.4 re-poll check tripped. **Do not block the seal on `1` or `3`** — the gate-red arms retain the whole cursor (uncertain ⇒ retain); only note them. The gc is a janitorial sensor, not a gate (Tenet 13).

6. **Report:** what shipped, what's pending, what's next.

**Cross-repo handoffs** (when you need to dispatch a message to another agent) write to your own `<repoRoot>/.totem/orchestration/<agent-id>/outbox/<YYYY-MM-DDTHHMMZ>-<your-agent-id>.md` with `to: <recipient-agent-id>` in the frontmatter. Recipients discover inbound handoffs by polling the single-level glob `<workspace>/*/.totem/orchestration/*/outbox/*.md` filtered by their own `to:` frontmatter match.

**Substrate (legacy) is read-only.** Do NOT write new content to `mmnto-ai/totem-substrate:.handoff/` or `:.journal/`. The substrate stays mounted as a frozen archive accessible via `resolveSubstratePaths(cwd)` for forensic reads; the cutover broadcast (when it lands) will confirm the final substrate-write cutoff.

<!-- totem:skill-end -->

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.