still·man (n.) — the distillery worker who tends the still, watches the spirit run through the safe, and decides where to make the cut.
Every session leaves behind a wash: hours of dialogue, most of it ephemeral. Somewhere in it are the few drops worth keeping — the correction you gave the agent, the assumption that proved false, the decision that got settled. Stillman runs the still when the session ends, draws off proposed memories, and holds them in the spirit safe until you make the cut. Nothing is casked without a human yes.
One plugin, two platforms: Claude Code and OpenAI Codex — same repo, same hooks, same review skill.
sequenceDiagram
participant W as The wash (session)
participant S as The still (SessionEnd hook)
participant D as Distiller model
participant SS as Spirit safe (pending/)
participant N as Next session
participant You as You (the stillman)
W->>S: transcript_path, session_id
S->>S: extract dialogue, discard the tool traffic
S->>D: dialogue + memory index
D-->>SS: 0–5 proposals (most runs: nothing — that's correct)
N->>SS: SessionStart: anything in the safe?
SS-->>N: "2 proposals pending"
You->>N: "make the cut"
N->>You: present each proposal
You-->>N: keep / feints
N->>N: kept → casked in the memory store, Supersedes honored
N->>SS: safe emptied
Agents forget everything between sessions. The fix is memory — but automatic memory written silently by a model is how stale, wrong, or embarrassing "facts" accumulate. Distilleries solved this problem centuries ago: the still runs unattended, but the cut is a human decision, made at the spirit safe, every run.
- Propose-only. The still never fills a cask on its own. Every memory passes through the safe, and you hold the key.
- Heads and tails go to the feints. The distiller is briefed that most sessions contain nothing durable. Zero proposals is a healthy run, not a failed one.
- Hooks are the apparatus; judgment is the cut. Extraction, gating, dedup bookkeeping, and queue management are deterministic shell and Python. A model is consulted exactly twice: once to draw off proposals, once — with you present — to review them.
- Dialogue over tools. Tool traffic is the bulk of a transcript and the least durable part. The still charges only with what you and the agent said to each other; corrections live there.
- Old casks get re-gauged. The distiller sees your existing memory index, so a
proposal that contradicts a stored fact is marked
Supersedes:and the stale entry is updated or deleted at review time instead of aging alongside its replacement.
| Category | Captures |
|---|---|
CORRECTION |
The human corrected the agent — the rule and the why |
FALSE-ASSUMPTION |
A belief the agent acted on that proved wrong, plus the verified truth |
DECISION |
A settled decision, its why, and the alternatives rejected |
WORKFLOW |
A repeatable multi-step procedure worth turning into a skill |
Each proposal names its cask: feedback memory, project memory, CLAUDE.md/AGENTS.md,
a decision log, or a skill.
Claude Code — the repo is its own marketplace:
/plugin marketplace add simiancreative/stillman
/plugin install stillman@stillman
Codex — Codex reads the same .claude-plugin/marketplace.json:
codex plugin marketplace add simiancreative/stillman
then install stillman from /plugins. Codex gates plugin hooks behind a one-time
trust review — approve them via /hooks on first run. If your org disables hooks
([features] hooks = false), the still won't run automatically, but the
$stillman-review skill still works on any pending queue.
| Claude Code | Codex | |
|---|---|---|
| Still fires on | SessionEnd, async, up to 600s |
SessionEnd (3s hard cap) fires a detached trampoline; also fires after 30 min idle — a dedup log keeps each session distilled once |
| The wash | project JSONL (~/.claude/projects/…) |
rollout JSONL (~/.codex/sessions/…, .zst handled) |
| Spirit safe | <project data dir>/distill/pending/ |
<plugin data dir>/<cwd-slug>/pending/ |
| Distiller engine | claude -p (default claude-sonnet-5) |
codex exec --ephemeral (default gpt-5.6-luna) |
| Surfacing | SessionStart → additionalContext |
same — the formats converged |
| Making the cut | /stillman-review skill or just ask |
$stillman-review skill or just ask |
Both transcript formats are parsed by one extractor (lib/extract_dialogue.py) that
auto-detects the shape per line.
What each platform reads from the repo:
stillman/
├── .claude-plugin/
│ ├── plugin.json # Claude manifest → hooks/claude.json
│ └── marketplace.json # catalog — read by BOTH marketplaces
├── .codex-plugin/
│ └── plugin.json # Codex overlay → hooks/codex.json
├── hooks/
│ ├── claude.json # SessionEnd async 600s + SessionStart
│ ├── codex.json # SessionEnd trampoline (3s cap) + SessionStart
│ ├── distill-session.sh # the still — shared by both
│ ├── distill-detach.sh # Codex-only: detach and return in <1s
│ └── surface-distillations.sh # shared SessionStart announcer
├── lib/
│ └── extract_dialogue.py # one parser, both transcript formats
└── skills/
└── stillman-review/ # SKILL.md — agentskills.io format, shared
The still itself is deterministic gating around a single model call:
on(SessionEnd)
if session already distilled # Codex refires on idle/archive
return
extract USER/ASSISTANT dialogue # tool traffic to the feints
if fewer than 6 real user messages
return # thin wash, not worth a run
mark session distilled
ask model: dialogue + memory index → proposals
if proposals
write pending/<date>-<session>.md # into the safe, never the cask
Start a session in a project with proposals in the safe and the agent announces them.
Say "review the distillations" (or invoke the stillman-review skill) and it will:
- Read each pending file and present its proposals for approval.
- Cask approved proposals in the store each one names, updating the memory index.
- Honor
Supersedes:lines by updating or deleting the memory they name. - Delete the proposal file — kept or feinted, the safe empties.
Environment variables, all optional:
| Variable | Default | Meaning |
|---|---|---|
STILLMAN_ENGINE |
auto-detected | claude or codex — which CLI drafts the proposals |
STILLMAN_MODEL |
per engine (see table above) | Model passed to the distiller CLI |
STILLMAN_MIN_USER_MESSAGES |
6 |
Sessions with fewer real user messages are skipped as a thin wash |
STILLMAN_MAX_DIALOGUE_BYTES |
160000 |
Dialogue budget; the tail is kept, since late dialogue carries the corrections that stuck |
STILLMAN_DATA_DIR |
plugin data dir, else ~/.codex/stillman |
Where Codex-side pending queues live |
Prefer plain hooks over a plugin? Copy the repo anywhere and wire hooks/claude.json
(or hooks/codex.json) content into your settings.json / ~/.codex/hooks.json,
pointing at the scripts on disk.
- Claude Code and/or Codex CLI on
PATH jqandpython3(zstdif your Codex rollouts are compressed)
MIT © Simian Creative
