Portable sessions (the bundle)¶
mokata's session state — the resumable run checkpoint(s), the approved approach, the emitted spec,
and any in-progress brainstorm — normally lives under .mokata/temp_local/, local and gitignored.
A session bundle is the portable form of that state: a single, self-contained file you can carry
to another machine or hand to a teammate, from which mokata resume continues the work.
It is composed from existing primitives, not a new state store: the run checkpoints
(pipeline_run__<id>), the brainstorm progress, the approved approach, and the emitted spec are all
read back through the same StateStore that the pipeline writes to. The bundle just collects,
packages, ships, and re-hydrates them.
What a bundle is¶
A versioned JSON object — the bundle schema is at v2, and a v1 bundle still pulls fine (back-compat is kept; a bundle newer than the reader is refused, never silently downgraded) — carrying:
state— the collected session keys, machine-path-free (absolute paths are stripped to basenames, so nothing machine-specific travels);repo_fingerprint— a deterministic, content-free signature of the codebase (its top-level layout), used to detect a cross-codebase pull;content_hash— a SHA-256 over the substantive payload — the schema, kind, fingerprint, run id, and state, plus (at schema v2) the transcript, meta, and cross-repo marker — not the provenance, so a re-push of the same session at a later time stays idempotent;provenance— author, source (a repo label, never a machine path), and created timestamp;resume— a small descriptor (run id, resume phase, done/total) solistreads well.
It is deterministic: the same (session, tag, author, timestamp) always produces the same
bytes.
Saving vs sharing — where the gate sits¶
mokata session save is ungated and purely local. It snapshots the in-flight session (the
brainstorm's progress, the approved approach, the run checkpoints) into your own .mokata/ so
mokata resume can continue it — nothing leaves the machine, so there is nothing to gate. The
human gate sits at the share boundary: push and pull, where state crosses to (or arrives
from) somewhere else.
That boundary is also where mokata asks for consent to share unfinished thinking. A push of an in-progress session — a brainstorm with no approved approach — refuses unless you say so:
| Flag | What it does |
|---|---|
--save-first |
snapshot the session, then bundle it — one atomic action, with no gap between what you see and what you share |
--allow-in-progress |
consent to share an unfinished session (a brainstorm with no approved approach) |
--requirements-only |
bundle only the distilled requirements (the anchor, goal, constraints, and requirement lines) as a cross-repo handoff — no approaches, no approval, no transcript; the repo-fingerprint check is replaced by an origin label |
--save-first is pure convenience. The other two are the two alternative consents: share the
unfinished thinking, or share only what it distilled to.
The invariants (why it's safe to share)¶
Sharing session state means moving untrusted, mutable content between repos, so the bundle is held to the same inviolables as every other mokata write — on both ends of the trip:
- Human-gated on push and pull (P2). Neither end writes silently; a declined gate writes / hydrates nothing.
- Secret-scanned on push and pull. The bundle is untrusted on pull, so it is re-scanned there; a secret anywhere in the session is a hard block approval cannot override.
- Content-hash verified on pull. A corrupted bundle is caught, not served.
- Cross-codebase mismatch surfaced, never silently applied. If the bundle's repo fingerprint
differs from the target repo's, the pull stops and surfaces it; applying anyway is an explicit
--forceoverride. -
The approach approval never crosses machines. On pull, the
approved_approachhandoff is stripped and the brainstorm's approved flag is cleared — even one that was approved on the source machine hydrates as not approved, withimported: approval not transferred — re-approve on this machine (HARD-GATE)appended to the record. Approving an approach is your decision, and a decision does not travel inside content: the HARD-GATE re-runs here.Precisely, and no further: this is true of the approach approval. An emitted spec crosses intact — it is content the completeness gate already proved, not a pending decision — and write proposals, gate overrides, and TDD red/green state are never bundled at all. - Degrade-clean. No session → a friendly no-op on push; a missing or corrupt bundle → a clean error, never a crash.
Where it sits¶
The transport is derived from the repo, not guessed at. push/pull take
--to/--from {local,postgres}, but you rarely pass either: the default is derived
from the repo's mode — a team-connected repo (one shared Postgres DSN) travels over
postgres, a solo repo over a local file. An explicit value is honoured verbatim,
and --file forces the local file transport even on a team-connected repo (the explicit
escape hatch).
On the local transport the bundle file lives at .mokata/session-bundles/<tag>.json — in the
.mokata/ root, not under temp_local/ — so it travels with the repo: you sync the repo or
copy the file.
Removed transport (removed in 0.0.18).
vault— the session-transport kind that stored bundles under.mokata/vault/sessions/— has been removed. Nothing of yours was deleted: those bundles are the same JSON the local transport reads, so move them into.mokata/session-bundles/andmokata session list/mokata session pull <tag>picks them up, still content-hash verified, human-gated and secret-scanned.mokata session listtells you if this repo still has any. ⚠ The design vault at.mokata/vault/is a different thing and is not removed — see share a design vault.
See the portable-sessions how-to for the commands, and governance & audit for the gate it shares with every other durable write.