Coordination protocol for working alongside other concurrent Claude Code sessions through the shared Director log. Use whenever you make a decision, defer a follow-up, hit a blocker, reach a handoff boundary, or need to leave context for a parallel/future session — anything that another session "should know." Covers how and when to run `director emit` and `director resolve`, and how to treat the CHARTER + digest injected at session start.
Scanned 9/5/2026
Install to Claude Code
npx -y skills add colinsurprenant/director --skill director --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Director?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/colinsurprenant-director)More formats (shields.io, HTML) on the badges page.
---
name: director
description: >-
Coordination protocol for working alongside other concurrent Claude Code sessions through
the shared Director log. Use whenever you make a decision, defer a follow-up, hit a blocker,
reach a handoff boundary, or need to leave context for a parallel/future session — anything
that another session "should know." Covers how and when to run `director emit` and
`director resolve`, and how to treat the CHARTER + digest injected at session start.
---
# Director coordination protocol
You are one of many concurrent Claude Code sessions a single human runs across many repos. You
coordinate with the others through a shared, durable, append-only **LOG** — not by relaying
messages through the human. The `director` CLI is the **only** sanctioned writer of that log:
**never** use Edit/Write to record coordination state, and never hand-edit the log file.
Your transient working state (what you decided, what you deferred, where you are) survives a
compaction or a fresh start **only if you wrote it to the LOG during a turn.** No hook can flush
it for you. The habit below is the real guarantee against lost context — treat it as load-bearing.
## 1. Continuous boundary-flush (the load-bearing habit)
Emit durable state to the LOG **as you work** — do not batch it for the end of the session.
- The **moment** a decision is made or a follow-up is deferred, emit it. Right then, not later.
An item written immediately survives an unexpected compaction; an item you were "going to log
at the end" is exactly what gets lost.
- At each **natural boundary of work that will resume** (finishing a sub-task, switching focus,
pausing, wrapping up mid-workstream), emit a `handoff`: **current task · next action ·
hypotheses · dead ends**. This is the positional snapshot a fresh session (you, after
compaction, or a peer) reads to pick up where you left off.
Dead ends ride along ("tried X, failed because Y") — negative results are what stop the next
session from re-walking a path this one already burned.
- A deferred loop is its **own `open-item` event** — do **not** pack it into the handoff body.
The handoff carries *position*; open-items carry *carried-forward loops*. `brief`/`render`
join the two. Packing them together duplicates state, and duplication goes stale.
- A finished **self-contained task** (a PR review, a one-shot investigation) records its
**outcome as a `note`** — a handoff is only for work that *resumes*, and starting a task needs
no event at all. A task-lifecycle handoff on a shared workstream shadows the coordination
session's real resume point. (This is the finished-workstream rule, applied to finished tasks.)
Prefer **flush-often, then start fresh at a boundary** over riding a session up into the
degradation zone (a reliable degradation signal: the human giving you the same correction twice). Because you flush continuously, a fresh start is already covered — there is no
need to hand-compose a big handoff at the last second.
## 2. The four event kinds — when to use each
There are exactly four model-emitted kinds. Pick by what the fact *is*:
| Kind | Use it for | Example |
|---|---|---|
| `decision` | a choice + what it affects (carries `--risk low\|escalate`) | `director emit --type decision --area auth --risk low "Use ULID not UUID for event ids — sortable, matches log fold"` |
| `open-item` | an open loop / follow-up / deferred item — the canonical home for "documented, not dropped" | `director emit --type open-item --area render "Resolve cross-machine ULID tie-break before multi-machine sync"` |
| `handoff` | current task · next action · hypotheses · dead ends (positional snapshot at a boundary) | `director emit --type handoff --area store --refs <the resume point ULID(s) you rehydrated from> "Done: NDJSON append. Next: wire emit dispatch. Hypothesis: O_APPEND is line-atomic on POSIX. Dead end: fsync-per-line, 30x too slow"` |
| `note` | FYI / context for a parallel or future session; a finished task's outcome (a review verdict, an investigation result) | `director emit --type note --to @next-on-hooks --area hooks "settings.json merge is _managedBy-tagged — don't strip GSD entries"` |
Two **reserved ref meanings**, both load-bearing:
- A `note` whose `--refs` names a **handoff** CONCLUDES it — that handoff (and the workstream's
older ones) leaves the digest's resume points, staying in the log. `/director:complete` uses
this to retire a dead workstream's last resume point; never ref a handoff from a note otherwise.
- A `handoff` whose `--refs` names same-workstream **handoff(s)** SUPERSEDES exactly those
positions and nothing else (nothing older than them, nothing newer): retirement is set
membership, so a position no handoff ever named still stands. Ref the resume point(s) you
rehydrated from plus any handoff you emitted earlier this session, and a parallel session's
position on the same workstream survives instead of being silently overwritten. A handoff with
no such refs retires ALL older positions of the workstream, including one you never saw.
`/director:handoff` does this on every checkpoint.
Refs to decisions and open-items carry no such effect. When your injected state shows **several**
resume points for your workstream, that is two parallel sessions' positions stacked: read them
all, consolidate them into your next handoff body, and `--refs` each — that collapses the stack
back to one.
Routing rule: an **open loop you carry forward** → an `open-item` event (its one home).
**Durable structured knowledge** (intent, architecture, a decision's full rationale) → the living
docs (CHARTER, README, ADRs), with the `decision`/`open-item` body holding a short pointer, not
the full content.
### "Stuck, needs a human" — there is no `blocker` kind
When you are blocked and need the human, emit an **`open-item` with `--risk escalate`**:
```
director emit --type open-item --area deploy --risk escalate "Need prod DB creds to finish migration — cannot proceed"
```
The escalate-flagged open-set is exactly what surfaces in the cockpit's **Needs-you** band. Use
`--risk escalate` only for genuine needs-a-human items; a routine follow-up is plain `open-item`.
`done` is **not** a kind you emit — it is fleet-liveness only (a hook marks the session terminal).
"What's done" belongs in the `handoff` body when the work resumes, or in the task-outcome `note`
when it doesn't.
### emit returns the new event's ULID
`director emit` prints the new event's **ULID to stdout**. Note it — that is the id others (and
you) use to `--refs` or `resolve` it later. It also echoes a routing line to **stderr**
(`→ <repo-key> · <workstream-id>`) naming the project it wrote to; if that is not the project you
expect, your cwd drifted and the event landed in the wrong log.
## 3. Closing open-items — resolve discipline
When an open-item is handled, close it:
```
director resolve <ulid>
```
This appends a close-marker (an `open-item`-typed marker with `status: closed`). Critical:
- The `<ulid>` **must** be one the CLI surfaced to you — `emit` printed it when the item was
created; `render`, `status`, and `brief` list open-items with their ids. **Copy it.**
- **Never invent, guess, or reconstruct a ULID.** `resolve` validates the target and rejects
anything that isn't a real, currently-open `open-item` (invented ids, non-open-items, and
already-closed items are refused). If you don't have the exact id in front of you, run
`director status` (or `render`/`brief`) to surface it, then copy it.
### Promoting decisions — human-directed only
`director promote <ulid>... --to <doc>` folds aged-but-durable decision rationale into a
slow-layer doc: the promoted decisions leave the digest and a one-line doc pointer stays.
Promotion is a curation act; **the human decides what graduates** to the slow layer. Run it only
at the human's direction, after the rationale has actually been written into the target doc,
never on your own initiative. The same ULID discipline applies: copy CLI-surfaced ids —
`promote` rejects invented, non-decision, already-promoted, and superseded targets.
## 4. Treat injected state as authoritative (Ground Truth)
At session start (including after an autocompaction) Director injects the project **CHARTER** plus
a bounded **digest** of current state. That block is your **authoritative current picture.**
- **Build on it. Do not rebuild it.** Do not re-read the log, re-scan the repo, or re-derive
project state to "reconfirm" what you were just handed.
- Re-deriving burns the exact context budget the digest was sized to save — and accelerates the
next compaction. Perfect context that you ignore and rediscover is no better than no context.
- The digest is an **INDEX**: every line is a capped headline, not the full text. The sanctioned
deeper read is `director show <ulid>` — one event in full, one deterministic hop from any
headline. Before touching an area, pull the full bodies of its listed decisions rather than
guessing past a headline.
- Reach for the underlying log/docs only to go **deeper** than the digest on a specific question,
or when escalation requires a fresh authoritative read (a render can be stale — but that is a
targeted `show`/scan, not a wholesale re-derivation of what you already hold).
Take the injected CHARTER + digest as true, start from there, and add to the LOG as you go.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!