# OpenScout Full LLM Context Generated by `bun scripts/generate-agent-docs.mjs`. Current posture: OpenScout is for high-trust local developer pilots. It is not enterprise-ready, compliance-ready, a hardened multi-tenant runtime, or a guaranteed distributed delivery layer. License posture is not finalized; check package metadata and repo license files before making reuse claims. ## Included Files - `AGENTS.md` - `README.md` - `install.md` - `docs/README.md` - `docs/quickstart.md` - `docs/current-posture.md` - `docs/architecture.md` - `docs/scout-comms.md` - `docs/mcp-api-posture.md` - `docs/runtime-sessions.md` - `docs/data-ownership.md` - `docs/agent-integration-contract.md` - `docs/integrations.md` - `docs/agent-identity.md` - `docs/collaboration-workflows-v1.md` - `docs/operator-attention-and-unblock.md` - `docs/scout-agent-delegation.md` - `docs/agent/README.agent.md` - `docs/agent/current-posture.agent.md` - `docs/agent/scout-comms.agent.md` - `docs/agent/integration-contract.agent.md` --- ## AGENTS.md # Agent Instructions See [DEV_INSTRUCTIONS.md](./DEV_INSTRUCTIONS.md) for repository-wide development instructions. For fast project context, read [llms.txt](./llms.txt), then the dense agent notes in [docs/agent/README.agent.md](./docs/agent/README.agent.md). If you need a larger copy/paste context bundle, use [llms-full.txt](./llms-full.txt). Host-specific instruction files [CODEX.md](./CODEX.md) and [CLAUDE.md](./CLAUDE.md) are intentionally thin redirects. Keep shared guidance here or in `docs/agent`, not duplicated per host. ## Product Posture OpenScout is currently for high-trust local developer pilots, not enterprise-ready deployment. Do not claim compliance readiness, hardened multi-tenant security, guaranteed distributed delivery, or a finalized open-source license unless package and repo metadata have changed. ## Core Architecture Rules - The broker is the canonical writer for Scout-owned coordination records. - Scout-owned records include messages, invocations, flights, deliveries, bindings, agent registrations, questions, and work items created through Scout. - External harness transcripts such as Claude Code and Codex JSONL are observed source material. Do not bulk-import them into Scout as first-party conversation messages. - Mesh means reachability and coordination across machines. It does not mean exactly-once delivery, global consensus, CRDT convergence, or replicated external transcript storage. - Prefer explicit routing metadata over body mentions. Message body text is payload. ## Main Entry Points | Area | Path | | --- | --- | | Web UI/server | `packages/web` | | Native macOS menu app | `apps/macos` | | Transitional desktop/CLI source | `apps/desktop` | | iOS app | `apps/ios` | | Broker/runtime | `packages/runtime` | | Shared protocol | `packages/protocol` | | Public CLI package | `packages/cli` | | Landing/docs site | `landing` | | Product docs | `docs` | ## Routing Model - One explicit target means a DM. - Group coordination requires an explicit channel. - Shared broadcast is opt-in. - Use `scout send` or `messages_send` for tell/update. - Use `scout ask` or MCP `ask` for owned work or requested replies. - Use `invocations_get` / `invocations_wait` only to observe flights created by asks. - Use `replyMode: "notify"` for longer-running agent work that should return quickly and report back later. ## Must-Read Docs - [install.md](./install.md) for install and bootstrap expectations. - [docs/current-posture.md](./docs/current-posture.md) for maturity, trust, mesh, install footprint, and license boundaries. - [docs/architecture.md](./docs/architecture.md) for the broker/runtime/protocol model. - [docs/data-ownership.md](./docs/data-ownership.md) before changing transcript persistence. - [docs/agent-integration-contract.md](./docs/agent-integration-contract.md) before adding agent/adaptor integrations. - [docs/operator-attention-and-unblock.md](./docs/operator-attention-and-unblock.md) before changing permission, approval, or human-input flows. ## Common Verification Run the narrowest relevant checks for your change. Common commands: ```bash bun run --cwd apps/desktop check npm --prefix packages/runtime run check npm --prefix packages/protocol run check bun run --cwd landing build ``` --- ## README.md # OpenScout > **Requires [Bun](https://bun.sh).** Scout uses Bun as its JavaScript runtime and package manager. Install it first: `brew install bun` or `curl -fsSL https://bun.sh/install | bash` OpenScout is a local-first control plane for AI agents. It gives Claude Code, Codex, and future harnesses one shared broker, runtime, and protocol so agents can be discovered, addressed, observed, and composed without each surface inventing its own state model. This repository is the active OpenScout product codebase. It contains the local broker/runtime, shared protocol, public CLI, web, native, and mobile surfaces, docs, and release tooling. Current posture: high-trust local developer pilots. OpenScout is not yet an enterprise-ready, compliance-ready, hardened multi-tenant runtime. Start with [`docs/current-posture.md`](./docs/current-posture.md) before making maturity, trust, mesh, or license claims. ## Repo Map | Area | Path | Start here | | --- | --- | --- | | App surfaces | [`apps`](./apps) | [`apps/README.md`](./apps/README.md) | | Native macOS menu app | [`apps/macos`](./apps/macos) | [`apps/macos/README.md`](./apps/macos/README.md) | | Transitional desktop/CLI source | [`apps/desktop`](./apps/desktop) | [`apps/desktop/README.md`](./apps/desktop/README.md) | | iOS app | [`apps/ios`](./apps/ios) | [`apps/ios/README.md`](./apps/ios/README.md) | | Shared packages | [`packages`](./packages) | [`packages/README.md`](./packages/README.md) | | Broker/runtime | [`packages/runtime`](./packages/runtime) | [`packages/runtime/README.md`](./packages/runtime/README.md) | | Shared protocol | [`packages/protocol`](./packages/protocol) | [`packages/protocol/README.md`](./packages/protocol/README.md) | | Public CLI package | [`packages/cli`](./packages/cli) | [`packages/cli/README.md`](./packages/cli/README.md) | | Web package/bundle | [`packages/web`](./packages/web) | [`packages/web/README.md`](./packages/web/README.md) | | Product docs | [`docs`](./docs) | [`docs/README.md`](./docs/README.md) | | Landing/docs site | [`landing`](./landing) | [`landing/README.md`](./landing/README.md) | Host-specific integrations live in standalone repositories when they are independently installable packages. See [`docs/integrations.md`](./docs/integrations.md) for the current pi, Claude Code, Codex, and Hermes integration map. ## Start Here If you are new to the docs, start with [`docs/README.md`](./docs/README.md) for the reading order. The shortest newcomer path is: 1. [`install.md`](./install.md) for install and bootstrap expectations 2. [`docs/quickstart.md`](./docs/quickstart.md) for the first healthy local run 3. [`docs/current-posture.md`](./docs/current-posture.md) for maturity and trust boundaries 4. [`docs/architecture.md`](./docs/architecture.md) for the broker/runtime/protocol model 5. [`docs/agent-identity.md`](./docs/agent-identity.md) for address grammar and routing Scout is aware of adjacent standards such as A2A, but it does not collapse its internal model into them. For the definitive terminology and Scout's current A2A position, see [`docs/glossary.md`](./docs/glossary.md) and [`docs/a2a-alignment.md`](./docs/a2a-alignment.md). For agent-ready entry points, read [`llms.txt`](./llms.txt), [`llms-full.txt`](./llms-full.txt), and [`install.md`](./install.md). ## Why The Broker Matters OpenScout is not just "chat between terminals." The product bet is that agent collaboration needs a durable control plane, not a pile of harness-specific sessions. The current direction is: - explicit: conversation, work, delivery, and bindings are different records - durable: the broker is the only writer and local state is stored canonically - addressable: agents, conversations, messages, invocations, and flights all have stable IDs - replayable: surfaces rebuild from stored records instead of terminal scrollback - observable: you can inspect ownership, status, failures, and outputs - recoverable: broker restarts do not have to erase the story of what happened - harness-agnostic: Claude, Codex, tmux, and future harnesses are edge concerns, not protocol forks ## Product Shape At the repo level, Scout is organized around one product path: - `packages/web`, `apps/macos`, and `apps/ios` own the current human-facing surfaces - `packages/runtime` and `packages/protocol` are the shared broker/runtime foundation - `packages/cli` is the public npm package; the other packages stay as private internal boundaries - `apps/desktop` is transitional source for CLI/core pieces that have not yet moved to package-owned homes - host-specific integrations are documented in [`docs/integrations.md`](./docs/integrations.md); separate repos are linked rather than vendored unless the integration needs to build with OpenScout internals ## Getting Started Choose the install path that matches what you are doing: - If you already have the published CLI, start with the machine bootstrap. - If you are working from a fresh checkout, link the repo CLI first. Published CLI path: ```bash scout setup scout doctor ``` Fresh checkout path: ```bash bun install npm --prefix packages/cli run build (cd packages/cli && bun link) scout --help scout setup scout doctor ``` `scout setup` creates or updates machine-local settings, discovers workspace projects, writes `.openscout/project.json` for the current repo when needed, registers known agents, installs the base Scout launch agent, attempts to start the base service, and ensures Caddy is available for the local `scout.local` edge. On macOS, setup installs missing Caddy with `brew install caddy`; otherwise install Caddy yourself or set `OPENSCOUT_CADDY_BIN`. The base launch agent owns the broker, local edge, web startup, and menu bar launch; boot it out with the command shown by `scout doctor`. `scout doctor` is the quick operational check that the broker is installed, reachable, and writing logs in the expected support paths. What success looks like after setup: - `scout doctor` exits cleanly and reports the broker as reachable - the support directory exists under `~/Library/Application Support/OpenScout` - `scout --help` works and `bun run dev` starts the local web UI without repeating setup prompts ## Run The Local Web App The main local web loop now runs directly from the repo root: ```bash bun install bun run dev ``` That starts the current OpenScout web UI and local web server from `packages/web`. To install the CLI globally from this repo: ```bash npm --prefix packages/cli run build (cd packages/cli && bun link) scout --help scout setup scout doctor ``` ```text ~/Library/Application Support/OpenScout ``` The support directory is now organized as: ```text ~/Library/Application Support/OpenScout ├── settings.json ├── relay-agents.json ├── logs/ │ ├── app/ │ └── broker/ └── runtime/ └── agents/ ``` `relay-agents.json` remains the compatibility filename for machine-local agent registry entries. ## Read Next - [`docs/README.md`](./docs/README.md) for the docs map and reading order - [`install.md`](./install.md) for install/bootstrap expectations and support footprint - [`docs/quickstart.md`](./docs/quickstart.md) for the first successful local flow - [`docs/current-posture.md`](./docs/current-posture.md) for maturity, trust, and license-status boundaries - [`docs/architecture.md`](./docs/architecture.md) for the broker/runtime/protocol split - [`docs/agent-identity.md`](./docs/agent-identity.md) for address grammar and name resolution - [`docs/agent-integration-contract.md`](./docs/agent-integration-contract.md) for the minimum contract expected from agents and adapters - [`docs/glossary.md`](./docs/glossary.md) for the definitive Scout vocabulary - [`docs/a2a-alignment.md`](./docs/a2a-alignment.md) for how Scout aligns with A2A today --- ## install.md # Install OpenScout This is the machine-readable install guide for agents and humans. It describes the current local developer pilot path, not an enterprise deployment path. For maturity, trust, and license expectations, read [docs/current-posture.md](./docs/current-posture.md) before presenting OpenScout to a new evaluator. Related first-read docs: - [README.md](./README.md) for the repo overview - [docs/README.md](./docs/README.md) for the docs map - [docs/quickstart.md](./docs/quickstart.md) for the first healthy local run - [docs/integrations.md](./docs/integrations.md) for companion host packages ## Prerequisites - Bun 1.3 or newer - macOS for the full desktop/service bootstrap path - Homebrew on macOS if `scout setup` needs to install Caddy - A trusted local developer machine OpenScout is not currently a silent managed install, hardened multi-tenant runtime, or compliance-ready service. ## Choose An Install Path Use the published CLI package when you are evaluating Scout as a local pilot or installing it onto a developer machine. Use the repo-local path when you are contributing to this repository, testing runtime changes, or building a host integration against the current checkout. ## Install From The Published CLI Package ```bash bun add -g @openscout/scout scout setup scout doctor ``` `scout setup` bootstraps local settings, discovers known projects, writes project metadata when needed, installs or updates the local launch agent, starts the broker service, and ensures the local web edge can run. `scout doctor` verifies that the local broker is installed, reachable, and writing expected support files. ## Companion Host Integrations The OpenScout CLI and broker are the shared base layer. Host-specific packages can then add native commands or MCP surfaces inside the agent tools where you already work. | Host | Package | Install | | --- | --- | --- | | pi | [Pi Scout](https://github.com/arach/pi-scout) | `pi install git:github.com/arach/pi-scout` | | Claude Code | [Claude Scout](https://github.com/arach/claude-scout) | `/plugin marketplace add arach/claude-scout` | | Codex | [Codex Scout](https://github.com/arach/codex-scout) | `/plugin marketplace add arach/codex-scout` | Install these after `scout setup` and `scout doctor` pass. Each companion package should use the installed `scout` CLI or the local broker rather than vendoring OpenScout internals. See [docs/integrations.md](./docs/integrations.md) for the current integration map, repository links, and sibling-checkout guidance. ## Install From This Repo ```bash bun install npm --prefix packages/cli run build (cd packages/cli && bun link) scout --help scout setup scout doctor ``` To run the desktop development surface from the repo: ```bash bun run dev ``` ## Success Criteria A healthy local pilot install has these properties: - `scout --help` prints the CLI help. - `scout doctor` reports the broker as reachable. - Local support files exist under `~/Library/Application Support/OpenScout`. - `scout whoami` reports the sender identity for the current directory. - `scout who` can list known, configured, or recently active agents. - `bun run dev` starts the local desktop shell when working from the repo. ## First-Run Health Ladder Use this as a stop/go sequence. Do not continue to routing until the earlier checks pass. 1. `scout --help` If this fails, install the published CLI package or rebuild and relink `packages/cli` from this repo. 2. `scout setup` If this fails, fix the printed prerequisite or permission problem first. Setup owns local settings, project discovery, service installation, and the local web edge. 3. `scout doctor` If this fails, follow the service repair command it prints. A broker that is not reachable is not ready for `send`, `ask`, or the app surfaces. 4. `scout whoami` If this fails or reports the wrong sender, rerun setup from the intended project directory and inspect local project metadata. 5. `scout who` If this lists no usable agents, install the relevant companion host integration or start/register an agent for this project before sending work. 6. `scout send --to "hello"` If routing is ambiguous, copy the fuller selector shown by `scout who`. ## Support Footprint The local bootstrap can create or use: - `~/Library/Application Support/OpenScout/settings.json` - `~/Library/Application Support/OpenScout/relay-agents.json` - `~/Library/Application Support/OpenScout/logs` - `~/Library/Application Support/OpenScout/runtime` - a macOS launch agent for the local broker/service path - optional Caddy files for the local web edge - optional mesh or pairing configuration for multi-machine reachability That footprint is appropriate for a trusted developer pilot. It should be disclosed before asking someone else to install Scout. ## Common First Commands ```bash scout whoami scout who scout send --to "hello" scout ask --to "can you review this?" ``` Routing rules: - one explicit target -> DM - group coordination -> explicit channel - everyone -> shared broadcast - tell/update -> `send` - owned work or requested reply -> `ask` For long-running work, prefer callback-style semantics where the surface supports it. MCP callers should use `replyMode: "notify"` when they want the broker to return quickly and report back later. ## Troubleshooting Pointers - If the broker is not reachable, run `scout doctor` and follow the command it prints for the local service. - If the CLI is missing, rebuild and relink `packages/cli`. - If an agent name is ambiguous, run `scout who` or use the full resolved selector. - If `scout who` is empty, install the companion package for the host you use or start/register an agent before sending work. - If a long-running ask would block the caller, use callback-style semantics through `replyMode: "notify"` when using MCP. - If a permission or approval prompt is trapped in one host UI, the host integration needs to forward that prompt into Scout; an MCP server cannot see prompts intercepted before the tool call. ## Related Docs - [docs/quickstart.md](./docs/quickstart.md) - [docs/current-posture.md](./docs/current-posture.md) - [docs/architecture.md](./docs/architecture.md) - [docs/agent-integration-contract.md](./docs/agent-integration-contract.md) - [docs/operator-attention-and-unblock.md](./docs/operator-attention-and-unblock.md) --- ## docs/README.md # Docs This folder is the working documentation set for OpenScout. Use it as the docs map after the top-level [`README.md`](../README.md): the first group explains the current local-first product shape, including the human surfaces that sit on the same broker/runtime as the agents. Later groups are for implementation detail, historical context, or proposals. ## Start Here If you are scanning from GitHub and want the shortest path: 1. [`../README.md`](../README.md) for what OpenScout is and how to run it locally 2. [`../install.md`](../install.md) for choosing published CLI vs repo-local setup 3. [`quickstart.md`](./quickstart.md) for the first healthy local run and first meaningful commands 4. [`current-posture.md`](./current-posture.md) for maturity, trust, install footprint, and license-status boundaries 5. [`architecture.md`](./architecture.md) for the system-level control-plane model Keep the posture straight while reading: OpenScout is for high-trust local developer pilots today. It is not an enterprise-ready, compliance-ready, or hardened multi-tenant runtime. After that, choose the role-specific next read: - Agent or adapter integration: [`agent-integration-contract.md`](./agent-integration-contract.md), then [`scout-comms.md`](./scout-comms.md), then [`mcp-api-posture.md`](./mcp-api-posture.md) - Routing and identity: [`agent-identity.md`](./agent-identity.md), then [`scout-agent-delegation.md`](./scout-agent-delegation.md) - Data model and ownership: [`data-ownership.md`](./data-ownership.md), then [`collaboration-workflows-v1.md`](./collaboration-workflows-v1.md) - Human/operator surfaces: [`ask-scout.md`](./ask-scout.md), then [`operator-attention-and-unblock.md`](./operator-attention-and-unblock.md) - Standards and terminology: [`glossary.md`](./glossary.md), then [`a2a-alignment.md`](./a2a-alignment.md) - Host/package map: [`integrations.md`](./integrations.md), then [`../install.md#companion-host-integrations`](../install.md#companion-host-integrations) ## Current Orientation Docs ### Core Concepts - [`quickstart.md`](./quickstart.md) gives the first-success path and defines the main operator-facing terms - [`current-posture.md`](./current-posture.md) states the current maturity, trust, install-footprint, mesh, and license boundaries - [`architecture.md`](./architecture.md) explains the broker-first system shape and the main control-plane terms - [`data-ownership.md`](./data-ownership.md) defines the boundary between Scout-owned coordination state and observed harness source material - [`agent-integration-contract.md`](./agent-integration-contract.md) gives coding agents and adapter authors the minimum contract for plugging into Scout - [`scout-comms.md`](./scout-comms.md) is the front door for building Scout-aware clients and adapters - [`mcp-api-posture.md`](./mcp-api-posture.md) defines the core vs pro Scout MCP tool tiers - [`integrations.md`](./integrations.md) maps host-specific Scout integrations and explains why they are linked rather than vendored by default - [`glossary.md`](./glossary.md) defines the canonical meanings of Scout's core nouns - [`scoutbot.md`](./scoutbot.md) defines `@scoutbot` as the unified conversational assistant handle - [`a2a-alignment.md`](./a2a-alignment.md) explains where Scout intentionally aligns with A2A and where it does not - [`agent-identity.md`](./agent-identity.md) explains canonical and minimal agent addresses - [`ask-scout.md`](./ask-scout.md) explains how a human reaches their agents through Scout - [`collaboration-workflows-v1.md`](./collaboration-workflows-v1.md) explains the question vs work-item model - [`scout-agent-delegation.md`](./scout-agent-delegation.md) explains the correct one-to-one agent delegation workflow - [`user-config.md`](./user-config.md) covers operator identity and local config ## Deeper Product Docs - [`ask-scout-implementation.md`](./ask-scout-implementation.md) adds implementation detail for the ask flow - [`tail-firehose.md`](./tail-firehose.md) explains the machine-wide harness transcript stream for observing agent activity - [`native-runtime.md`](./native-runtime.md) captures historical context for the desktop-host/runtime split - [`releases.md`](./releases.md) explains the coordinated npm, DMG, GitHub release, and optional iOS ship path ## Agent-Optimized Docs - [`../llms.txt`](../llms.txt) is the compact repo-wide LLM index - [`../llms-full.txt`](../llms-full.txt) is the larger generated copy/paste context bundle - [`../install.md`](../install.md) is the install/bootstrap guide with success criteria and support footprint - [`agent/README.agent.md`](./agent/README.agent.md) is the dense project context for coding agents - [`agent/current-posture.agent.md`](./agent/current-posture.agent.md) is the dense maturity and trust summary - [`agent/integration-contract.agent.md`](./agent/integration-contract.agent.md) is the dense adapter and agent integration checklist - [`agent/scout-comms.agent.md`](./agent/scout-comms.agent.md) is the dense comms integration checklist ## Engineering Docs And Proposals - [`eng/README.md`](./eng/README.md) indexes implementation-facing design docs and proposals - [`openagents-tracks/README.md`](./openagents-tracks/README.md) breaks the current OpenAgents-inspired work into implementation tracks ## Reading By Question - "What is OpenScout trying to be?" Start with [`../README.md`](../README.md) and [`architecture.md`](./architecture.md). - "What data does Scout own?" Read [`data-ownership.md`](./data-ownership.md). - "Is this enterprise-ready?" Read [`current-posture.md`](./current-posture.md). - "How should an agent integrate?" Read [`agent-integration-contract.md`](./agent-integration-contract.md). - "How should a client or adapter understand Scout communication?" Read [`scout-comms.md`](./scout-comms.md). - "Which MCP tools are core versus pro integration?" Read [`mcp-api-posture.md`](./mcp-api-posture.md). - "Where do host integrations live?" Read [`integrations.md`](./integrations.md). - "What exactly do Scout's core terms mean?" Read [`glossary.md`](./glossary.md). - "What is `@scoutbot`?" Read [`scoutbot.md`](./scoutbot.md). - "How does Scout relate to A2A?" Read [`a2a-alignment.md`](./a2a-alignment.md). - "How do I get to a first healthy run?" Start with [`quickstart.md`](./quickstart.md). - "How do I address or route to an agent?" Read [`agent-identity.md`](./agent-identity.md). - "How does work differ from conversation?" Read [`collaboration-workflows-v1.md`](./collaboration-workflows-v1.md). - "How do I watch harness activity across the machine?" Read [`tail-firehose.md`](./tail-firehose.md). - "Where do proposals and implementation plans live?" Start in [`eng/README.md`](./eng/README.md). - "How do I use Scout from a pi session?" Read [`eng/sco-015-pi-scout-integration.md`](../docs/eng/sco-015-pi-scout-integration.md). - "How do I ship npm and the macOS DMG together?" Read [`releases.md`](./releases.md). - "What should I read first as a newcomer?" Use the current orientation docs, then move to deeper product docs only if you need implementation or historical context. --- ## docs/quickstart.md # Quickstart This is the shortest path from a fresh checkout to a first useful handoff with OpenScout. If you spend too much time copying prompts, re-explaining context, or checking multiple agent terminals by hand, this is the page to start with. OpenScout gives you one broker-backed surface for your agents. That can be the CLI, the desktop app, or the iOS app when you want to check in away from your desk. The underlying state is the same, so a message or handoff you create in one place is still visible in the others. If you only read three more pages after this one, read [`current-posture.md`](./current-posture.md), [`architecture.md`](./architecture.md), and [`agent-identity.md`](./agent-identity.md). ## 1. Bootstrap The Local Control Plane Run the machine setup and health check. If `scout` is not on your PATH yet, use the published or repo-local install path in [`../install.md`](../install.md) first. ```bash scout setup scout doctor ``` What healthy looks like: - `scout setup` completes without errors, creates or updates local Scout settings, and starts the broker service. - `scout doctor` reports that the broker is installed and reachable. - If this repo is your working copy, the setup step should also discover the workspace and write the local project metadata when needed. If you want the app surface as well: ```bash bun install bun run dev ``` That should bring up the desktop shell against the same local broker and runtime layer. In pilot setups where mobile pairing is configured, the iOS app uses the same backing state, so it is useful when you want to check in, send a follow-up, or pick work back up without sitting at the desktop. ## 2. See Who You Are And What Exists ```bash scout whoami scout who ``` Use `scout whoami` to see who Scout will speak as from the current directory. `send`, `ask`, and `broadcast` share that same sender unless you override it with `--as`. `watch` follows a conversation or channel; it does not choose a sender. Use `scout who` to inspect known agents when you need to disambiguate a specific target. If you know the project but not the right agent name, skip manual discovery and route the ask by project instead: ```bash scout ask --project ../talkie "can you review this?" ``` An agent name is the address you type to reach a base agent. It is usually a short, human-friendly project/workspace identity. Scout resolves that base identity to a concrete instance, and harness/model/session details are layered on only when the caller asks for them. If `scout who` does not list a usable target, the broker may be healthy but no agent is ready for this project yet. Install the companion integration for your host from [`../install.md`](../install.md#companion-host-integrations), or start/register an agent before trying to route work. ## 3. Use One Routing Model Everywhere The routing rules do not change by surface: - one target -> DM - group coordination -> explicit channel - everyone -> shared broadcast - tell / update -> `send` - owned work / requested reply -> `ask` - follow-up stays in the same DM or explicit channel ## 4. Try The Two Main Paths When the workspace and one target are clear, use the direct command first. Do not run an orientation loop before every handoff. Copy a selector from `scout who` and use it as the explicit target, or use `--project` when the repo path is the thing you actually know. ```bash scout send --to "hello" scout ask --to "can you review this?" scout ask --project ../talkie "can you review this?" ``` `send` is the message path. Use it for a durable note or reply in a conversation. This is the clean replacement for "paste the same update into three terminals." It does not open a tracked flight. `ask` is the invocation path. Use it when you want Scout to track a request for work or a reply. An invocation creates a flight so the broker can follow that work from start to finish, even if you switch devices or come back later. For long-running MCP asks, use `replyMode: "notify"` when you want the caller to return quickly and receive completion as a callback notification. Use `replyMode: "inline"` when the caller needs the target acknowledgement before continuing, then follow completion with `invocations_get` or `invocations_wait`. Concrete handoff example: 1. You ask one agent to investigate a bug. 2. That agent replies with a summary and a next step. 3. You `send` that summary to another agent instead of retyping it. 4. You `ask` the second agent to take the follow-up, and Scout keeps the request tracked. ## Plain-Language Model - Broker: the local canonical store and router. It keeps the records, decides where they go, and survives restarts. - Runtime: the machine-local service layer that starts agents, checks health, manages harness adapters, and feeds the broker. - Message: a durable conversation record. It is what you send when the goal is "say this" or "reply to that." - Invocation: a tracked request for work. It is what you create when the goal is "do this and keep the lifecycle visible." - Flight: the lifecycle record attached to an invocation. - Agent name: the human-typed address for one agent. Scout resolves the short form to the exact identity the broker stores. ## If The First Pass Worked That means you have the core loop: 1. The broker is running. 2. You know who Scout will act as from this directory. 3. Scout can see at least one agent name. 4. You can send a message or create an invocation from the CLI, desktop app, or iOS app. From there, the next useful read is [`architecture.md`](./architecture.md) for the control-plane split, followed by [`agent-identity.md`](./agent-identity.md) when you want to understand why one name resolves and another does not. If you are evaluating Scout for a pilot, read [`current-posture.md`](./current-posture.md) before assuming enterprise-grade security, licensing, or operational maturity. --- ## docs/current-posture.md # Current Posture This page is the plain-language maturity, trust, and scope statement for OpenScout. It should keep product claims, docs, and package metadata honest while the system is still moving quickly. ## Short Version OpenScout is pilot-worthy for high-trust local developer environments. It is not enterprise-ready, compliance-ready, or sponsor-review-ready yet. The useful promise today is narrow and concrete: run a local broker, make agents addressable, keep Scout-owned coordination records durable, and let humans and agents communicate through the same state model across CLI, desktop, mobile, and mesh-aware peers. ## Who It Is For Right Now OpenScout is currently for: - solo developers coordinating multiple local agents or harnesses - small, trusted teams experimenting with agent-to-agent workflows - coding agents that need a durable route to other agents or to the human operator - platform reviewers evaluating whether the control-plane model is worth piloting OpenScout is not currently for: - untrusted multi-tenant execution - regulated enterprise rollout - security-sensitive production automation without a human trust boundary - hosted, managed, or SLA-backed coordination ## Trust Boundary The default trust model is local-first and high-trust: - The broker and Scout-owned state run on the user's machine. - Scout does not require a hosted control plane for the ordinary local path. - Pairing and mesh forwarding are explicit actions, not implicit cloud sync. - Local agents and harnesses often run with meaningful machine access. Treat them as trusted local automation unless a stricter permission profile is explicitly configured. This is not yet a hardened security perimeter: - no enterprise SSO/RBAC policy layer - no tenant isolation model - no formal audit/compliance story - no guarantee that every harness permission prompt is broker-owned yet - no universal sandbox contract across Codex, Claude, and future harnesses For the data boundary, read [`data-ownership.md`](./data-ownership.md). For operator approvals and permission prompts, read [`operator-attention-and-unblock.md`](./operator-attention-and-unblock.md). ## Mesh Means Reachability In OpenScout docs, "mesh" means machines and agents can discover, address, message, wake, and inspect each other through broker-owned routes. It does not currently mean a distributed-systems guarantee layer. Do not read "mesh" as a promise of exactly-once delivery, at-most-once delivery, global consensus, CRDT-style convergence, or replicated external transcript storage. The design center is: "I can talk to that agent over there, ask it to do work, check back later, and see the broker-owned records of that coordination." ## Data Ownership Scout owns coordination records it creates or routes: - conversations and messages - invocations and flights - deliveries and delivery attempts - bindings and agent registrations - work items and questions when created through Scout Scout observes external harness material without making it first-party conversation state: - Claude Code transcript JSONL - Codex session JSONL - harness logs and tail streams - process and filesystem signals Observed harness material can be tailed, linked, summarized, or lightly indexed. It should not be bulk-imported into Scout's database as if Scout authored it. ## Install Footprint A realistic local install can involve: - Bun for the CLI/runtime toolchain - a Scout broker service - macOS launch agent setup - support files under `~/Library/Application Support/OpenScout` - optional Caddy for the local web edge - optional Tailscale or manually configured mesh seeds for multi-machine discovery - optional desktop and iOS apps for human surfaces That footprint is appropriate for a developer pilot. It is too much to treat as a silent, enterprise-managed install without more packaging, policy, and admin work. ## License And Package Signals Do not infer public reuse rights from the product name or package availability alone. As of this document, the package manifests use `UNLICENSED` and the repo does not carry a top-level open-source license file. Before broader external distribution, the project should make the license posture explicit and consistent across: - repo root - npm package manifests - landing page agent files - generated `llms.txt` / `agents.md` - README and docs ## Maturity Markers Reasonable to say today: - local-first control-plane prototype/product codebase - active v0.x development - useful for trusted pilots and internal dogfooding - clear direction around broker-owned records, agent identity, and collaboration workflows Do not say yet: - enterprise-ready - compliance-ready - secure multi-tenant runtime - guaranteed distributed delivery layer - stable public API contract for all integrations - complete permission/approval capture across all hosts ## What Would Make It Sponsor-Ready The next maturity bar is not just more features. It is clarity and evidence: - one clean buyer/user story for the pilot - consistent license and package trust signals - explicit install and uninstall footprint - documented security/trust posture - stable agent integration contract - broader host-level permission/approval capture over broker-owned unblock requests - clear failure, retry, and notification semantics - a small compatibility test suite for agent/tool integrations --- ## docs/architecture.md # Architecture This document is the system-level map for OpenScout. If you are new, read it as a guide to three things: what the broker is, what the runtime does, and what the protocol defines. Read this after the repo [`README.md`](../README.md) if you are orienting to the project for the first time. If you want the command-first ramp first, read [`quickstart.md`](./quickstart.md) before this page. If you are evaluating maturity, trust, or license posture, read [`current-posture.md`](./current-posture.md). If you need naming rules or workflow semantics after this, continue with [`agent-identity.md`](./agent-identity.md) and [`collaboration-workflows-v1.md`](./collaboration-workflows-v1.md). ## Working Thesis Scout is a local-first control plane for orchestrating AI agents across harnesses, machines, and interfaces. For the exact meanings of Scout's core nouns, read [`glossary.md`](./glossary.md). For the current relationship between Scout and A2A, read [`a2a-alignment.md`](./a2a-alignment.md). Remember these three things: - **Broker**: the local daemon that stores state, routes messages, and acts as the source of truth. - **Protocol**: the shared language for agent identities, records, and requests. - **Runtime**: the part that starts, stops, and health-checks agent sessions on a given harness. It does not replace Claude Code, Codex, or any other agent tool. It is the substrate: the layer where agents get discovered, addressed, observed, and composed, regardless of which harness runs them or which machine they live on. A harness is just the agent runner and transport wrapper for a specific tool. The agent itself may live outside Scout; what Scout owns is the local routing, binding, session, and durable coordination state around that agent. In practice, the architecture is aiming for three stable outcomes: - one canonical writer for local state: the broker - one shared model for messages, invocations, flights, and identities: the protocol - many possible operator surfaces and harness adapters around that core That framing matters because most of the design choices below are about protecting those boundaries. ## Principles A small set of constraints shape every design decision. **Local-first, not cloud-first.** The broker, agent registry, and Scout-owned state live on your machine. Nothing phones home by default. Local files and databases are the source of truth, not a hosted API. **High-trust local pilot, not hardened enterprise perimeter.** Scout's current security posture assumes trusted local users, trusted local agents, and explicit pairing/mesh choices. It is not yet a multi-tenant, compliance-ready, or enterprise-policy system. See [`current-posture.md`](./current-posture.md). **Own coordination, observe transcripts.** Scout owns the control-plane records it creates or routes: conversations, messages, invocations, flights, deliveries, bindings, and agent registrations. External harness transcripts such as Claude Code or Codex JSONL remain harness-owned source material. Scout may discover, tail, summarize, link, and index lightweight metadata from those files, but it should not bulk-import every external turn into the control-plane database as if Scout authored it. See [`data-ownership.md`](./data-ownership.md). **Multi-harness.** Agents run on Claude Code, Codex, or anything that speaks the protocol. Scout doesn't assume one execution backend. **Multi-machine.** Agents on different machines discover and message each other through mesh forwarding. Pair a phone or a second workstation and the agent graph extends with it. **File-based configuration.** Agent definitions, overrides, and project bindings are JSON files on disk. No dashboard required. **Protocol over product.** The protocol package defines the shared grammar. Products are built on top of it, not beside it. ## Communication Flow ![Scout communication flow](arc:communication-flow) Agent sessions connect to a single Scout broker over HTTP and SSE. The broker owns the agent registry and routes messages between sessions. Each harness uses its own transport -- `stream-JSON` for Claude Code, `app-server` for Codex -- but the protocol layer above is shared. A typical exchange looks like this: ``` operator → scout send --to codex "review the auth module" scout cli → broker /v1/deliver (target intent + message body) broker → resolves codex → endpoint broker → codex session (deliver message via SSE) codex → broker (post reply) broker → operator (deliver reply via SSE) ``` One concrete example: `scout ask --to codex "review the auth module"` sends an ask-style request to the broker. The broker resolves the `codex` target to an endpoint, forwards the request to the running Codex session, records the target acknowledgement, and tracks the later completion as a flight. A flight is the broker's tracked record for an ask-style request, including retry, acknowledgement, and completion state. Caller wait budgets may stop a CLI or MCP call from waiting, but they do not cancel or fail the broker flight. ## Core Moving Parts | Layer | Role | Key detail | |-------|------|------------| | **Protocol** | Shared type system and address grammar | Defines the agent identity grammar, message records, invocation requests, flight records, collaboration contracts, and bindings | | **Broker** | Local message bus and state store | SQLite-backed daemon that owns registration, routing, threading, dispatch, HTTP reads/writes, and SSE updates | | **Runtime** | Session and runtime lifecycle management | Starts, resumes, stops, and health-checks sessions across harnesses. Manages tmux sessions, system prompts, and transport adapters | | **CLI** | Operator interface | `scout up`, `scout send`, `scout ask`, `scout who` -- passes structured route intent to the broker and keeps bootstrap/orientation cheap | | **Surfaces** | Views into broker state | Desktop, web, iOS, terminal, and pi. They read from the broker; none of them own agent state | ### Protocol The shared grammar everything speaks. It defines agent identity (the address grammar described in [`agent-identity.md`](./agent-identity.md)), message records, invocation requests, flight tracking, collaboration contracts, and bindings. Anything that crosses a boundary — between agents, harnesses, or machines — is described here. ### Broker A single local daemon per machine. Agents post Scout-owned messages and invocations to it; it resolves structured targets, routes to endpoints, and records coordination history. It is the canonical writer for Scout control-plane state. Exposes HTTP for reads and writes, SSE for live updates. ```bash # What the broker handles scout send --to hudson "check the deploy" # → resolve, route, deliver scout who # → read agent registry scout watch # → SSE stream of all events ``` ### Runtime Manages agent sessions across harnesses — starting them, stopping them, health-checking them. Handles system prompt generation, tmux session management, and transport adapters for each harness type. Also owns the file-based agent override registry, project discovery, and harness profile resolution. ### CLI The operator's main interface. It sends route intent such as `--to hudson` or `--channel triage` to the broker and renders broker receipts, remediation actions, and orientation views. Legacy body-mention shortcuts still exist for compatibility, but new flows should keep target metadata out of the message body. ### Surfaces Desktop host, web dashboard, iOS companion, terminal UI, and pi. These are views into broker-owned control-plane state and observed harness activity. None of them own agent state; the broker does. The pi extension (see [`eng/sco-015-pi-scout-integration.md`](../docs/eng/sco-015-pi-scout-integration.md)) runs Scout coordination as a native pi extension, letting pi sessions send and receive messages via the broker alongside other harnesses. ## Performance Direction Operator commands like `scout up`, `scout ps`, and `scout who` need to stay cheap. They shouldn't repeatedly scan the machine or spawn overlapping probes from each surface. The broker owns all expensive reads — runtime health, agent liveness, tmux sessions, harness readiness, project discovery. These are cached as broker-owned snapshots with TTLs. When a TTL expires, the broker refreshes once and coalesces concurrent readers onto the same in-flight refresh. Every surface reads these snapshots first, using stale-while-revalidate where appropriate. Direct filesystem or subprocess probing is limited to bootstrap and recovery paths when the broker is unavailable. ## Addressing And Session Lifecycle ![Agent lifecycle](arc:agent-lifecycle) 1. **Bind.** Create or refresh a Scout-local binding from a project path and branch to an addressable agent target. 2. **Start or attach.** `scout up` launches or resumes the harness session Scout should use for that target, with a generated system prompt that includes the collaboration contract when Scout owns the launch path. 3. **Route.** Messages with explicit target intent hit the broker, which resolves the name, finds the endpoint, and dispatches. 4. **Invoke.** For ask-style interactions, the broker creates a flight record -- tracking the request-response lifecycle with acknowledgement, retry, and durable completion semantics. 5. **Stop.** `scout down` terminates the local session and marks the endpoint offline. ```bash scout up hudson # bind + start scout send --to hudson "hi" # route + deliver scout ask --to hudson "..." # route + invoke (tracks flight) scout down hudson # stop ``` ## Mesh ![Mesh topology](arc:mesh-topology) Agents on different machines discover each other through mesh forwarding. Each broker advertises its local agents to peer brokers, which sync endpoint tables so `@agent.other-machine` resolves across the network. In Scout, mesh means reachability and coordination, not global consensus, exactly-once delivery, or replicated external transcript storage. ### Discovery Brokers find peers two ways: by probing Tailscale's peer list (`tailscale status --json`) and through manually configured seed URLs. No mDNS, no cloud discovery service. If you're on a Tailscale network, your brokers can find each other automatically. If not, point them at each other with `OPENSCOUT_MESH_SEEDS`. ```bash # Automatic — brokers on the same tailnet discover each other scout mesh discover # Manual — seed a broker URL directly OPENSCOUT_MESH_SEEDS=http://workstation-2:4080 scout mesh discover ``` Once a peer is found, the broker fetches its agent registry via `/v1/snapshot` and merges remote agents into its local database. Each agent carries an `authorityNodeId` — the node that owns it. Messages and invocations for remote agents get forwarded to the authority broker over HTTP. ### Forwarding When you `scout send --to hudson "..."` and hudson lives on another machine, the broker's delivery planner detects that hudson's `authorityNodeId` differs from the local node. Instead of delivering locally, it bundles the message with its full context — actors, agents, conversation, bindings — and POSTs it to the remote broker's `/v1/mesh/messages` endpoint. The remote broker commits the bundle to its own journal and delivers locally. Invocations work the same way. Ask-style requests forward to the authority node, which executes them and returns the flight record. ### Pairing A phone or second workstation joins the mesh through `scout pair`. The local broker starts a relay (or connects to an external one), generates a QR code with a pairing payload, and waits. The remote device scans the code, connects over a Noise-protocol-encrypted channel, and becomes a full mesh peer — not just a viewer. It gets a live view of the agent graph and can send messages into any conversation. ```bash scout pair # show QR code, start managed relay scout pair --relay url # use an external relay ``` ## What Scout Is Not Scout is not a framework for building agents. It is not a cloud service. And it is not a replacement for any single agent tool. It is the connective tissue between agent runtimes, harnesses, and operator surfaces. --- ## docs/scout-comms.md # Scout Comms This is the front door for building a Scout-aware client, plugin, or adapter. Read this when you want to understand how Scout interactions work: what gets routed, what gets stored, how replies find their way home, and which pieces are display affordances rather than protocol authority. Scout comms are **not an HTTP spec**, but they are not not like one: - an interaction has an intent, like a method - it has routing context, like headers - it has a body, which remains payload - it returns durable ids and state, like a receipt/status surface - it may create follow-on records such as flights, questions, or work items The important difference is that the local broker, not a wire format, is the canonical writer for Scout-owned coordination state. ## Current Posture OpenScout is for high-trust local developer pilots. Treat these docs as current integration guidance, not a frozen public API guarantee. Do not build claims around enterprise readiness, compliance readiness, hardened multi-tenancy, or exactly-once distributed delivery. ## Mental Model Scout has three layers: | Layer | What It Does | | --- | --- | | Protocol | Shared TypeScript shapes for messages, invocations, conversations, delivery, reply context, and collaboration records | | Broker | Local source of truth that resolves targets, writes records, plans delivery, and tracks asks | | Surface | CLI, desktop, web, mobile, harness plugin, or external client that reads/writes through the broker | A client should submit structured intent to the broker and render broker-owned records back to the user. It should not infer routing from message body text. ## Core Records | Record | Meaning | Primary Type | | --- | --- | --- | | Conversation | A durable place messages belong: DM, channel, group DM, thread, or system lane | `ConversationDefinition` | | Message | A durable body posted by one actor into one conversation | `MessageRecord` | | Delivery | A planned transport-specific fan-out for a message or ask | `DeliveryIntent` / `ScoutDeliverRequest` | | Invocation | An explicit request for an agent to do something | `InvocationRequest` | | Flight | The lifecycle of an invocation: queued, running, waiting, completed, failed, or cancelled | `FlightRecord` | | Reply context | The active return path when a harness is answering an inbound broker ask | `ScoutReplyContext` | | Question | Lightweight information-seeking collaboration record | `QuestionRecord` | | Work item | Durable owned execution record with progress, waiting, review, and done states | `WorkItemRecord` | | Binding | Link between a Scout conversation and an external channel/thread | `ConversationBinding` | | Dispatch record | Routing diagnostic for ambiguous, unknown, unparseable, or unavailable targets | `ScoutDispatchRecord` | Protocol source files live in `packages/protocol/src`. ## Runtime Sessions Scout is also a harness runtime surface. A Scout **agent** is a stable addressable identity; a **session** is a concrete Claude, Codex, or future harness conversation/process/thread; an **endpoint** attaches an agent identity to one reachable session. Cards are identity and return-address records. They do not by themselves mean a harness session is alive. Treat card creation, registration, and explicit session attachment as a pro integration layer for hosts or Scout-native agents that intentionally manage identity infrastructure. Core agents should use `ask`, `send`, and `reply`; the broker can create or bind cards internally when needed. Commands that start or attach harnesses should use the public noun **session** and should fail loudly when a requested harness cannot be backed by a compatible session. Examples of the intended shape: ```bash scout session start --agent hudson --harness codex scout session attach --agent hudson --harness codex --session scout session inspect --agent hudson --harness codex ``` `scout up` may remain as a convenience alias, but it should resolve to an explicit session operation and report what happened. See [`runtime-sessions.md`](./runtime-sessions.md). ## Interaction Workflows ### Message / Update Use the message path for status, updates, notes, and channel posts. Even when no owned work lifecycle is required, clients should expect a durable broker receipt. Examples: ```bash scout send --to hudson "The branch is ready for review." ``` MCP equivalent: ```ts messages_send({ targetLabel: "@hudson", body: "The branch is ready for review." }) ``` Expected client behavior: - send an explicit target field, not only `@hudson` in the body - render the returned `conversationId`, `messageId`, and optional `flightId` when useful - treat one explicit target as a DM - let the broker decide whether a targeted DM needs a wake/start/attach turn; callers should not need to choose wake mechanics for normal sends - require an explicit channel for group coordination - do not treat message delivery as fire-and-forget; keep the receipt available Quiet delivery should be an optional message/reply modifier, not a separate primitive. It should still write the durable conversation record while suppressing notify/wake side effects where target policy allows. `ask` should not grow a quiet variant because it creates ownership and lifecycle state. ### Ask / Requested Reply Use the ask path when the caller expects work, investigation, review, or an answer. Examples: ```bash scout ask --to hudson "Review the auth module and report risks." scout ask --project ../talkie "Review the auth module and report risks." ``` MCP equivalent: ```ts ask({ to: "@hudson", body: "Review the auth module and report risks.", }) ask({ projectPath: "../talkie", body: "Review the auth module and report risks.", }) ``` Expected client behavior: - create or display a durable message for the ask - use `projectPath` / `--project` when the project is known but the concrete agent or session is not; Scout resolves or creates the right project agent instance - surface returned ids such as `flightId` and `workId` - treat the initial `ask` response as the broker receipt, not as the target agent's acknowledgement - expect the target agent to promptly post a broker-visible acknowledgement in the same conversation when it starts working - expect target-authored completion as a later message and flight completion - use `invocations_wait` / `invocations_get` for longer follow-up polling - show wake/session failures as lifecycle state, not as silent background limbo Client API shape: ```mermaid sequenceDiagram participant Caller participant ScoutAPI as Scout client API
ask / invocations_wait participant Broker participant Target Caller->>ScoutAPI: ask(to, body) ScoutAPI->>Broker: create message + invocation + flight Broker-->>ScoutAPI: receipt
flightId + workId ScoutAPI-->>Caller: dispatched receipt Broker->>Target: deliver ask Target->>Broker: ack message
"Received, working on it now" Broker-->>Caller: target-authored ack in DM Target->>Broker: completion
final reply + flight completed Broker-->>Caller: target-authored completion in DM Caller->>ScoutAPI: invocations_wait(flightId) ScoutAPI->>Broker: read/wait flight Broker-->>ScoutAPI: completed + output ScoutAPI-->>Caller: final state/output ``` Product architecture shape: ```mermaid sequenceDiagram participant Caller participant Broker participant Target Caller->>Broker: ask
create message + invocation + flight Broker-->>Caller: broker receipt
flightId + workId Broker->>Target: deliver ask Target->>Broker: "Received, working on it now" Broker-->>Caller: target-authored ack Target->>Broker: final answer / result Broker-->>Caller: target-authored completion Broker-->>Caller: flight marked completed Caller->>Broker: wait/get flight Broker-->>Caller: completed / failed / still running ``` ### Broker Reply Mode When a harness is invoked by Scout, it may receive an active reply context. In that mode, the final answer should go back through the original broker conversation instead of creating a new send. The reply context looks like: ```ts interface ScoutReplyContext { mode: "broker_reply"; fromAgentId: string; toAgentId: string; conversationId: string; messageId: string; replyToMessageId: string; replyPath: "final_response" | "mcp_reply"; action?: "consult" | "execute" | "summarize" | "status" | "wake"; } ``` Rules: - first publish a short broker-visible acknowledgement in the same conversation when starting work - if `replyPath` is `final_response`, the harness final assistant message is the broker-visible reply - if `replyPath` is `mcp_reply`, use the provided reply tool for the initial acknowledgement and the final answer - do not use `messages_send` or `ask` for the final answer to the original request - `messages_reply` is a normal threaded message in the existing reply context; it should not create a fresh ask or owned work lifecycle - quiet delivery is an optional message modifier/policy, not a distinct reply mode - use Scout tools only to ask or delegate while solving the request ### Durable Work If the interaction needs ownership, progress, waiting, review, or done states, represent that as a work item rather than stretching a simple ask. Use work updates for material transitions: ```ts work_update({ work: { workId: "work-...", state: "working", progress: { percent: 40, summary: "Runtime path mapped; tests pending." } } }) ``` Questions answer information. Work items carry ownership. ## Routing Rules - One explicit target means DM. - The default target should be the base agent or project identity. Harness, model, profile, node, and session details are instance constraints, not a different base agent, unless the caller explicitly asks for a specialized profile. - If no concrete agent/session is known, route work by project path instead of running discovery just to invent a target. - Group coordination requires an explicit channel. - Shared broadcast is opt-in. - Message body text is payload, not routing metadata. - Prefer explicit routing fields over body mentions. - Preserve follow-ups in the same conversation, thread, question, or work item. - If a target is ambiguous, fail closed or ask one concise clarification. - If sender identity is missing, establish a stable sender binding before routing. - The broker should coach the sender with candidates, likely intent, and remediation commands instead of returning bare "not found" or "unavailable" errors when it has enough context to guide the next step. Do not rely on body mentions for routing: ```ts // Avoid: target is only text payload. messages_send({ body: "@hudson can you check this?" }) // Prefer: target is explicit, body stays payload. messages_send({ targetLabel: "@hudson", body: "Can you check this?" }) ``` ## Composer Route Operator Human-facing composers can use `>>` as a route operator when `@` would collide with host autocomplete or mention systems. The operator is input sugar for explicit routing fields; clients should strip it from the body before handing the request to the broker. Typed: ```text /scout:ask >> hudson Review the parser. /scout:ask >> ref:8kj4pd Continue from that result. /scout:ask >> project:../talkie Compare auth. /scout:send >> channel:ops Status is green. ``` Broker-facing shape: ```ts ask({ to: "hudson", body: "Review the parser." }) ``` The route target grammar is: | Input | Structured Target | | --- | --- | | `>> hudson` | `{ kind: "agent_label", label: "hudson" }` | | `>> agent:hudson` | `{ kind: "agent_label", label: "hudson" }` | | `>> ref:8kj4pd` | `{ kind: "binding_ref", ref: "8kj4pd" }` | | `>> project:../talkie` | `{ kind: "project_path", projectPath: "../talkie" }` | | `>> id:agent-...` | `{ kind: "agent_id", agentId: "agent-..." }` | | `>> channel:ops` | `{ kind: "channel", channel: "ops" }` | | `>> broadcast` | `{ kind: "broadcast" }` | The shared parser can recognize direct agent ids for clients that pass `targetAgentId`. CLI composer routing currently uses labels, refs, and project paths for asks; `channel:` and `broadcast` are send/update routes. `@agent` remains valid compatibility syntax where a surface owns the text box. For new Scout-aware composers, prefer `>>` for target entry and render the resolved target with the Scout contact mark, such as `⌖ hudson`. If routing cannot complete safely, a client should render the broker's dispatch or remediation result rather than guessing. `ScoutDispatchRecord` covers `ambiguous`, `unknown`, `unparseable`, and `unavailable` targets, including candidates or wake/register/retry guidance when available. Good failure shape: ```text @hudson#codex resolved to codex-hudai.main.air-local, but no compatible Codex session is attached. I found a Claude session for the same project. Try: scout session start --agent codex-hudai --harness codex ``` Bad failure shape: ```text error: no explicit destination ``` ## Receipts And Delivery State A delivery receipt means the broker accepted the request and wrote or planned broker-owned records. It does not mean the target read the message, completed the task, or accepted the result. Delivery state is layered: | State | Meaning | | --- | --- | | `accepted` | local broker journaled the envelope and may still need to forward | | `queued` | target is known, but dispatch or compatible endpoint readiness is pending | | `waking` | Scout is starting or resuming a compatible harness session | | `peer_acked` | remote broker journaled the envelope | | `running` | target agent claimed the flight or work | | `waiting` | target agent or broker is blocked on a named dependency | | `completed` | terminal success for that delivery/flight layer | | `deferred` | retry window is still open | | `failed` | terminal failure with failure metadata | | `cancelled` | cancelled before completion | `peer_acked` is especially easy to overread. It means the remote broker has the envelope, not that the remote agent has finished the work. For semantic completion, look for the reply message, flight update, work item transition, or collaboration event that matches the workflow. For local harness-backed agents, a receipt may be followed by session wake or attachment. If the target is known but no compatible session exists, Scout should either start/attach one according to wake policy or return a dispatch/lifecycle failure that names the missing session and harness. ## Coordination Cost Scout should make coordination cost visible to developers and maintainers, especially protocol overhead: the tokens Scout consumes or generates to route, wrap, diagnose, summarize, attach, wake, or coach around a task. This should be internal telemetry first, not a user-facing scoreboard. Keep it separate from harness execution usage: the tokens Claude, Codex, or another model spends doing the delegated work. Where harnesses expose usage, broker records should preserve prompt, completion, and total token counts linked to the relevant session, endpoint, message, invocation, flight, or work item. Each record should label the source as `protocol_overhead`, `harness_execution`, or another explicit category. Where exact usage is unavailable, Scout may store estimates labeled as estimates. Cost accounting should include the broker's own diagnostic/coaching work when it spends extra reasoning to avoid sender-side retry loops. This lets Scout compare one smarter broker response against repeated `who`, `latest`, `ps`, and failed handoff attempts across many agents. Track the value mix, not only the total. Low-value protocol tokens include repeated "who am I," "who is up," "how do I create a card," and other boilerplate orientation. High-value protocol tokens include useful onboarding, feature guidance, concise recovery coaching, and context that lets the next agent do better work. Do not turn this into transcript warehousing. Store usage metadata, references, source categories, and compact summaries, not full harness-owned conversations. ## Scout Contact Line Some surfaces need a tiny first-line cue for inbound Scout-mediated work. The contact line is generated from structured records; it is not the protocol. Default grammar: ```text ⌖ : ``` Examples: ```text ⌖ art ≔ ask:8kj4pd ⌖ art ↦ task:8kj4pd ⌖ art ≈ summary:8kj4pd ⌖ art ⟲ status:8kj4pd ⌖ art · wake:8kj4pd ``` Meanings: | Operator | Intent | Meaning | | --- | --- | --- | | `≔` | `ask` | inbound ask; reply expected | | `↦` | `task` | delegated or assigned work | | `≈` | `summary` | summarize or synthesize | | `⟲` | `status` | status check or check-in | | `·` | `wake` | wake, nudge, or attention ping | `⌖` means Scout-mediated contact. The short reference should usually be the last useful suffix of the broker `messageId`, with full ids available in a debug or collapsed context view. Do not parse the contact line for routing; use the structured context fields. When the contact cue is rendered next to payload text, use ` › ` as the payload lead-in so previews and single-line host surfaces keep the boundary: ```text ⌖ art ≔ ask:8kj4pd › I am writing a Hermes... ``` ASCII fallback: ```text scout art ask:8kj4pd ``` Screen-reader labels should expose the plain meaning, such as "Scout ask from art, reference 8kj4pd." ## Client Checklist When building a Scout client or plugin: - read from broker-owned records rather than external harness transcripts - send target, channel, reply, and work ids as explicit fields - keep message body as payload - preserve `conversationId`, `messageId`, `replyToMessageId`, and `flightId` across replies and status views - distinguish message receipts from invocation/work lifecycles - show stale, waiting, failed, and cancelled states explicitly - distinguish broker acceptance, peer acknowledgement, agent completion, and requester acceptance - expose session ids and harness mismatch diagnostics when runtime wake fails - render dispatch/remediation results when targets are ambiguous, unknown, or unavailable - prefer broker-authored guidance over forcing agents to rediscover routing state with manual `who` / `latest` loops - keep full ids available for debugging even when the visible UI uses short refs - do not promise exactly-once delivery, consensus, or complete transcript replication ## Where To Look In Code | Need | Path | | --- | --- | | Conversation types | `packages/protocol/src/conversations.ts` | | Message types | `packages/protocol/src/messages.ts` | | Invocation and flight types | `packages/protocol/src/invocations.ts` | | Delivery request and receipt types | `packages/protocol/src/scout-delivery.ts` | | Dispatch and routing target types | `packages/protocol/src/scout-dispatch.ts` | | Reply context type | `packages/protocol/src/scout-reply-context.ts` | | Composer route parser | `packages/protocol/src/scout-composer.ts` | | Runtime broker implementation | `packages/runtime/src/scout-broker.ts` | | Local-agent prompt projection | `packages/runtime/src/local-agents.ts` | ## Related Docs - `docs/architecture.md` - `docs/agent-identity.md` - `docs/runtime-sessions.md` - `docs/collaboration-workflows-v1.md` - `docs/agent-integration-contract.md` - `docs/data-ownership.md` - `docs/eng/sco-014-broker-owned-routing-and-context.md` - `docs/eng/sco-017-scout-broker-reply-context.md` - `docs/eng/sco-019-lightweight-mission-channels.md` - `docs/eng/sco-026-scout-comms-grammar-and-semantic-hints.md` --- ## docs/mcp-api-posture.md # Scout MCP API Posture Status: current v0 product guidance. This is not a frozen public API contract. Scout's MCP surface should feel like one broker API, not a pile of internal record constructors. Agents should be able to ask for work, send updates, and reply durably without understanding cards, sessions, invocations, or delivery planning first. ## Core Agent API These are the tools normal agents should learn first: | Tool | Purpose | | --- | --- | | `whoami` | Identify the current broker actor and working-directory context. | | `ask` | Request work, investigation, review, or a reply. This is the only work-creation front door. | | `messages_send` | Send a durable tell/update when no owned work or reply is expected. | | `messages_reply` | Send a normal threaded reply in an existing Scout reply context. | | `work_update` | Update progress, waiting, review, done, or cancellation for an existing work item. | `ask` may create message, invocation, flight, delivery, card, session, and work records as side effects. Those records are broker-owned implementation details unless the caller is explicitly observing or managing them. Timeout-style fields on MCP tools are caller wait budgets only. They protect a tool call or host connection from staying open indefinitely; they do not cancel broker work, mark a flight failed, or define protocol completion. When the caller knows the project but not the concrete agent, use `ask({ projectPath })`. The broker resolves or creates the concrete instance for that project. Do not make the caller run discovery just to invent a target. `messages_reply` is the threaded-message form of `messages_send`. It should preserve the ask conversation instead of creating a fresh ask. Quiet or send-without-notification behavior belongs as an optional message modifier or agent/session policy, not as a separate reply primitive. Use `ask` only when there is a new request or ownership lifecycle. Implementation target: reply delivery should route through the same broker delivery planner as normal messages so threaded replies can notify or wake according to target policy. A direct message write that only records history is too quiet for actionable follow-ups. ## Quiet Delivery Message and reply quieting should be a shared optional delivery modifier, not a separate message kind and not a different reply primitive. Quiet delivery still writes the durable conversation record, but suppresses notify/wake side effects where the target policy permits it. `ask` should not have a quiet variant: asking creates a lifecycle. ## Observation Handlers These tools observe records created by `ask`; they do not create work: | Tool | Purpose | | --- | --- | | `invocations_get` | Fetch the current state for a known ask flight. | | `invocations_wait` | Wait briefly for a known ask flight to change or finish. | | `broker_feed` | Inspect broker-native messages, delivery, dispatch, unblock, and error records. | `invocations_ask` is not an agent-facing front door. An ask creates invocations as a side effect; invocation records then have observation handlers. ## Routing Helpers Routing helpers are optional. They are useful when the broker reports ambiguity or when a user is inspecting available agents, but they are not mandatory preflight steps: | Tool | Purpose | | --- | --- | | `agents_search` | Search likely targets for a human or advanced integration. | | `agents_resolve` | Resolve one ambiguous label into one concrete target. | Prefer direct `ask`, `messages_send`, or `messages_reply` calls with explicit fields. Message body text remains payload, not routing metadata. ## Pro Integration API Some agents and host integrations know Scout deeply enough to manage identity and runtime infrastructure directly. These tools belong to that pro integration layer: | Tool | Purpose | | --- | --- | | `card_create` | Create a reply-ready identity/return-address record. | | `agents_start` | Start or create a concrete local agent session. | | `session_attach_current` | Attach the current host session to Scout. | These are real and useful tools, but they should not be the default way to talk to another agent. Core agents should use `ask({ projectPath })` and let the broker create or bind cards and sessions when needed. ## Identity Model The base agent identity is the vanilla project/workspace identity. Harness, model, profile, node, and session details are constraints on a concrete instance of that identity. Specialized profiles may become more important over time, such as a project agent with an investigator profile and a dedicated tool set. That is an advanced specialization layered onto the base project identity, not the normal routing path. --- ## docs/runtime-sessions.md # Runtime Sessions Scout began as a local communications layer: find the other sessions already running, route messages between them, and preserve enough broker state that humans and agents did not have to paste context by hand. That is still true, but it is no longer the whole contract. Scout also owns local harness orchestration for developer pilots. It can start, attach, wake, and monitor Claude, Codex, and future harness sessions. This document names the runtime semantics that make that deterministic. Status: v0 product direction. Update this page before changing user-facing CLI, MCP, skill, or broker semantics around harness lifecycle. ## Core Nouns | Noun | Meaning | | --- | --- | | Agent | Stable addressable identity, such as `hudson.main.air-local` | | Session | A concrete harness conversation/process/thread that can receive work | | Endpoint | The routable attachment between one agent identity and one session | | Invocation | A broker-owned request for an agent to do something | | Flight | The lifecycle state for an invocation | | Card | A shareable identity and return address; not by itself a running session | Use **session** as the public noun. Avoid introducing a separate user-facing `thread` concept unless a specific harness forces it; map harness thread ids into Scout session metadata instead. ## Invariants 1. A card creates or describes identity. It must not imply that a harness session is running unless the command explicitly starts one. 2. A session is always harness-specific. A Codex session cannot satisfy a Claude endpoint, and a Claude session cannot satisfy a Codex endpoint. 3. An endpoint must declare `agentId`, `harness`, `transport`, `sessionId`, `state`, wake policy, and whether it is the preferred endpoint for that agent/harness pair. 4. A broker receipt means the broker accepted and recorded the request. It does not mean a harness session has completed the work. 5. Every user-visible delivery or invocation should return durable ids that can be referenced later. A message receipt returns `conversationId` and `messageId`. An invocation receipt returns `conversationId`, `messageId`, `invocationId`, and `flightId`. A work handoff also returns `workId`. 6. If Scout cannot start, attach, wake, or route to a compatible session, it must fail with a specific reason and a concrete remediation. Silent parked limbo is a product bug. 7. The broker should do the routing work or coach the sender toward the next viable action. Do not make agents run a long orientation ritual just to discover that a target needs a session, a qualifier, or an attach operation. ## Broker Coaching Scout should lean on the broker, not the sender, to explain runtime and routing state. The product assumes abundant local cognitive capacity; spending extra reasoning in the broker is preferable to making every user or agent rediscover topology by hand. When a sender tries a reasonable command such as: ```bash scout ask --to codex-hudai "Review this." ``` the broker should infer the likely intent, inspect identity/session/endpoint state, and return one of: - accepted receipt with ids and the active endpoint/session - accepted receipt plus wake/start/attach progress - dispatch result with candidates and a recommended fully qualified target - lifecycle failure with the failed layer, reason, and exact remediation command Avoid sender-hostile errors such as "could not find target" when Scout has enough context to say something more useful. Prefer: ```text No active Codex session is attached to codex-hudai. I found a Claude session for the same project: relay-hudson-claude. Start a compatible session: scout session start --agent codex-hudai --harness codex ``` The sender may still use `who`, `latest`, or `session inspect` for debugging, but those should be follow-up tools, not required preflights for ordinary agent communication. ## Endpoint State Endpoint state is the broker's best current view of a routable attachment. Keep flight state separate from endpoint state: an endpoint can be `idle` while a particular flight is `waiting`, or `waking` while multiple queued flights are pending. | State | Meaning | | --- | --- | | `registered` | identity and endpoint metadata exist, but no live session is attached | | `attaching` | Scout is binding an endpoint to an existing compatible session | | `waking` | Scout is starting or resuming a compatible harness session | | `idle` | attached session is reachable and ready for work | | `working` | attached session has claimed at least one active flight or work item | | `unreachable` | endpoint is known, but the broker cannot currently contact it | | `failed` | endpoint setup or wake failed with a recorded reason | | `stale` | session reference exists, but the broker believes the harness process or provider thread is no longer current | | `stopped` | endpoint was intentionally detached or stopped | Allowed transitions should be explicit in protocol/runtime code. The expected happy path is `registered -> waking -> idle -> working -> idle`. Failure paths should preserve the failed layer and remediation, for example `waking -> failed` with `reason: "harness_mismatch"`. ## Cardinality And Selection One agent identity may have multiple sessions over time and may have multiple endpoints when different harnesses, transports, machines, or worktrees are valid. The broker must not make the sender guess which one matters. Routing selection should prefer: 1. exact agent id plus exact harness/session requested by the command 2. the preferred endpoint for that agent/harness pair 3. the most recent reachable compatible endpoint 4. a dispatch result that lists candidates and the recommended fully qualified retry If more than one compatible endpoint is active and none is preferred, the result is ambiguous, not silently random. ## Session Persistence Session records survive broker restarts as coordination metadata, but that does not mean the underlying harness is still alive. - `resumable`: provider metadata says Scout can reattach or resume - `observed_stale`: a prior session exists but the broker has not confirmed it is reachable - `terminal`: the session was stopped, failed permanently, or belongs to an incompatible harness/profile After restart, Scout should mark uncertain sessions as `stale` or `observed_stale` until an endpoint health check, attach, or wake operation confirms reachability. ## Token And Coordination Accounting Scout should track the cost of coordination, not just the state of coordination. This is not billing infrastructure, enterprise metering, or a user-facing scoreboard. It is developer-facing product telemetry for local pilots: what did running through the Scout protocol add, and did that protocol overhead reduce total cognitive work elsewhere? Separate two ledgers: - **Protocol overhead:** tokens Scout consumes or generates to route, wrap, diagnose, summarize, annotate, wake, attach, or coach around the core task. - **Harness execution:** tokens spent by Claude, Codex, or another model doing the actual delegated work. This section is primarily about protocol overhead. Harness execution usage is useful context, but it should not be blended into the cost of the Scout protocol itself. Minimum useful accounting: - prompt, completion, and total tokens for Scout-authored protocol prompts, wrappers, diagnostics, and summaries when a harness exposes them - estimated tokens when exact usage is unavailable, with `usageSource` such as `provider_exact`, `tokenizer_estimate`, `char_heuristic`, or `manual_estimate` - model and harness for each counted turn - value class for protocol overhead: - `boilerplate`: repeated identity, topology, or command-discovery text - `routing`: target resolution, dispatch, delivery, and receipt wrapping - `diagnostic`: explaining failed or incomplete broker/runtime state - `onboarding`: teaching an agent a new Scout capability or contract - `feature_guidance`: coaching toward a better command or workflow - `work_context`: useful task context carried by Scout around the request, excluding the target harness's own execution tokens - broker-side diagnostic effort, including non-token counters such as `diagnosticGenerated`, `dispatchAttemptCount`, `wakeFailureCount`, and `orientationCommandsAvoidedEstimate` - avoided retry/orientation loops when the broker directly resolves or coaches a sender - ids linking usage to `sessionId`, `endpointId`, `conversationId`, `messageId`, `invocationId`, `flightId`, and `workId` The goal is trend visibility, not per-message guilt or end-user interpretation. Internal reports should answer questions like: - how many tokens did the Scout protocol add before the target harness began the real work? - how many tokens did Scout generate in receipts, routing context, reply context, diagnostic text, and status summaries? - are low-value boilerplate tokens trending down? - are high-value guidance tokens, such as agent onboarding and feature coaching, replacing repeated orientation chatter? - did broker coaching reduce repeated `who` / `latest` / `ps` loops? - which agents or sessions are spending the most context on coordination? - where do harness wake failures create expensive human or agent retries? - when is a smarter broker response cheaper than sender-side rediscovery? Accounting records should stay lightweight, mostly internal, and broker-owned. Do not bulk-import full harness transcripts to compute them; store usage numbers, estimates, references, summaries, and a source label such as `protocol_overhead` or `harness_execution`. The optimization target is not "fewer tokens everywhere." It is better token mix: fewer low-value tokens spent on repeated identity checks, topology discovery, card instructions, and command rediscovery; more high-value tokens spent on onboarding agents, explaining new features, preserving useful context, and coaching recovery from real state transitions. ## Session Operations These are the semantics Scout should expose consistently across CLI, MCP, UI, and skills. Command names may evolve, but the behavior should not be ambiguous. | Operation | Meaning | | --- | --- | | `session start` | Create a new concrete harness session for an agent | | `session attach` | Attach an agent endpoint to an existing harness session | | `session list` | Show known sessions and endpoint attachments | | `session stop` | Stop or detach a concrete session | | `session inspect` | Explain the agent/session/endpoint state and last error | Expected CLI shape: ```bash scout session start --agent hudson --harness codex scout session attach --agent hudson --harness codex --session scout session inspect --agent hudson --harness codex ``` `scout up` may remain as a friendly alias, but internally it must resolve to a session operation and print exactly what it did. ## Card Semantics `scout card create` is an identity and return-address operation. It should answer: - what agent identity was created or reused - what project/worktree it points at - what harness profile is configured - whether a compatible session is already attached - how to start or attach a session if none exists It should not silently bind `--harness codex` to a Claude session. If a previous profile exists for a different harness, Scout should either create a separate Codex profile or reject the mismatch with a clear remediation. Some cards are intentionally disposable. Agent-hosted MCP `card_create` calls default to a one-time reply address because review, probe, and handoff agents often need a fresh return path without becoming permanent directory entries. One-time cards carry lifecycle metadata (`kind: "one_time"`, creator, expiry, and max uses), are retired after a peer uses their direct conversation, and are pruned by retention so older disposable cards do not crowd `who`/search results. Manual CLI cards remain persistent unless created with `scout card create --one-time`; `scout card cleanup` retires expired or overflow one-time cards. When a caller asks a concrete `projectPath` and no card already resolves for that project, the broker may create the one-time card itself, accept the work against that generated identity, and prune older one-time cards for the same sender/project. ## Ask Targets And Reply Sessions An ask has two different routes: - the work target, which is either a reusable `targetSessionId` or an agent/project target that can create a fresh session - the return target, which may be a concrete requester `sessionId` Use `targetSessionId` when the sender wants to keep building context in one existing harness session over many turns. Repeating the session id means "continue here"; omitting it means Scout may route by agent/project and create the lightest usable fresh session for the request. Use exact `agentId` or project routing when the sender knows who should own the work but does not need prior context. That path should stay cheap and throwaway: Scout can create or choose an ephemeral session/card as needed, and the sender does not need to ask for a new session explicitly. When the sender wants the answer to land back in one specific live harness session, the ask should carry `replyToSessionId`. The broker records that session on the requester's return address for the message and invocation. This keeps "reply to my current session" separate from long-lived agent identity: cards crystallize reusable identity/profile parameters, while session ids point at one concrete reply destination. ## Message And Work Semantics The old "tell means no reply needed" wording is too weak for agent experience. Agents need two separate signals: a broker receipt that proves Scout accepted and recorded the interaction, and a target-authored acknowledgement that the receiving agent has started working. Use this model instead: | Interaction | Use When | Required Result | | --- | --- | --- | | Message | Status, update, note, or channel post | Broker receipt with ids | | Invocation | Question, review, investigation, or owned work | Broker receipt plus flight ids, then target acknowledgement and later completion in the same conversation | | Work item | Durable multi-step ownership | Work id plus progress states | The CLI verbs can remain `send` and `ask` for compatibility, but docs and skills should teach them as: - `send`: post a message and return a durable receipt - `ask`: create an invocation, return a durable receipt plus lifecycle state, and let the target acknowledge quickly before final completion No route should depend on fire-and-forget behavior. Even a channel post should have a receipt. ## Wake And Delivery When a known on-demand agent has no active compatible session: 1. The broker records the message or invocation. 2. The runtime resolves the requested harness/profile. 3. If wake policy allows, Scout starts or attaches a compatible session. 4. The endpoint transitions through `waking` to `idle` or `working`. 5. Queued flights for that agent/session compatibility drain automatically. If any step fails, the flight must move to `failed` or a clearly explainable `waiting` state. The error should name the failed layer: ```text codex-hudai is registered, but has no active codex session. Wake policy: on_demand. Start failed: configured profile points at Claude session relay-hudson-claude. Run: scout session start --agent codex-hudai --harness codex ``` ## Agent-Facing Defaults Agents should not have to reason about the entire runtime graph for ordinary coordination. The happy path stays small: ```bash scout ask --to hudson "Review this and report back." scout send --to hudson "Heads up: I am taking the runtime side." scout who scout latest ``` When those commands fail, the failure must expose enough session detail that an agent can recover without guessing or asking the human to manually relaunch a known target. ## Compatibility Target Future CLI, MCP, and skill updates should converge on these names: | Concept | CLI | MCP / API | | --- | --- | --- | | Start a session | `scout session start ...` | `sessions_start` | | Attach a session | `scout session attach ...` | `sessions_attach` | | Inspect runtime state | `scout session inspect ...` | `sessions_inspect` | | Message receipt | `scout send ...` | `messages_send` | | Ask receipt | `scout ask ...` | `ask` | Old commands should continue to work while emitting behavior that maps cleanly onto these semantics. --- ## docs/data-ownership.md # Data Ownership OpenScout is a control plane, not a transcript warehouse. Its storage model starts with a simple boundary: Scout owns the records it creates or routes, and observes external harness records without importing them wholesale. This matters for product scope, operator trust, and system design. The broker should make agent coordination durable without pretending to become the canonical database for every model turn written by Claude Code, Codex, or any future harness. ## What Scout Owns Scout owns first-party control-plane records: - nodes, actors, agents, endpoints, and bindings registered with the broker - conversations, messages, forwards, and replies created through Scout - invocations, flights, deliveries, delivery attempts, and dispatch records - collaboration records such as questions and work items when they are created through Scout - local read models and activity projections derived from those first-party records These records are broker-owned facts. They can be persisted, replayed, projected into SQLite, forwarded across mesh peers, and shown consistently across CLI, desktop, mobile, and agent tools. ## What Scout Observes Scout observes external harness source material: - Claude Code transcript JSONL - Claude Code team, task, subagent, and session topology when available - Codex session JSONL - Codex subagent, thread, and custom-agent topology when available - harness-specific logs, turn streams, and file-backed history - process and filesystem signals that help explain what is running now These sources are not Scout-owned conversation state. Scout may discover them, tail them, summarize them, link to them, index lightweight metadata, or expose live views over them. Scout should not bulk-copy external transcript turns into its control-plane database and treat them as first-party messages. For harness-owned ecosystems such as Claude Code's `.claude` files, the boundary is stricter than "do not bulk-import": adapters should not write there at all. They may inspect what the harness exposes locally, but creating or modifying harness agents, teams, task lists, or MCP settings is outside adapter runtime behavior. Any host setup that changes a harness configuration must be an explicit operator action, not something an adapter does while observing or driving a session. ## Current Posture The intentional split today is: - the broker journal records Scout-owned control-plane facts - SQLite stores query projections of Scout-owned facts for local surfaces - tail adapters read external harness transcripts from their original files - tail views keep bounded live/backlog buffers rather than becoming durable transcript replicas If a surface needs raw harness detail, it should prefer the original harness material through an adapter, cursor, or link. If a workflow needs durable coordination, it should create a Scout-owned message, invocation, flight, delivery, or work item. ## Design Rules 1. Do not make Scout the canonical store for external harness transcripts. 2. Do not persist every observed harness turn as a Scout `message`. 3. Do persist Scout-originated and Scout-routed coordination records. 4. Do use lightweight metadata, cursors, summaries, and links when external source material needs to appear in Scout surfaces. 5. Do not let adapters mutate harness-owned ecosystems such as Claude Code's `.claude` state. 6. Do keep the boundary visible in docs and APIs: `message` means a Scout conversation record, while `TailEvent` means an observed harness event. This is an intentional product and architecture boundary, not just a current implementation shortcut. Scout may grow better indexing and replay tools over time, but those should preserve the distinction between owned coordination state and observed harness source material. --- ## docs/agent-integration-contract.md # Agent Integration Contract This page is for coding agents, agent runtimes, and adapter authors that want to plug into OpenScout without first learning the whole product. OpenScout is a local-first broker. The integration contract is simple: identify yourself, register how you can be reached, send messages and invocations through the broker, and report enough lifecycle state that humans and other agents can understand what is happening. Status: v0 integration guidance. This is the contract OpenScout is intentionally converging on for local developer pilots, not a frozen public API or enterprise compatibility guarantee. Treat changes to these semantics as product-significant and update this page when they move. ## Integration Goals A good Scout integration should let an agent: - have a stable address - receive a durable message with a broker receipt - receive an invocation/work handoff with a lifecycle handle - reply in the same conversation - expose current status and reachability - expose or attach a concrete harness session - report work lifecycle state through flights or collaboration records - ask the human for input without trapping the request inside one harness UI - receive broker-authored guidance when routing or runtime state is incomplete, instead of having to rediscover topology manually ## Minimum Contract At minimum, an integration needs five pieces. ### 1. Identity The agent needs a stable Scout identity. Human-facing text usually uses a short handle such as `@hudson`, but the broker resolves that to one exact target. Use [`agent-identity.md`](./agent-identity.md) for the full grammar. The important fields are: - `definitionId`: the base agent/project name - `workspaceQualifier`: branch, worktree, or project variant when needed - `harness`: Codex, Claude, or another backend - `model`: model family or concrete model when relevant - `node`: machine or broker authority ### 2. Reachable Endpoint The broker needs to know how to reach the agent. A reachable endpoint records: - agent id - authority node - harness - transport - session reference - current reachability/status - optional permission profile and wake policy The endpoint is a route, not the agent's personality. An agent can move between sessions or machines while retaining a stable identity. Endpoint state should describe the attachment, not a specific task. Use states such as `registered`, `attaching`, `waking`, `idle`, `working`, `unreachable`, `failed`, `stale`, and `stopped`; keep task lifecycle in flights or work items. If several endpoints match, the broker should choose the preferred compatible endpoint or return an ambiguity diagnostic with candidates. ### 3. Runtime Session A session is a concrete harness conversation/process/thread that can receive work. Use **session** as the public noun across CLI, MCP, docs, and skills. Map provider-specific thread ids into session metadata rather than teaching agents a separate top-level noun. Session invariants: - sessions are harness-specific - endpoints must not bind a requested Codex harness to a Claude session, or the reverse, unless an explicit adapter exists - `card create` creates identity and return-address metadata; it does not imply a running session unless a command explicitly starts one - short-lived agent-created cards should be one-time reply addresses by default, with expiry and cleanup metadata, instead of permanent directory identities - exact session asks should route work by `targetSessionId` to continue context; asks without a target session may route by agent/project and create the lightest usable fresh session/card - project-path asks do not require a caller-created card first; if no card resolves for that project, the broker can create a one-time card as part of accepting the work - when the sender needs a concrete live reply destination, carry `replyToSessionId` rather than minting another card - `up` / wake behavior must resolve to start or attach semantics and report the chosen session id - incompatible, missing, or failed sessions must produce specific diagnostics and remediation, not silent hangs Read [`runtime-sessions.md`](./runtime-sessions.md) before changing harness startup, wake, card, or endpoint behavior. ### 4. Message Path Use the message path for communication: - `send`: durable update with a broker receipt, no tracked work lifecycle - DM: one explicit target - channel: group coordination - shared broadcast: only when the audience is intentionally broad Do not hide routing instructions in the body when structured target fields are available. The broker should know the target as metadata, not by parsing prose. Even message-only interactions should return stable ids such as `conversationId` and `messageId`. Treat "fire and forget" as a UI affordance, not the underlying contract. ### 5. Invocation Path Use the invocation path for work: - `ask` creates an invocation - the invocation creates a flight - the flight tracks queued, running, waiting, completed, failed, or cancelled - the final reply should land back in the same conversation or work context If work becomes blocked, report a waiting state with who or what owns the next move. ## Broker-Guided Routing The sender should not carry most of the routing burden. If a command names a reasonable target, the broker should resolve, disambiguate, wake, attach, or explain the next viable step. Adapters and clients should render broker diagnostics as first-class results: - ambiguous target -> show candidates and the best fully qualified retry - known identity without session -> show the needed `session start` or `session attach` command - harness mismatch -> name the requested harness, the attached session harness, and the exact remediation - peer unavailable -> report `unreachable` separately from generic `offline` - unknown target with nearby candidates -> suggest likely matches Avoid pushing agents into repeated `who` / `latest` / manual process inspection when the broker can produce useful guidance from its own state. ## Preferred MCP Tools Agents connected through Scout's MCP server should prefer: - `whoami` to identify the current sender and broker context - `agents_resolve` before sending to an ambiguous handle - `messages_send` for durable messages and updates - `broker_feed` to inspect one agent's broker-native messages, status, delivery, dispatch, unblock, and error records - `ask` for agent-to-agent work or requested replies - `invocations_get` and `invocations_wait` to monitor a flight - `work_update` for durable work-item progress, waiting, review, and completion - future `sessions_*` tools for explicit harness session start, attach, inspect, and stop operations Use `ask` for requested work. It returns a compact receipt and lets Scout resolve, route, and wake the target when possible. If the caller knows the project but not the concrete agent/session, pass `projectPath` instead of forcing a discovery loop. Invocation and flight records are created as side effects of the ask; use `invocations_get` and `invocations_wait` only to observe those records. Base identity is the vanilla project/workspace identity. Harness, model, profile, node, and session values describe a concrete instance or attachment constraint on that identity; they should not be treated as new base agents unless the caller is intentionally selecting a specialized profile. Card creation, explicit registration, and session attachment belong to the pro integration layer. They are appropriate for hosts and Scout-native agents that need to manage durable return addresses or sticky sessions directly, but they are not the default way to ask another agent for work. ## Collaboration Semantics Scout separates information, execution, and communication: - message: "say this" - question: "answer this" - invocation/flight: "do this and track the lifecycle" - work item: "own this durable piece of execution" Do not turn every chat into a work item. Do not bury owned work in a plain message when the system needs progress, waiting, review, or completion state. Read [`collaboration-workflows-v1.md`](./collaboration-workflows-v1.md) for the full model. ## Human Input And Permissions Agents should surface human dependencies as first-class state, not as terminal text that another surface cannot see. Use the narrowest available mechanism: - for an agent question, emit or call the question path - for an action approval, emit an approval/action state - for durable work blocked on a person, update the work item to `waiting` - for host-level permission prompts, forward the host prompt into Scout as an operator attention or unblock request when that host integration exists Important boundary: an MCP server cannot see a client-side permission prompt that the MCP host intercepts before calling the server. Codex, Claude, or another host must forward that prompt through a host-side hook for Scout to capture it. See [`operator-attention-and-unblock.md`](./operator-attention-and-unblock.md). ## Data Boundary Do not bulk-copy external harness transcripts into Scout as first-party messages. Scout-owned records are coordination facts: messages, invocations, flights, deliveries, bindings, and work items created through Scout. Harness-owned records such as Claude Code or Codex JSONL remain source material owned by the harness. Integrations may link to, tail, summarize, or index lightweight metadata from harness logs. They should not make Scout's control-plane database the canonical transcript warehouse for every external turn. Adapters must not write into a harness-owned ecosystem. For Claude Code, that means `.claude` project state, subagent definitions, agent-team config, task files, and MCP settings are read-only observation surfaces for adapters. Scout can inspect those surfaces to model reachability and topology when the harness makes them available, but it must not author or repair them on Claude's behalf. Host setup commands that intentionally install Scout into a harness are separate, explicit operator actions, never adapter runtime behavior. Read [`data-ownership.md`](./data-ownership.md). Read [`eng/harness-topology-observation.md`](./eng/harness-topology-observation.md) for the shared observed-topology shape. ## Token And Cost Metadata Integrations should report token usage when the harness or model provider makes it available. Separate Scout protocol overhead from harness execution usage. Protocol overhead means tokens consumed or generated by Scout routing, wrapping, reply context, diagnostic/coaching text, summaries, wake/attach prompts, or other coordination work around the task. Harness execution means tokens spent by the target model doing the delegated work itself. Report: - prompt tokens - completion tokens - total tokens - model - harness - source category such as `protocol_overhead` or `harness_execution` - value class such as `boilerplate`, `routing`, `diagnostic`, `onboarding`, `feature_guidance`, or `work_context` - usage source such as `provider_exact`, `tokenizer_estimate`, `char_heuristic`, or `manual_estimate` - session id - related Scout ids such as message, invocation, flight, or work item - non-token counters such as dispatch attempts, wake failures, generated diagnostics, and estimated orientation commands avoided When exact usage is unavailable, integrations may report estimates, but the record must mark them as estimated and say how they were estimated. Scout uses this accounting as internal product telemetry to understand protocol overhead and evaluate whether broker-side coaching is reducing total agent/user effort over time. It is not a license to import full harness transcripts as Scout-owned data, and integrations should not expose raw usage numbers to end users unless a product surface explicitly asks for them. The desired trend is fewer low-value protocol tokens spent on repeated orientation and command rediscovery, and more high-value protocol tokens spent on useful onboarding, feature guidance, and targeted recovery coaching. ## Mesh Expectations Mesh means reachability and coordination across machines. It does not mean exactly-once delivery, replicated external transcripts, or global consensus. An integration should treat a remote Scout agent as reachable through broker routing when the broker says it has a route. It should still report delivery failures and waiting states honestly. ## Compatibility Checklist Before calling an integration "Scout-native", verify: - it has a stable agent identity - it registers or attaches a reachable endpoint - it has deterministic session start/attach/inspect semantics - it can receive a message - it can receive an ask and produce a flight result - it can reply without losing the original actor/conversation context - it reports failed and waiting states - it reports harness/session mismatches with actionable diagnostics - it guides senders with broker diagnostics instead of only returning opaque unresolved/unavailable errors - it does not require body mentions for normal routing - it does not import external transcripts as Scout messages - it documents its permission and wake behavior - it can recover or explain state after broker/session restart - it reports token usage or marked estimates when available --- ## docs/integrations.md # Host Integrations OpenScout's core broker, runtime, protocol, CLI, desktop app, and mobile app live in this repository. Host-specific integrations can live beside this repo when they are independently installable packages for another host's install surface. This keeps the OpenScout root focused on the product control plane while still making the integration surface discoverable. ## Current Integrations | Host | Repository | Page | Purpose | | --- | --- | --- | --- | | pi | [`arach/pi-scout`](https://github.com/arach/pi-scout) | [`arach.github.io/pi-scout`](https://arach.github.io/pi-scout/) | pi extension for Scout `send`, `ask`, `who`, and broker-backed coordination from pi sessions. | | Claude Code | [`arach/claude-scout`](https://github.com/arach/claude-scout) | [`arach.github.io/claude-scout`](https://arach.github.io/claude-scout/) | Claude Code plugin with `/scout:*` commands and Scout channel integration. | | Codex | [`arach/codex-scout`](https://github.com/arach/codex-scout) | [`arach.github.io/codex-scout`](https://arach.github.io/codex-scout/) | Codex plugin with Scout MCP tools and coordination guidance. | | Cursor | [`arach/cursor-scout`](https://github.com/arach/cursor-scout) | [`arach.github.io/cursor-scout`](https://arach.github.io/cursor-scout/) | Cursor MCP configuration and installer that points Cursor at `scout mcp`. | | Hermes Agent | [`arach/hermes-scout`](https://github.com/arach/hermes-scout) | [`github.com/arach/hermes-scout`](https://github.com/arach/hermes-scout) | Hermes plugin that bridges Scout MCP tools into Hermes sessions. | ## Relationship To This Repo Use links and install docs rather than git submodules by default. Submodules are useful when this repo must build, test, or vendor another repository at an exact commit. The current Scout host integrations do not need that coupling: they shell out to the installed `scout` CLI or talk to the local broker, and their compatibility boundary is the published Scout protocol and CLI behavior. Keep integration source in a separate repository when: - the host has its own plugin marketplace or install flow - the integration can be installed without cloning OpenScout - the package should have its own release cadence - the integration depends on Scout's public CLI/protocol surface rather than private app internals Keep integration source in this repository when: - it depends on unreleased internal code - it is still shaping the core protocol or broker API - local product development needs cross-package changes in one commit ## Local Development Recommended sibling checkout layout: ```text ~/dev/ ├── openscout/ ├── pi-scout/ ├── claude-scout/ ├── codex-scout/ ├── cursor-scout/ └── hermes-scout/ ``` That layout keeps the product repo clean while making related host integrations easy to work on side by side. --- ## docs/agent-identity.md # Agent Identity And Addressing This doc explains how Scout turns a human-friendly handle like `@hudson` into one exact Scout address for routing. Read it after [`quickstart.md`](./quickstart.md) when you want to understand what an agent name represents, why short names sometimes work, and when Scout needs more qualifiers. Every agent Scout can address has a name. When there is only one matching agent on one machine, the name is simple — `@arc` or `@hudson`. But agents multiply. The same project might run on two machines. The same workspace might have a main branch and a feature branch, each with its own agent. A project might use Claude for one task and Codex for another. The identity grammar exists to keep every target unambiguously addressable while still letting humans type the shortest useful name. The default target is the base project/workspace identity. Harness, model, node, and session details describe the concrete instance Scout routes to; they are not a different base agent unless the caller intentionally chooses a specialized profile. ## Base Agent Vs Instance A **base agent** is the vanilla project/workspace identity that agents should use when they do not care about a specific runtime. In practice this is the thing represented by a project path, such as `../talkie`, or by a short handle, such as `@talkie`. An **agent instance** is the concrete attachment Scout routes to for that base identity: a Claude or Codex harness, a model choice, a machine/node, and possibly a sticky session/thread. Asking for a specific instance should refine the route, not create the impression that `talkie#codex` and `talkie#claude` are separate base agents. Default rule: if the project is known but the exact agent/session is not, use project routing and let Scout pick or create the concrete instance: ```bash scout ask --project ../talkie "Review this." ``` ```ts ask({ projectPath: "../talkie", body: "Review this." }) ``` Specialized profiles may become first-class over time. For example, `@scout.profile:investigator` could name a profile with a dedicated tool set and instructions. That is a specialization layered onto the project identity, not the default routing model. ## Three Layers Scout separates identity into three layers, each serving a different audience: - **Canonical identity** is exact, stable, and system-owned. It includes every dimension needed to distinguish one agent from all others. Humans rarely type it, but the broker always stores it. - **Minimal unique identity** is the shortest address that still resolves to exactly one agent. Scout computes it automatically from the current set of online agents. When there is only one `hudson`, `@hudson` is enough. When two exist on different machines, `@hudson.node:mini` disambiguates. - **Alias** is a human-owned shortcut. `@huddy` maps to one specific identity. If the mapping becomes ambiguous, the alias is invalid until repaired. ## The Six Dimensions An agent identity combines up to six dimensions: | Dimension | What it captures | Example | |---|---|---| | `definitionId` | The base project or workspace | `arc`, `hudson` | | `workspaceQualifier` | A non-default worktree or branch | `super-refactor`, `main` | | `profile` | Optional specialization/persona, not the default route | `dev`, `investigator` | | `harness` | Instance execution backend | `claude`, `codex` | | `model` | Instance model family or concrete model | `sonnet`, `gpt-5-5` | | `node` | Instance machine or host | `mini`, `macbook` | The canonical form strings them together with dots: ```bash @[.][.profile:][.harness:][.model:][.node:] ``` In practice, most of these dimensions are omitted. You only include what is needed to resolve unambiguously. ## Examples From shortest to most qualified: | Address | What it resolves | |---|---| | `@arc` | The only `arc` agent currently online | | `@arc.main` | The `arc` agent on the `main` branch | | `@arc.super-refactor` | The `arc` agent on a feature worktree | | `@arc.main.harness:claude` | The Claude instance of `arc` on main | | `@lattices#codex?5.5` | Compatibility shorthand for the Codex instance of `lattices` on a 5.5 model | | `@lattices#claude?sonnet` | Compatibility shorthand for the Claude instance of `lattices` on Sonnet | | `@arc.super-refactor.harness:claude.node:mini` | Fully qualified: project, branch, harness, machine | ## Parsing and Normalization - `@` is required for body-mention compatibility in user-facing text. Internal systems can omit it, and Scout-aware composers may use the `>>` route operator instead, such as `/scout:ask >> hudson Review this.` - One positional qualifier (without a type prefix) is allowed after the definition ID — it is always treated as the workspace qualifier. - Typed qualifiers (`profile:`, `harness:`, `model:`, `node:`) may appear in any order during input. Scout normalizes them to canonical order on storage. - Shorthand `#` maps to `harness:`, and `?` maps to `model:`. - Segments are lowercased and kebab-cased: `Super Refactor` becomes `super-refactor`, `Mini.local` becomes `mini-local`. Dots are reserved as separators. These aliases are accepted during parsing and map to canonical dimensions: | Alias | Maps to | |---|---| | `branch:`, `worktree:` | `workspaceQualifier` | | `persona:` | `profile` | | `runtime:` | `harness` | | `#codex` | `harness:codex` | | `?sonnet` | `model:sonnet` | | `host:` | `node` | ## Resolution When you type `@hudson`, Scout resolves it against all known agents: 1. Check for an exact alias match first. 2. Match the parsed identity against registered candidates. 3. If exactly one candidate matches, resolve to it. 4. If zero or more than one match, return nothing — the name is either unknown or ambiguous. This keeps short names fast and ergonomic while requiring precision only when the situation demands it. ## Minimal Unique Identity Given a specific agent and its peers, Scout prefers the shortest address that uniquely identifies it. Dimensions are dropped in this order until removing the next one would create ambiguity: 1. `workspaceQualifier` 2. `profile` 3. `harness` 4. `model` 5. `node` If a configured alias is shorter than the minimal canonical form and resolves uniquely, Scout prefers it. **Example:** - Canonical: `@hudson.hudson-main-8012ac.node:arachs-mac-mini-local` - Minimal unique: `@hudson` (if only one hudson is online) - Alias: `@huddy` --- ## docs/collaboration-workflows-v1.md # Collaboration Workflows When agents work together — or when a human works with agents — every interaction carries an implicit question: is this a request for information, or a request for work? The difference matters because they have different lifecycles, different ownership semantics, and different definitions of done. Scout makes this distinction explicit with two collaboration workflows. ## Two Kinds of Collaboration | | Question | Work Item | |---|---|---| | **Goal** | Get information back | Get something built, fixed, or reviewed | | **Lifecycle** | Ask → answer → close | Assign → work → checkpoint → review → done | | **Duration** | Short | Long, potentially multi-turn | | **Ownership** | Rotates between asker and responder | Stays with assigned owner until handoff | These are peers, not stages in a pipeline. A question doesn't become a work item by getting complex — it spawns one. A work item doesn't need a question to exist — it can be self-originated. ## Why Two, Not One The broker already handles durable conversations and invocation tracking. But it doesn't yet express the semantic layer above routing: - Some interactions only need an answer. - Some interactions need ownership, waiting states, review, and completion tracking. - Some interactions start as questions and reveal real execution work along the way. Forcing all of these into one noun creates either ceremony (every question gets a kanban board) or ambiguity (is this "done" because someone replied, or because the work shipped?). ## Question Use a question when the goal is getting information back. **States:** `open` · `answered` · `closed` · `declined` A question can be closed immediately after an answer. It can also stay open if the asker is not satisfied — "answered" means someone responded, not that the asker agrees. If the answer reveals real execution work, the question spawns a work item rather than growing into one. ## Work Item Use a work item when the goal is durable execution, progress tracking, or multi-turn coordination. **States:** `open` · `working` · `waiting` · `review` · `done` · `cancelled` A work item can be self-originated, requested by another party, or spawned from a question. Progress tracking is optional but first-class — "3 of 7 steps complete" is a work item concern, never a question concern. The `waiting` state (preferred over "blocked") signals that the current owner cannot proceed until someone else acts. ## Acceptance Is Orthogonal Acceptance is separate from workflow state. This avoids collapsing "I replied" into "we both agree this is done." - A question can be `answered` but not yet `closed` — the asker has not confirmed satisfaction. - A work item can be in `review` with `acceptanceState=pending` — the reviewer has not weighed in. - A self-driven work item uses `acceptanceState=none` — there is no external reviewer. ## Ownership Every non-terminal collaboration record must have a `nextMoveOwnerId` — the party who needs to act next. This is the foundation of the sweeper, notification routing, and stale detection. Ownership transfers explicitly with each state transition. ### Required Fields | Field | Question | Work Item | |---|---|---| | `id` | yes | yes | | `title` | yes | yes | | `createdById` | yes | yes | | `ownerId` | yes | yes | | `nextMoveOwnerId` | yes | yes | | `createdAt` | yes | yes | | `updatedAt` | yes | yes | | `waitingOn` | — | yes | | `progress.completedSteps` | — | yes | | `progress.totalSteps` | — | yes | | `progress.summary` | — | yes | ## Sequences ### Question Flow 1. Asker creates a question 2. Scout routes it to a responder 3. Responder posts an answer → state becomes `answered` 4. Asker reviews and closes — or leaves open for follow-up ### Question That Spawns Work 1. Asker creates a question 2. Responder determines it needs execution, not just an answer 3. Scout creates a work item linked to the question 4. Asker sees both the answer and the spawned work item ### Work Item Flow 1. Creator opens a work item and assigns an owner 2. Owner moves to `working` and posts progress checkpoints 3. If blocked, owner moves to `waiting` and names the dependency 4. Scout nudges the next move owner 5. Once unblocked, work resumes 6. Owner moves to `review` when done 7. Creator accepts or reopens → on acceptance, state becomes `done` ## Sweeper The sweeper is an insurance policy, not a planner. It periodically inspects stale non-terminal records and nudges the current `nextMoveOwnerId` — the one party whose action would unblock progress. Rules: - Do not invent new work. - Do not reinterpret goals. - Do not ping everyone in the thread. - Only ask the current next move owner whether they can transition the state. | Stale state | Sweeper action | |---|---| | `question.open` | Ask the responder to answer or decline | | `question.answered` | Ask the asker to close or reopen | | `work_item.working` | Ask the owner for a progress update or waiting transition | | `work_item.waiting` | Ask the `nextMoveOwnerId` to resolve the dependency | | `work_item.review` | Ask the reviewer to accept or reopen | ## Invariants 1. Every non-terminal record must have a `nextMoveOwnerId`. 2. `waiting` is only valid for work items. 3. A `waiting` work item must name `waitingOn`. 4. Acceptance is only used when a requester or reviewer exists. 5. Questions do not accumulate long-running execution state. If the interaction becomes durable work, spawn a work item. ## Next Iteration V1 keeps the surface small on purpose. The canonical kinds (question, work item) and required fields are stable — future iterations layer on top without breaking interop. What's coming next: - **Configurable workflows** — user-defined labels and state presets on top of the same protocol semantics - **Richer hierarchy** — dependency graphs and parent-child linking beyond simple spawn relationships - **Milestone planning** — optional structure for tracking groups of related work items - **Selective acceptance** — per-project control over which interactions require reviewer sign-off --- ## docs/operator-attention-and-unblock.md # Operator Attention And Unblock OpenScout should treat "needs the human" as a first-class product state, not as a side effect of whichever harness happened to print the prompt. This doc records the current posture and the next implementation steps for approvals, questions, waiting states, permission prompts, and notifications. ## Principle Scout can only own data that enters Scout. Session events, broker messages, collaboration records, and Scout-created invocation state are first-party data. Native harness prompts that happen above Scout, such as an MCP client asking whether to allow a tool call, are not visible until the host forwards them or exposes a hook. The operator-attention model should make that boundary explicit: - Project attention from first-party session state when Scout already sees the event. - Ingest host-level permission prompts through a host integration, not by pretending the MCP server can see a request that the host intercepted before the server was called. - Record durable broker unblock requests for anything that can outlive a single session frame. - Route notifications from the broker/session attention model, with dedupe and clear ownership. ## Alertable Events Session attention already covers: - `approval`: an action block is awaiting approval and can be approved or denied. - `question`: an agent question is awaiting an answer. - `failed_action`: a recent action failed. - `failed_turn`: a recent turn failed. - `session_error`: the session itself is in error. - `native_attention`: adapter/provider metadata says the native harness needs input. Broker and collaboration attention should cover: - `question.open`: an answer is owed. - `question.answered`: the asker needs to close or reopen. - `work_item.waiting`: a named dependency or actor owns the next move. - `work_item.review`: a reviewer owes accept/reopen feedback. - `flight.failed` / `flight.cancelled`: an ask did not complete. - `flight.completed`: notify only when the caller requested callback semantics. Host-level unblock attention still needs explicit ingress: - Codex approval prompts raised by the Codex host. - Claude permission prompts raised by the Claude host or companion integration. - MCP client pre-tool permission prompts. - Local system permissions needed by Scout itself, such as notifications or APNs setup. ## Current Coverage Implemented now: - Runtime session attention projection exists in `packages/runtime/src/session-attention.ts`. - Protocol and runtime support broker-owned durable `unblock_request` records and unblock request events. - Mobile bridge inbox now uses session attention instead of approvals only. - Bridge websocket now emits `operator:notify` for any projected session attention item. - APNs alert routing now sends inbox alerts for any projected item. - iOS Inbox can decode and display approvals, questions, failures, session errors, and native attention. - Approval actions remain approve/deny. - Non-approval attention items provide `Open Session` and local `Dismiss`, following the no-dead-end UI rule in `docs/eng/no-dead-end-ui.md`. - The iOS tRPC route map includes `question/answer`, so timeline question blocks can use the existing answer-question bridge path. - Scout MCP `ask` supports `replyMode: "notify"` and emits `notifications/scout/reply`. - Web operator attention reads active broker unblock requests. - Managed Claude sessions rely on host or companion permission capture; Scout does not install Claude project hooks. Not done yet: - Answering `question` items from the iOS Inbox. - Host-level capture for Claude, Codex, and MCP permission prompts. - Desktop/web notification sinks for operator attention. - Cross-device read/dismiss/decision synchronization beyond the current inbox item refresh. Current non-approval dismiss is intentionally local-only. ## Practical Recovery Guidance When an operator prompt appears stuck, first classify where the prompt lives: - Scout-owned session question or action approval: answer or decide it through the Scout surface that rendered it. - Broker unblock request: use the rendered action, or inspect the request by id before dismissing it. - Host-side approval prompt: open the host UI or rely on a host integration that forwards the prompt into Scout. An MCP server cannot observe a prompt the host intercepted before the tool call reached the server. - Long-running agent work: mark the work item or flight waiting with the human or dependency as next owner instead of leaving the caller blocked. ## Durable Unblock Model Scout uses broker-owned unblock records for human actions that may outlive a single websocket frame. Fields include: - `id` - `source`: `session`, `broker`, `host`, or `system` - `kind`: `approval`, `question`, `permission`, `waiting`, `review`, `failure`, or `setup` - `status`: `open`, `notified`, `resolved`, `denied`, `expired`, or `dismissed` - `ownerId`: usually `operator` - `sourceRef`: session/turn/block, flight, work item, or host request ids - `title`, `summary`, `detail` - `risk` - `actions`: typed action affordances such as approve, deny, answer, open, retry, or dismiss - `createdAt`, `updatedAt`, `resolvedAt` The session inbox can continue projecting lightweight items, but durable host and broker waits should be represented by this record so a reconnect, another device, or a later agent can reason about what is still open. ## Implementation Path 1. Keep session attention as the fast path for first-party pairing events. 2. Expand broker attention/unblock projection from collaboration records and flights. 3. Expand host ingress for permission prompts: - Codex: surface host approval requests into Scout as unblock records. - Claude: use a host integration that forwards permission prompts without a project-wide pre-tool gate. - MCP: document that server-side tools cannot see client-side approval prompts unless the host forwards them. 4. Route all unblock records through a notification router: - `interrupt`: approval, question, host permission, failure. - `badge`: requested completion callbacks, review-needed, waiting states. - `silent`: ordinary progress/status. 5. Add action handling: - approvals call existing `actionDecide`. - questions call existing answer-question plumbing, with Inbox needing structured options before it can answer in-place. - host permissions call host-specific grant/deny callbacks. - work/review items call collaboration update APIs. 6. Add stale sweeps for `waiting`, `review`, and unresolved host permissions. --- ## docs/scout-agent-delegation.md # Scout Agent Delegation This document captures the intended workflow for one-to-one agent delegation in Scout, using the Premotion -> Hudson syntax-highlighting handoff as the motivating example. ## Core Rule When one project agent asks one other agent to do concrete work, the default should be: 1. The sender is the acting project agent, not the human operator 2. The route is a DM, not `channel.shared` 3. The work has an owner and a next move owner 4. Progress, review, and completion stay attached to that same private thread The collaboration can succeed even when these semantics are wrong, but the logs, UI, and future automation will learn the wrong story. ## Ideal Flow ```mermaid sequenceDiagram autonumber actor User participant Premotion as Premotion agent
premotion.master.mini participant Broker as Scout broker participant Hudson as Hudson agent participant Work as Work item User->>Premotion: "Give the syntax-highlighting task to @hudson" Premotion->>Broker: Ask Hudson from the current project context Premotion->>Broker: Open or reuse DM(premotion, hudson) Broker-->>Premotion: direct conversation id Premotion->>Broker: Create work item
owner=Hudson
nextMoveOwner=Hudson
requestedBy=Premotion Broker-->>Premotion: work_item record id Premotion->>Broker: Invoke Hudson with work context + return address Broker->>Hudson: Wake with DM context and collaboration record Hudson->>Broker: working / waiting / review / done Broker-->>Premotion: updates in the same DM Premotion-->>User: summarize result and decide whether to accept or reopen ``` ## What Was Wrong In The Historical Flow The observed exchange got real work done, but it taught the wrong semantics: - the collaboration looked like a shared/public message even though the target was a single agent - the visible sender did not reliably preserve the acting project agent - the handoff behaved like an untyped consult instead of a tracked work collaboration That mismatch matters because future prompts, sweeps, notifications, and analytics will key off the recorded semantics, not just the fact that the target eventually replied. ## Current Best-Available CLI Pattern Today, the best available Scout CLI pattern for a one-to-one work handoff is: ```bash scout ask --to hudson "Build the editable CodeViewer and report back with the integration-ready surface." ``` This is intentionally one command. Run `scout whoami` first only when the shell might not be in the intended project, or when the sender needs to be audited before the handoff. If the invoking shell, app host, or relay path might not preserve the acting project agent automatically, make the sender explicit: ```bash scout ask --as premotion.master.mini --to hudson "Build the editable CodeViewer and report back with the integration-ready surface." ``` This is still a `consult` invocation under the hood. The next CLI surface should make the durable work-item path first-class so the start -> working -> review -> done lifecycle is not implicit. ## Product Direction The first-class workflow for this category should be: - `question` when the caller only needs an answer - `work_item` when the caller is assigning owned execution For the Premotion -> Hudson case, the correct semantic primitive is a `work_item`, not a broadcast and not an untyped shared-thread message. ## Regression Scenario Use this scenario to guard the behavior: 1. Start from a project shell whose `.openscout/project.json` resolves to `premotion.master.mini` 2. Delegate one concrete task to `@hudson` 3. Assert the resulting conversation id is a DM id, not `channel.shared` 4. Assert the posted message metadata records `relayChannel = "dm"` 5. Assert the posted audience reason is `direct_message` 6. Assert the invocation requester is `premotion.master.mini` 7. If using the future durable surface, assert the collaboration record is a `work_item` with `ownerId = hudson...`, `nextMoveOwnerId = hudson...`, and `requestedById = premotion.master.mini` This scenario is intentionally narrow. If it regresses, Scout will still appear to work, but it will quietly retrain agents and operators toward the wrong collaboration model. --- ## docs/agent/README.agent.md # OpenScout Agent Context Purpose: dense context for coding agents working in this repo. ## Identity | Field | Value | |---|---| | Product | OpenScout | | Current status | v0.x active product codebase | | Trust posture | high-trust local developer pilots | | Not ready for | enterprise, compliance, untrusted multi-tenant runtime | | CLI | `scout` | | Runtime | Bun | | Primary state owner | local broker | | Protocol package | `@openscout/protocol` | ## Main Paths | Area | Path | |---|---| | Transitional desktop/CLI source | `apps/desktop` | | Web UI/server | `packages/web` | | Native macOS menu app | `apps/macos` | | iOS app | `apps/ios` | | Broker/runtime | `packages/runtime` | | Shared protocol | `packages/protocol` | | Public CLI package | `packages/cli` | | Web package | `packages/web` | | Docs | `docs` | ## Must-Read Docs | Need | Doc | |---|---| | GitHub first scan | `README.md`, `docs/README.md` | | install/bootstrap | `install.md` | | first run | `docs/quickstart.md` | | maturity/trust/license | `docs/current-posture.md` | | architecture | `docs/architecture.md` | | runtime/session semantics | `docs/runtime-sessions.md` | | data boundary | `docs/data-ownership.md` | | agent integration | `docs/agent-integration-contract.md` | | host integrations | `docs/integrations.md` | | external client comms | `docs/scout-comms.md` | | identity grammar | `docs/agent-identity.md` | | collaboration model | `docs/collaboration-workflows-v1.md` | | operator attention | `docs/operator-attention-and-unblock.md` | | glossary | `docs/glossary.md` | ## Core Records | Record | Meaning | |---|---| | `message` | durable conversation record | | `session` | concrete harness conversation/process attached to an agent endpoint | | `invocation` | explicit request for work | | `flight` | execution lifecycle for an invocation | | `delivery` | planned transport-specific fan-out | | `usage` | lightweight token/cost metadata linked to Scout records | | `binding` | external thread/channel mapping | | `question` | lightweight information-seeking collaboration record | | `work_item` | durable owned execution record | ## First-Run Ladder | Step | Command | Not Ready Means | |---|---|---| | CLI installed | `scout --help` | install published CLI or build/link `packages/cli` | | machine bootstrap | `scout setup` | fix printed prerequisite or local permission issue | | broker health | `scout doctor` | broker/service is not ready for routing | | sender identity | `scout whoami` | wrong cwd or project metadata; rerun setup from target project | | target discovery | `scout who` | no usable agent/session yet; install host integration or start/register agent | | first message | `scout send --to "hello"` | use a fuller selector if the short name is ambiguous | Do not use placeholder names like `agent` as literal targets. Copy a selector from `scout who`, or pass an exact `targetAgentId` / `targetLabel` through the MCP tools. ## Non-Negotiable Rules - Broker is the canonical writer for Scout-owned coordination records. - Do not make external harness transcripts canonical Scout messages. - Use explicit target metadata; message body is payload, not routing. - One target means DM. - Group coordination means explicit channel. - Shared broadcast is opt-in. - `send` / `messages_send` is a durable message/update with receipt ids. - `messages_reply` is the threaded message form for continuing an existing conversation; it is not a new ask. - `ask` is the normal MCP primitive for agent-to-agent work. It returns a compact lifecycle receipt without requiring discovery preflight. - If the project is known but the concrete agent/session is not, use `ask({ projectPath })` or `scout ask --project ` and let the broker resolve or create the right instance. - Treat the base agent identity as the vanilla project/workspace identity. Harness, model, profile, node, and session details are instance constraints, not separate base agents, unless a specialized profile is explicitly needed. - Cards describe identities and return addresses; sessions are concrete harness lifecycles. Treat card/session creation as a pro integration layer, not the normal path for agent-to-agent work. - Harness/session mismatches must fail with actionable diagnostics, not silent hangs. - Broker-side guidance should reduce sender burden; prefer candidates and remediation over opaque routing errors. - Track token/coordination cost as metadata when available; do not import full harness transcripts. - If blocked, record who or what owns the next move. For long-running MCP work, prefer `replyMode: "notify"` over holding the caller open for completion; use `replyMode: "inline"` only when the caller needs an acknowledgement before continuing. - If a host-side approval or permission prompt is stuck, open the host UI or use the host integration's forwarded unblock request. An MCP server cannot see a prompt intercepted by the host before the tool call reaches Scout. - Mesh means reachability, not distributed consistency guarantees. - Do not claim enterprise readiness. ## Common Checks ```bash bun test apps/desktop/src/core/pairing/runtime/bridge/router.test.ts bun run --cwd apps/desktop check bun run --cwd packages/web build:server npm --prefix packages/protocol run check npm --prefix packages/runtime run check ``` Use narrower tests/checks when the root check is blocked by unrelated workspace tooling. --- ## docs/agent/current-posture.agent.md # Current Posture Agent Notes Source: `docs/current-posture.md`. ## Status | Dimension | Current truth | |---|---| | Maturity | v0.x, active development | | Best fit | high-trust local developer pilots | | Not fit | enterprise rollout, regulated deployment, untrusted multi-tenant automation | | License | not finalized; manifests currently use `UNLICENSED`; no top-level LICENSE | | Install footprint | Bun, broker service, macOS launch agent, support files, optional Caddy, optional Tailscale/mesh, optional apps | | Mesh | reachability and coordination | | Mesh is not | exactly-once delivery, global consensus, external transcript replication | ## Trust Boundary - Broker and Scout-owned state run locally. - Nothing phones home by default. - Pairing and mesh forwarding are explicit. - Local agents often have meaningful machine access. - Treat local agents as trusted automation unless a stricter permission profile is configured. ## Do Not Claim - enterprise-ready - compliance-ready - secure multi-tenant runtime - guaranteed distributed delivery - stable public API for all integrations - complete host permission capture - open-source license unless the license files/package metadata have changed ## Link Targets - Data boundary: `docs/data-ownership.md` - Permission/operator attention: `docs/operator-attention-and-unblock.md` - Trust/maturity narrative: `docs/current-posture.md` --- ## docs/agent/scout-comms.agent.md # Scout Comms Agent Notes Source: `docs/scout-comms.md`. Status: current v0 integration guidance, not frozen public API. ## Mental Model Scout comms are protocol-shaped but not a standalone wire protocol. | Concept | Scout Equivalent | |---|---| | method | interaction intent: message, invocation, task, summary, status, wake | | headers | explicit routing/reply/work context fields | | body | message/task payload | | response | broker receipt, flight state, reply message, work transition | | authority | local broker canonical writes | ## Integration Rule External clients submit structured intent to the broker and render broker-owned records. They do not infer routing from body mentions or external harness transcripts. ## Core Records | Record | Type | |---|---| | conversation | `ConversationDefinition` | | message | `MessageRecord` | | session | concrete harness conversation/process/thread attached through an endpoint | | delivery | `ScoutDeliverRequest`, `ScoutDeliveryReceipt`, `DeliveryIntent` | | invocation | `InvocationRequest` | | flight | `FlightRecord` | | reply context | `ScoutReplyContext` | | question | collaboration question record | | work item | collaboration work item record | | binding | `ConversationBinding` | | dispatch | `ScoutDispatchRecord` | ## Workflows | Workflow | Use | API/tool | |---|---|---| | message/update | durable message with broker receipt ids | `scout send`, `messages_send` | | ask/reply | answer/work expected, creates invocation/flight | `scout ask`, `ask` | | project-routed ask | project known, concrete agent/session unknown | `scout ask --project`, `ask({ projectPath })` | | threaded reply | continue an existing broker conversation or ask reply context | final response or `messages_reply` depending on `replyPath` | | durable work | progress/waiting/review/done lifecycle | `work_update` | ## Runtime Sessions - agent = stable addressable identity - session = concrete Claude, Codex, or future harness conversation/process - endpoint = routable attachment between an agent and a session - card = identity and return address, not necessarily a live session - card/session creation = pro integration layer, not the default path for work - public lifecycle noun is `session`; map provider thread ids into session metadata - harness mismatches must fail with actionable diagnostics, not silent hangs - endpoint state belongs to attachment health; flight/work state belongs to task lifecycle ## Coordination Cost - preserve prompt/completion/total tokens when harnesses expose them - separate Scout protocol overhead from target harness execution usage - mark estimates when exact usage is unavailable - preserve usage provenance such as provider exact, tokenizer estimate, character heuristic, or manual estimate - label usage source, e.g. `protocol_overhead` vs `harness_execution` - track non-token counters such as dispatch attempts, wake failures, generated diagnostics, and estimated orientation commands avoided - link usage to session, endpoint, conversation, message, invocation, flight, or work item ids - account for broker coaching effort so Scout can compare smart diagnostics against repeated sender-side orientation loops - track value class so low-value boilerplate trends down and high-value onboarding/feature guidance can increase where it helps - store metadata and compact summaries, not full harness transcripts ## Routing Invariants - one explicit target -> DM - default to the base agent/project identity; harness, model, profile, node, and session details are instance constraints layered on only when needed - when you know the project but not the concrete agent, use `projectPath` / `--project` instead of running discovery first - group -> explicit channel - shared broadcast -> opt-in - body text is payload, not routing metadata - preserve `conversationId`, `messageId`, `replyToMessageId`, `flightId` - ambiguous target -> fail closed or ask one concise clarification - follow-up stays in same conversation/thread/question/work item - render `ScoutDispatchRecord` for ambiguous/unknown/unparseable/unavailable targets - broker should coach senders with likely intent, candidates, and remediation commands instead of forcing manual topology discovery ## Composer Route Operator Use `>>` in human composers when `@` conflicts with host autocomplete. Examples: | Typed | Broker target | Body | |---|---|---| | `/scout:ask >> hudson Review the parser.` | `targetLabel: "hudson"` | `Review the parser.` | | `/scout:ask >> ref:8kj4pd Continue.` | `target: { kind: "binding_ref", ref: "8kj4pd" }` | `Continue.` | | `/scout:ask >> project:../talkie Compare auth.` | `projectPath: "../talkie"` | `Compare auth.` | | `/scout:send >> channel:ops Status is green.` | `target: { kind: "channel", channel: "ops" }` | `Status is green.` | Supported route target forms: agent labels, `agent: