Skip to content

Draft: full-screen shared agent session view (multi-person, live tool streaming)#3050

Draft
rkhettry wants to merge 2 commits into
block:mainfrom
rkhettry:feat/desktop-harness-mode
Draft

Draft: full-screen shared agent session view (multi-person, live tool streaming)#3050
rkhettry wants to merge 2 commits into
block:mainfrom
rkhettry:feat/desktop-harness-mode

Conversation

@rkhettry

Copy link
Copy Markdown

Draft — not asking for a merge. I built this to see whether the idea held up, and I'd like thoughts before I invest in splitting it properly. Happy to hear "no thanks" or "yes but differently."

What this is

A full-screen view for watching and driving an agent session, opened from a thread. It renders the same transcript the agent session panel already produces, but with the whole window, a participant roster, the thread's history, and a composer — so several people can watch one agent work and talk to it in one place.

I've written up the reasoning in the linked issue. This PR is the code behind it.

Why

Keep engineers where they want to work. In my experience people would rather stay in the agent/terminal view than drive an agent from a chat thread — more control, more visibility, more comfortable. But then your team loses sight of what you're doing. This tries to get both: work in the agent view, and have that view be something teammates can join.

Show the work, not just the output. The current panel shows the transcript, but there's no persistent "what is it doing right now." Mid-turn it can read as hung. I added a live status line — elapsed, tokens, running shell commands, tool progress — all derived from data the observer stream already carries (usage_update, tool item startedAt/completedAt), so nothing is estimated.

What's here

  • Full-screen view opened from a thread; URL-addressable so it survives reload and can be shared
  • Left rail: participants with presence, plus the thread's message history (resizable)
  • Live status rendered inline with the existing turn-liveness indicator
  • Composer that auto-p-tags the agent, so you don't re-@mention every message
  • Per-author colour on prompts, derived from pubkey — stable across clients, no shared state
  • Per-thread scoping: turns are attributed via the messageId on user rows, so two threads in one channel stay independent

Unit tests cover the derivations (turn scoping, transcript merge, status parsing). just ci passes apart from the file-size guard below.

⚠️ Known issue: the file-size guard fails

pnpm check:file-sizes fails on three files. All three are at their caps on main before I touch them:

File on main here limit
ChannelPane.tsx 999 1031 1000
AgentSessionTranscriptList.tsx 996 1010 1000
ChannelScreen.tsx 978 985 979

ChannelScreen has one line of headroom. I already extracted the bulk of the wiring into useChannelHarness (ChannelPane 1132 → 1031), but the remaining ~30 lines are the integration points themselves.

I didn't want to start restructuring upstream files in a first contribution, so I'm asking instead: where would you want this mounted? Options I can see are splitting those files, mounting the overlay higher up, or a scoped exception. Happy to do whichever you prefer.

If you want it, here's how I'd ship it

  1. Put the full-screen view behind preview-features.json, the way Workflows / Projects / Pulse / Forum Channels shipped hidden first
  2. Split out the small independently-useful bits as their own PRs — tool-call groups rendering expanded, and an in-channel entry point for agent activity when the agent isn't mid-turn (the composer pill only renders while composerWorkingBotPubkeys.length > 0)
  3. Land the full view last, flagged

Naming

I've been calling it "harness mode," which collides with how Buzz uses "harness" for the ACP runtime (goose / claude-agent-acp / codex-acp). Happy to rename.

Also found while building

The transcript only renders a steered mid-turn message when a goose-native _goose/unstable/session/steer frame is written. With claude-agent-acp that never happens — the steer falls back to cancel+merge (ExpectedRunIdMissing in the agent log), so the message is folded into a merged re-prompt and never gets its own row. It gets answered, but you can't see what was asked. Can file separately if that's useful.

Environment

macOS, built from source with just dev. Agent: @agentclientprotocol/claude-agent-acp 0.62.0.

rkhettry added 2 commits July 26, 2026 18:55
**Category:** feature
**User Impact:** Opening a thread's agent surface now shows a full-window
harness view with a live status strip, per-author colour coding, and a
composer, so a turn in progress is visible while it runs instead of
appearing to hang until the agent posts its reply.

**Problem:** The agent session transcript rendered as a side panel with no
turn-level status. A long turn produced no visible signal between the
triggering message and the final reply, and a session shared by several
people gave no way to tell who prompted what.

**Solution:** A HarnessModeScreen presentation component plus a
HarnessModeView container wiring it to the existing observer transcript,
channel members, and presence. Supporting pure modules carry the logic and
are unit-tested independently of React:

- harnessStatus.ts - derives running commands, tool progress, token and
  cost counters, and a summary line from observer frames already on the
  stream. Nothing estimated.
- threadTurnScope.ts - scopes a transcript to one thread's turns by
  excluding only provably foreign turns, so the in-flight turn stays
  visible even when its prompt row does not exist yet.
- threadHarnessTarget.ts - resolves which known channel agent a thread's
  harness affordance opens, from p-tag mentions plus authorship.
- authorAccent.ts - deterministic per-author hue from the pubkey, so the
  same person is the same colour in every client with no shared state.

Channel panel history state gains a harness entry so the view is routable
and back-navigable.

## Testing
- just desktop-test - 3562 pass, 0 fail
- pnpm typecheck - clean
- biome check - clean

## Known gap (blocks merge)
pnpm check:file-sizes fails and this commit used --no-verify to checkpoint
the work. Extraction is pending; per the script header these must be split,
not added to the override map:
- ChannelPane.tsx 1132 (limit 1000)
- AgentSessionTranscriptList.tsx 1010 (limit 1000)
- ChannelScreen.tsx 985 (its ratcheted limit is 979)

## Related issue
none found

Signed-off-by: Raj Khettry <raj.khettry@gmail.com>
Keeps ChannelPane closer to the desktop file-size guard by moving the
harness derivations, handlers and overlay into their own hook.

ChannelPane: 1132 -> 1031 lines.

Note: three integration points (ChannelPane, ChannelScreen,
AgentSessionTranscriptList) sit at their file-size caps on main, so
wiring any feature through them trips the guard. Raised as an open
question on the PR rather than restructuring upstream files here.

Signed-off-by: Raj Khettry <raj.khettry@gmail.com>
@rkhettry

Copy link
Copy Markdown
Author

Context and reasoning for this PR: #3051

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