Skip to content

feat: the orchestrator (beta, opt-in): catch-up report and a promoted tab (core 0.42.0) - #244

Merged
Maxaubert merged 6 commits into
mainfrom
feat/catch-up-report
Oct 17, 2026
Merged

Maxaubert merged 6 commits into
mainfrom
feat/catch-up-report

Conversation

@Maxaubert

@Maxaubert Maxaubert commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

Owner, 2026-10-16 (Sonara#285, #179): "say I have seven Claude sessions and they all are working, then I go to school, come back and I just want to get a report of what's been done and what I need to do next", based on "whether or not I've seen the session"; a tab left in front while away must not count as read. Then: others who download it should get it "if they want ... if they don't want it, it's like already in there", an orchestrator tab "promoted in the tab bar ... first in the list and there's a divider line", and "if you right click and choose make orchestrator it already knows".

Spec and plan: docs/superpowers/specs/2026-10-16-catch-up-report.md (reviewed before building: 25 findings folded in; the opt-in rework is its own section).

What the owner gets (Settings > Agents > Orchestrator (beta), OFF by default)

  • In any tab opened with it on: /prism-terminal-orchestrator:catch-up ("catch me up"): per session done / still working / needs you, then "do next". Asked twice, nothing repeats.
  • Right-click a tab > Make orchestrator: it moves first, with an accent outline and an accent rule after it (strip) or under it (sidebar), and from its next prompt Claude knows it is the orchestrator ("fix the bug in Wind" finds the Wind tab; it asks when unsure). Kept across restarts.
  • Sending into any tab (owner: "it needs to be able to send it to any session, not just whichever is in focus. That is very important."): the orchestrator's send.ps1 asks the app, which types the message into that tab's Claude prompt and presses Enter, in front or not. Only from the promoted tab; never into a bare shell (it would run); never while that tab asks a question (it would answer it). An owner exception to rule 2, recorded in docs/regression-rules.md and CLAUDE.md.

Core (Prism gets it too; nothing changes there until its host passes the orchestrator folder)

  • The status plugin's turn hooks add session=<id> (hook.cmd, delayed expansion, only a UUID-shaped value; hostile values tested). Parser carries only a lower-case UUID.
  • core/claude-plugin-orchestrator: the catch-up skill + Windows PowerShell 5.1 script (byte cursors, 120 s grace for late lines, owner prompts by origin.kind, turn answers, PRs, commits, open questions; -List, -Only), the orchestrator skill, and role.cmd (UserPromptSubmit additionalContext only in the promoted tab; MEASURED that it reaches the model).
  • orchestratorOn switch; spawn/prewarm take { status, orchestrator } (a boolean still works); orchestratorPluginDir for registerTermIpc; setSessionsFile + PRISM_SESSIONS_FILE, an inherited one always dropped.

App

  • sessionLedger.ts (pure): sessions kept apart from tabs; seen = 10 s in front while present (focused, shown, not locked or asleep, input within 120 s) or typed into, capped at last input + 10 s, restarted after any time away.
  • sessionsWire.ts: idle until switched on; writes sessions.json (no content) and orchestrator-tab.txt; flushed with the tabs in close, session-end and will-quit (rule 7). PRIVACY.md says what it holds.
  • The tab model (setOrchestrator, kept first through drags, saved in tabs.json), the menu entry, the strip and sidebar looks (impeccable; detector: only the sidebar's existing width transition), the Settings row.

Measured: a real Claude Code 2.1.301 turn printed state=done;session=<id> and that transcript exists; the digest on this PC's 7 largest sessions of the day (722 MB): 6.3 s, 60k characters; after commit, 0.8 s and empty.

Security review fixes: Windows process check before typing (a tab that only CLAIMS to be Claude is refused, e2e), sends addressed by tab id, decided again right before typing and before Enter.

Tests: unit 2271 pass (incl. orchestratorSend 7) (ledger 14, script 8, orchestrator plugin 2, hook/parser, env, tabs, store), typecheck clean, lint 0 errors. e2e catchUp 24/24 (sending into the tab not in front, and a refusal; off by default; on: a new tab's env and plugin, the link, a parked window stamps nothing, Make orchestrator moves first with outline and rule, the role file, off again clears it). Full e2e (last, after the security fixes): every scenario passed; the real-clipboard guard counted 10 changes during the run (5 the run before), which began only while the owner had another session working; the run before the fixes was untouched. Cause not established. Screenshot: .e2e-shots/orchestrator-strip.png.

The outline colour choice is #245.

Core 0.41.6 -> 0.42.0, app 0.55.6 -> 0.56.0.

🤖 Generated with Claude Code

https://claude.ai/code/session_017XYVRPzvhLpPCr75uB6uaA

Maxaubert and others added 3 commits October 16, 2026 13:43
…ve not seen (core 0.42.0)

Owner, 2026-10-16: a report of what the Claude sessions did while away and
what needs them next, based on whether they have SEEN each session, with a
tab left in front while away not counted as seen. Spec and plan:
docs/superpowers/specs/2026-10-16-catch-up-report.md (reviewed before
building; 25 findings folded in).

Core: the turn's own hooks (UserPromptSubmit, Stop) add session=<id>
(hook.cmd reads CLAUDE_CODE_SESSION_ID with delayed expansion, only a
UUID-shaped value); the parser carries it; setSessionsFile + an always
replaced PRISM_SESSIONS_FILE in ptyEnv; the plugin's catch-up skill and its
Windows PowerShell 5.1 script.

App: sessionLedger (pure): sessions kept apart from tabs; seen = in front
10 s while present (focused, shown, not locked or asleep, input within
120 s) or typed into, capped at last input + 10 s, restarted after any time
away. sessionsWire writes sessions.json, flushed with the tabs in close,
session-end and will-quit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XYVRPzvhLpPCr75uB6uaA
The digest quotes other sessions (and whatever web pages or files they
read), so a blanket powershell grant would let injected text run any
command without a prompt. The two script calls now ask like any other.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XYVRPzvhLpPCr75uB6uaA
…role

Owner, 2026-10-16: others who download the terminal should be able to
use it "if they want ... if they don't want it, it's like already in
there"; an orchestrator tab "promoted in the tab bar ... first in the list
and there's a divider line"; "right click and choose make orchestrator it
already knows".

- Settings > Agents > Orchestrator (beta), off by default. Off: no session
  list, no file, no PRISM_SESSIONS_FILE, no plugin, no menu entry.
- core/claude-plugin-orchestrator: a second Claude plugin given to new
  tabs only when it is on, with the catch-up and orchestrator skills and
  role.cmd, which adds a fixed additionalContext in the promoted tab only
  (MEASURED: a plugin hook's additionalContext reaches the model).
- Make orchestrator in a tab's menu: one tab, kept first, an accent
  outline and rule; saved in tabs.json; orchestrator-tab.txt names its
  PRISM_TAB_ID for the role hook.
- The script gains -List and -Only for the orchestrator.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XYVRPzvhLpPCr75uB6uaA
@Maxaubert Maxaubert changed the title feat: catch-up report: which session is in which tab, and what you have not seen (core 0.42.0) feat: the orchestrator (beta, opt-in): catch-up report and a promoted tab (core 0.42.0) Oct 16, 2026
Maxaubert and others added 3 commits October 16, 2026 15:00
Owner, 2026-10-16: "the terminal needs to be able to send it, and it needs
to be able to send it to any session, not just whichever is in focus.
That is very important." An owner exception to rule 2, recorded in
regression-rules.md and CLAUDE.md.

- orchestratorSend.ts (pure): only from the promoted tab, into the tab
  named by label, a word of its label or folder, its session or its
  PRISM_TAB_ID; never into a bare shell (it would run), never while that
  tab asks a question (it would answer it); one sanitised bracketed paste,
  then Enter after 300 ms (MEASURED on Claude Code 2.1.301: one prompt,
  multi-line kept).
- The orchestrator's send.ps1 drops a request in the app's outbox and
  waits for its answer: SENT to <label>, or NOT SENT: <why>.
- An agent arriving in a tab is now news to the ledger (the e2e caught the
  list lagging).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XYVRPzvhLpPCr75uB6uaA
Security review of the sends: a tab's Claude mark rests on in-band
signals any program in the tab can print (or a stale one), so it was
enough to make the app type into a shell. Now, at the moment of typing,
agentUnder (core/main/agentPoll.ts) asks the process tree itself; no
Claude under that tab's shell, no send. The e2e proves both: a shell that
only claims to be Claude is refused, a stand-in claude.exe in the tree
gets the message.

A name now resolves to a tab's own ids first, then an exact label, a word
only when nothing else matched and only when it names one tab; -List
prints each tab's id and the skill sends by it.

The process-spawning unit tests get 60 s: 5.8 s on a busy PC failed the
5 s default in a full run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XYVRPzvhLpPCr75uB6uaA
Security review: the process-tree check takes about a second, in which
the switch, the tab or its state can change. The send is decided again,
synchronously, right before the paste (the same tab and session must
win), and once more before the Enter: a question that opened in between
would take it as its answer, so the text then waits unsent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XYVRPzvhLpPCr75uB6uaA
@Maxaubert
Maxaubert merged commit 26a2111 into main Oct 17, 2026
2 checks passed
@Maxaubert
Maxaubert deleted the feat/catch-up-report branch October 17, 2026 09:22
github-actions Bot pushed a commit that referenced this pull request Oct 17, 2026
… tab (core 0.42.0) (#244)

* feat: catch-up report: which session is in which tab, and what you have not seen (core 0.42.0)

Owner, 2026-10-16: a report of what the Claude sessions did while away and
what needs them next, based on whether they have SEEN each session, with a
tab left in front while away not counted as seen. Spec and plan:
docs/superpowers/specs/2026-10-16-catch-up-report.md (reviewed before
building; 25 findings folded in).

Core: the turn's own hooks (UserPromptSubmit, Stop) add session=<id>
(hook.cmd reads CLAUDE_CODE_SESSION_ID with delayed expansion, only a
UUID-shaped value); the parser carries it; setSessionsFile + an always
replaced PRISM_SESSIONS_FILE in ptyEnv; the plugin's catch-up skill and its
Windows PowerShell 5.1 script.

App: sessionLedger (pure): sessions kept apart from tabs; seen = in front
10 s while present (focused, shown, not locked or asleep, input within
120 s) or typed into, capped at last input + 10 s, restarted after any time
away. sessionsWire writes sessions.json, flushed with the tabs in close,
session-end and will-quit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XYVRPzvhLpPCr75uB6uaA

* fix(catch-up): no tool allowlist in the skill

The digest quotes other sessions (and whatever web pages or files they
read), so a blanket powershell grant would let injected text run any
command without a prompt. The two script calls now ask like any other.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XYVRPzvhLpPCr75uB6uaA

* feat: the orchestrator is opt-in, with a promoted tab that knows its role

Owner, 2026-10-16: others who download the terminal should be able to
use it "if they want ... if they don't want it, it's like already in
there"; an orchestrator tab "promoted in the tab bar ... first in the list
and there's a divider line"; "right click and choose make orchestrator it
already knows".

- Settings > Agents > Orchestrator (beta), off by default. Off: no session
  list, no file, no PRISM_SESSIONS_FILE, no plugin, no menu entry.
- core/claude-plugin-orchestrator: a second Claude plugin given to new
  tabs only when it is on, with the catch-up and orchestrator skills and
  role.cmd, which adds a fixed additionalContext in the promoted tab only
  (MEASURED: a plugin hook's additionalContext reaches the model).
- Make orchestrator in a tab's menu: one tab, kept first, an accent
  outline and rule; saved in tabs.json; orchestrator-tab.txt names its
  PRISM_TAB_ID for the role hook.
- The script gains -List and -Only for the orchestrator.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XYVRPzvhLpPCr75uB6uaA

* feat: the orchestrator sends a message into any tab's Claude

Owner, 2026-10-16: "the terminal needs to be able to send it, and it needs
to be able to send it to any session, not just whichever is in focus.
That is very important." An owner exception to rule 2, recorded in
regression-rules.md and CLAUDE.md.

- orchestratorSend.ts (pure): only from the promoted tab, into the tab
  named by label, a word of its label or folder, its session or its
  PRISM_TAB_ID; never into a bare shell (it would run), never while that
  tab asks a question (it would answer it); one sanitised bracketed paste,
  then Enter after 300 ms (MEASURED on Claude Code 2.1.301: one prompt,
  multi-line kept).
- The orchestrator's send.ps1 drops a request in the app's outbox and
  waits for its answer: SENT to <label>, or NOT SENT: <why>.
- An agent arriving in a tab is now news to the ledger (the e2e caught the
  list lagging).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XYVRPzvhLpPCr75uB6uaA

* fix(orchestrator): ask Windows before typing into a tab; send by tab id

Security review of the sends: a tab's Claude mark rests on in-band
signals any program in the tab can print (or a stale one), so it was
enough to make the app type into a shell. Now, at the moment of typing,
agentUnder (core/main/agentPoll.ts) asks the process tree itself; no
Claude under that tab's shell, no send. The e2e proves both: a shell that
only claims to be Claude is refused, a stand-in claude.exe in the tree
gets the message.

A name now resolves to a tab's own ids first, then an exact label, a word
only when nothing else matched and only when it names one tab; -List
prints each tab's id and the skill sends by it.

The process-spawning unit tests get 60 s: 5.8 s on a busy PC failed the
5 s default in a full run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XYVRPzvhLpPCr75uB6uaA

* fix(orchestrator): decide again right before typing, and before Enter

Security review: the process-tree check takes about a second, in which
the switch, the tab or its state can change. The send is decided again,
synchronously, right before the paste (the same tab and session must
win), and once more before the Enter: a question that opened in between
would take it as its answer, so the text then waits unsent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XYVRPzvhLpPCr75uB6uaA

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant