Multi-Session Etiquette
Multiple AI sessions (Claude Code windows, other MCP clients) often work on
the same TouchDesigner project at once -- same live network, same
externalized files, same git tree. Envoy coordinates them; this rule is how
you cooperate.
At session start
Call get_sessions once early. It lists every connected session (label,
idle time, recent_scopes it modified, claims it holds, you = your own
session id). If peers are active, prefer working in a subtree none of them
touched recently.
Read the advisories -- they come to you
- Any tool response may carry
_peers: another session touched territory
overlapping your request (op path or externalized file) within ~10 min.
conflict: false -- informational. Note it, re-read files before editing
them, and avoid building on top of a peer's in-flight work.
conflict: true (a peer WROTE there within the last minute) is a HARD
STOP. Do not keep mutating that scope. Check get_sessions, tell the
user who is working there, and either divide the work (different
subtrees) or get explicit user direction before proceeding.
- A
CONFLICT WARNING or MULTI-SESSION GATE line in _logs follows the
same contract as a LAYOUT WARNING: never end a turn without addressing it.
Claim before big or destructive work
- Before a large build, a refactor of a COMP subtree, or editing an
externalized file, call
claim_scope with the NARROWEST scope that
covers the work and a short note ("rebuilding camera rig"): an op-path
prefix (/project1/scene), a file (file:scripts/tools.py), or a
special scope (project:tests before a test run).
- Your own tool calls touching the scope renew the lease automatically; it
expires on its TTL or when your session goes silent.
release_scope when
done is polite but never required for others to make progress.
- If a claim is refused, the response names the holder, their note, and the
expiry. Coordinate or work elsewhere -- do NOT retry in a loop.
The task ledger -- state, not just presence
Claims say who is touching what right now; the ledger (.embody/tasks.json,
via announce_task / update_task) says what state the WORK is in. It
exists because a dirty tree plus recency signals cannot distinguish
in-flight work from FINISHED work awaiting a commit -- and misreading that
costs real coordination time.
- Starting substantive work (a feature, fix, refactor -- not single-tool
edits):
announce_task with a short title and the scopes it will touch.
Worktree tasks announce IN ADDITION to their durable worktree claim.
- Finishing: flip to
done_uncommitted the moment the work is complete
but sitting uncommitted in the tree. This is the load-bearing state -- it
is what stops a peer from reading your finished feature as in-flight work,
and preflight_landing reports ledger tasks overlapping a landing.
- Committing:
update_task(task_id, commit='<sha>') -- a sha alone
implies the committed transition.
- Reading:
get_sessions carries every session's active entries; check
them at session start and before working in files another task names.
- Hygiene: any session may mark a dead session's stale task
abandoned
(the ledger records updated_by for non-owner writes).
Destructive operations are gated
delete_op, import_network with clear_first=True, run_tests, and
batches containing them are REFUSED while a live peer holds a claim on
the scope or wrote it within the last minute.
override=True exists for when you are CERTAIN -- e.g. the "peer" is the
same user's stale session, or the user explicitly told you to proceed.
Never override silently: state in your reply that you overrode and why.
Raw file edits are invisible to Envoy
- Envoy only sees MCP traffic. Editing an externalized file with your own
file tools (Edit/Write) leaves no touch record -- so before editing one,
check
get_sessions (does a peer claim it or list it in
recent_scopes?) and claim it yourself (file:<repo-relative-path>)
for the duration.
- Re-read a file before editing whenever a peer's
recent_scopes mentions
it: your cached copy may be stale.
Worktrees are scoped territory too
Isolated-worktree work (../<repo>-wt-<task>, see
rules/worktree-td-safety.md) is doubly invisible: the edits are raw file
edits AND they happen outside the repo Envoy watches. Peers cannot see any
of it until the diff lands. So coordinate by intent, not by touch records:
- On starting a worktree task: claim
project:worktree-<task> (e.g.
project:worktree-watchdog) with a note naming the files/subsystem the
diff will land on. This is how peers learn a worktree task is in flight. Worktree
claims are DURABLE -- they survive session death and Envoy restarts,
expiring only when the worktree directory is removed (7-day
backstop); get_sessions lists them under worktrees.
- Before landing the diff: claim
file:<repo-relative-path> for each
externalized file the diff touches (or the narrowest shared parent
scope). If a peer holds one, reconcile first -- landing over a peer's
in-flight edit is the worktree version of a blind overwrite.
Run preflight_landing(worktree_path) FIRST -- it intersects the
landing's files with main-tree dirt, peer file territory, and
unsaved live TDXN state in one call; a conflicts verdict means
reconcile before any file moves.
- Two sessions must never share one worktree -- one writer per
checkout, always. A second session starts its own
../<repo>-wt-<other-task>.
- Access is pre-authorized: Envoy's generated settings allow Read/Edit in
sibling
<repo>-wt-* folders, so worktree work never needs permission
prompts (keep the -wt- naming for this to apply).
Division of labor
The cheapest coordination is spatial: agree (via the user) on separate COMP
subtrees or file areas per session. Claims make that agreement visible and
enforceable.
1---2name: multi-session-etiquette3description: MUST READ when a _peers advisory appears or multiple AI sessions are active in the same TouchDesigner project: advisory contract, claim leases, destructive gates, raw-file-edit visibility, division of labor.4---5<!-- Generated by Embody/Envoy - Do not remove this comment -->67# Multi-Session Etiquette8910Multiple AI sessions (Claude Code windows, other MCP clients) often work on11the same TouchDesigner project at once -- same live network, same12externalized files, same git tree. Envoy coordinates them; this rule is how13you cooperate.1415## At session start1617Call `get_sessions` once early. It lists every connected session (label,18idle time, `recent_scopes` it modified, `claims` it holds, `you` = your own19session id). If peers are active, prefer working in a subtree none of them20touched recently.2122## Read the advisories -- they come to you2324- Any tool response may carry `_peers`: another session touched territory25 overlapping your request (op path or externalized file) within ~10 min.26- `conflict: false` -- informational. Note it, re-read files before editing27 them, and avoid building on top of a peer's in-flight work.28- **`conflict: true` (a peer WROTE there within the last minute) is a HARD29 STOP.** Do not keep mutating that scope. Check `get_sessions`, tell the30 user who is working there, and either divide the work (different31 subtrees) or get explicit user direction before proceeding.32- A `CONFLICT WARNING` or `MULTI-SESSION GATE` line in `_logs` follows the33 same contract as a LAYOUT WARNING: never end a turn without addressing it.3435## Claim before big or destructive work3637- Before a large build, a refactor of a COMP subtree, or editing an38 externalized file, call `claim_scope` with the NARROWEST scope that39 covers the work and a short note ("rebuilding camera rig"): an op-path40 prefix (`/project1/scene`), a file (`file:scripts/tools.py`), or a41 special scope (`project:tests` before a test run).42- Your own tool calls touching the scope renew the lease automatically; it43 expires on its TTL or when your session goes silent. `release_scope` when44 done is polite but never required for others to make progress.45- If a claim is refused, the response names the holder, their note, and the46 expiry. Coordinate or work elsewhere -- do NOT retry in a loop.4748## The task ledger -- state, not just presence4950Claims say who is touching what right now; the ledger (`.embody/tasks.json`,51via `announce_task` / `update_task`) says what state the WORK is in. It52exists because a dirty tree plus recency signals cannot distinguish53in-flight work from FINISHED work awaiting a commit -- and misreading that54costs real coordination time.5556- **Starting substantive work** (a feature, fix, refactor -- not single-tool57 edits): `announce_task` with a short title and the scopes it will touch.58 Worktree tasks announce IN ADDITION to their durable worktree claim.59- **Finishing**: flip to `done_uncommitted` the moment the work is complete60 but sitting uncommitted in the tree. This is the load-bearing state -- it61 is what stops a peer from reading your finished feature as in-flight work,62 and `preflight_landing` reports ledger tasks overlapping a landing.63- **Committing**: `update_task(task_id, commit='<sha>')` -- a sha alone64 implies the committed transition.65- **Reading**: `get_sessions` carries every session's active entries; check66 them at session start and before working in files another task names.67- **Hygiene**: any session may mark a dead session's stale task `abandoned`68 (the ledger records `updated_by` for non-owner writes).6970## Destructive operations are gated7172- `delete_op`, `import_network` with `clear_first=True`, `run_tests`, and73 batches containing them are REFUSED while a live peer holds a claim on74 the scope or wrote it within the last minute.75- `override=True` exists for when you are CERTAIN -- e.g. the "peer" is the76 same user's stale session, or the user explicitly told you to proceed.77 Never override silently: state in your reply that you overrode and why.7879## Raw file edits are invisible to Envoy8081- Envoy only sees MCP traffic. Editing an externalized file with your own82 file tools (Edit/Write) leaves no touch record -- so before editing one,83 check `get_sessions` (does a peer claim it or list it in84 `recent_scopes`?) and claim it yourself (`file:<repo-relative-path>`)85 for the duration.86- Re-read a file before editing whenever a peer's `recent_scopes` mentions87 it: your cached copy may be stale.8889## Worktrees are scoped territory too9091Isolated-worktree work (`../<repo>-wt-<task>`, see92`rules/worktree-td-safety.md`) is doubly invisible: the edits are raw file93edits AND they happen outside the repo Envoy watches. Peers cannot see any94of it until the diff lands. So coordinate by intent, not by touch records:9596- **On starting a worktree task**: claim `project:worktree-<task>` (e.g.97 `project:worktree-watchdog`) with a note naming the files/subsystem the98 diff will land on. This is how peers learn a worktree task is in flight. Worktree99 claims are DURABLE -- they survive session death and Envoy restarts,100 expiring only when the worktree directory is removed (7-day101 backstop); `get_sessions` lists them under `worktrees`.102- **Before landing the diff**: claim `file:<repo-relative-path>` for each103 externalized file the diff touches (or the narrowest shared parent104 scope). If a peer holds one, reconcile first -- landing over a peer's105 in-flight edit is the worktree version of a blind overwrite.106 Run `preflight_landing(worktree_path)` FIRST -- it intersects the107 landing's files with main-tree dirt, peer file territory, and108 unsaved live TDXN state in one call; a `conflicts` verdict means109 reconcile before any file moves.110- **Two sessions must never share one worktree** -- one writer per111 checkout, always. A second session starts its own112 `../<repo>-wt-<other-task>`.113- Access is pre-authorized: Envoy's generated settings allow Read/Edit in114 sibling `<repo>-wt-*` folders, so worktree work never needs permission115 prompts (keep the `-wt-` naming for this to apply).116117## Division of labor118119The cheapest coordination is spatial: agree (via the user) on separate COMP120subtrees or file areas per session. Claims make that agreement visible and121enforceable.