HomeDocsArchitecture › 10. End-to-End Flows

10. End-to-End Flows

This chapter ties the sub-projects together with cross-cutting sequence diagrams. Each flow shows how a real user action travels through the actor system, the NATS bus, the agentic engine, and (where relevant) the cloud server and external surfaces.


10.1 Local AI coding turn (with approval)

A developer types a prompt in an AI pane; the agent edits a file, which requires approval.

sequenceDiagram
    autonumber
    participant TUI
    participant WS as WorkspaceActor
    participant Pane as PaneActor
    participant M as LLMPromptExecutionActor
    participant O as OrchestratorActor
    participant Claude
    participant Tool as file_edit tool

    TUI->>WS: MsgSubmitInput ("@ refactor X") → ws.inbox
    WS->>Pane: MsgPaneSubmitInput → pane.{id}.inbox
    Pane->>M: MsgAgenticPrompt → llm_prompt_execution.inbox
    M->>M: append user turn, trim 50, sys+memory
    M->>O: spawn orchestrator
    O->>Claude: CompleteWithTools(conv, specs, sys)
    Claude-->>O: text + tool_use(file_edit)
    O-->>TUI: stream text (output.ai)
    O->>Tool: Execute (compute diff)
    O->>TUI: MsgApprovalRequest(diff) → approval.request
    TUI-->>O: MsgApprovalResponse(yes) → approval.response
    O->>Tool: apply edit
    Tool-->>O: ToolOutput (success)
    O->>Claude: CompleteWithTools(... tool result ...)
    Claude-->>O: text, end_turn
    O-->>TUI: stream final text
    O->>M: MsgOrchestratorDone(conversation)
    M->>M: merge + persist to KV

Concrete behavior: the approval request (step 9) is published to pane.{id}.approval.request; waitForApproval blocks up to 5 minutes before defaulting to No. The diff is computed by executing file_edit first (preview-then-confirm). On MsgOrchestratorDone, the manager replaces its conversation with the orchestrator's full version, trims to 50 turns, and persists to KV ({paneID}.llm_conversation) at most every 2s.


10.2 Cloud-driven browser control

A server-side agent, reachable via the Chrome extension, navigates and reads a page.

sequenceDiagram
    autonumber
    participant U as User (side panel)
    participant Ext as Extension (React)
    participant Proxy as browser_pane_proxy
    participant M as LLMPromptExecutionActor (server)
    participant O as OrchestratorActor
    participant Claude
    participant BA as browser_action tool
    participant Exec as Extension executor
    participant Page as Active tab

    U->>Ext: prompt + page context
    Ext->>Proxy: MsgAgenticPrompt (NATS over WS)
    Proxy->>M: rysh.pane.{id}.llm_prompt_execution.inbox
    M->>O: spawn
    O->>Claude: CompleteWithTools
    Claude-->>O: tool_use(browser_action: click)
    O->>BA: Execute
    BA->>Proxy: MsgBrowserActionRequest → browser.request
    Proxy->>Exec: (NATS over WS)
    Exec->>Page: chrome.scripting (resolve selector, click)
    Page-->>Exec: result
    Exec->>BA: MsgBrowserActionResponse → browser.response
    BA-->>O: ToolOutput
    O->>Claude: CompleteWithTools(... result ...)
    Claude-->>O: text, end_turn
    O-->>Ext: stream output (.llm_prompt_execution.output)

Note the subject-ACL is bypassed for this trusted path: browser_pane_proxy uses an explicit allow-list of pane subjects rather than the streaming ACL.


10.3 Website chatbot session (with operator takeover)

A visitor chats with an embedded widget; a human operator takes over mid-conversation.

sequenceDiagram
    autonumber
    participant V as Visitor (widget)
    participant CP as chatbot_pane_proxy
    participant CPS as ChatbotPaneService
    participant M as LLMPromptExecutionActor (PaneToolsNone)
    participant Claude
    participant Op as Operator (dashboard)

    V->>CP: chatbot.visitor_message {type,payload}
    CP->>CPS: rysh.pane.{id}.output.chat (echo) + LLM inbox
    CPS->>M: MsgAgenticPrompt
    M->>Claude: CompleteWithTools (no tools)
    Claude-->>M: text
    M->>CPS: output.chat (assistant)
    CPS->>CP: chatbot.message
    CP->>V: assistant reply
    Op->>CPS: POST /sessions/:id/takeover
    CPS->>CPS: suppress LLM
    Op->>CPS: POST /sessions/:id/reply
    CPS->>CP: chatbot.message (human)
    CP->>V: operator reply
    Op->>CPS: POST /sessions/:id/release
    CPS->>CPS: resume LLM

The widget never sees raw NATS subjects — chatbot_pane_proxy translates between the closed {type, payload} protocol and the internal pane subjects (chatbot.visitor_message ↔ LLM inbox; output.chatchatbot.message; status phase → chatbot.typing/typing_stop). The pane has zero tools (PaneToolsNone) because it runs on an untrusted third-party site. Transcript writes are batched (10 msgs / 500ms); idle sessions are reaped every 5 min past the configured timeout (default 30 min).


10.4 Humanoid answering a Slack thread

A teammate mentions the bot in Slack; a humanoid agent replies.

sequenceDiagram
    autonumber
    participant Slack
    participant SA as Slack adapter (CLI)
    participant H as HumanoidActor
    participant M as LLMPromptExecutionActor
    participant Claude

    Slack->>SA: AppMentionEvent (Socket Mode)
    SA->>H: MsgHumanoidInboundMessage (via inboundLoop)
    H->>H: build contextual prompt (thread history + memory)
    H->>M: MsgAgenticPrompt
    M->>Claude: CompleteWithTools
    Claude-->>M: text (end_turn)
    M->>H: stream output (external buffer)
    H->>SA: routeOutboundToChannel(reply)
    SA->>Slack: chat.postMessage (in-thread)

For email humanoids in human-governed mode, the agent drafts via email_draft, the human reviews, and email_send (which requires approval) sends — the agent never auto-sends.


10.5 Pane/tab sharing across machines

A developer shares a tab to a teammate, who mirrors it in control mode.

sequenceDiagram
    autonumber
    participant SrcCLI as Source CLI
    participant SR as ShareRegistryActor
    participant US as UpstreamShareActor
    participant Srv as rysh-server NATS
    participant SS as ShareService
    participant SubCLI as Subscriber CLI
    participant MTL as MirrorTabListenerActor

    SrcCLI->>SR: ##share tab (share.registry.inbox)
    SR->>US: spawn per share
    US->>Srv: register (ws.{wsID}.share.{id}.register)
    Srv->>SS: SetupNATSHandlers records SharedEntity
    US->>Srv: layout doc + output (600ms/150ms loop)
    SubCLI->>Srv: ##upstream subscribe {id} control
    Srv->>SS: subscriber event
    Srv->>SubCLI: replay state + live output
    SubCLI->>MTL: build synthetic mirror tab
    MTL->>MTL: reconstruct via own VTerm, reflow to width
    SubCLI->>Srv: control-mode op/input
    Srv->>US: command (.command) + ack (.command.ack)
    US->>SrcCLI: apply to local actors

The subject-ACL ensures both CLIs only touch ws.{workspaceID}.>. Stale shares are reaped after a 2-minute heartbeat gap.


10.6 Session attach / restore

sequenceDiagram
    autonumber
    participant User
    participant Main as main.go
    participant Sess as session store
    participant Daemon
    participant KV as JetStream KV

    User->>Main: rysh
    Main->>Sess: find live session?
    alt no daemon
        Main->>Daemon: spawn (rysh daemon ), goHeadless
        Daemon->>KV: actors restore tree in Started
    end
    Main->>Daemon: attach TUI (connect NATS client port)
    Daemon-->>Main: ws.snapshot (layout)
    Main->>Main: stream content, render
    User->>Main: Ctrl+? detach (SIGUSR1) — daemon keeps running

10.7 Voice prompt

sequenceDiagram
    participant U as User
    participant Ctl as voice.Controller
    participant Rec as Recorder (sox/ffmpeg)
    participant Tr as Transcriber (Deepgram/Whisper)
    participant TUI
    U->>Ctl: start (push-to-talk)
    Ctl->>Rec: record 16kHz mono WAV
    U->>Ctl: stop
    Ctl->>Tr: Transcribe(wav)
    Tr-->>Ctl: text
    Ctl->>TUI: fill prompt field
    Note over TUI: user reviews, then submits as a normal AI prompt (§10.1)