diff --git a/docs/prd/mosaic-stack.md b/docs/prd/mosaic-stack.md index f65210a5e..e6b459553 100644 --- a/docs/prd/mosaic-stack.md +++ b/docs/prd/mosaic-stack.md @@ -1,9 +1,28 @@ # PRD: Mosaic Stack -- Status: approved, version 1.1. Jason approved draft 0.4 unchanged as +- Status: approved, version 1.2. Jason approved draft 0.4 unchanged as 1.0 on 2026-10-05 (lead decision 61). He approved version 1.1, the Organization requirements, in decision 03130d08-ddce-480d-a601-e59f64744fc3 - on 2026-10-14. It is never edited in place. Changes are a new version. + on 2026-10-14. He approved version 1.2, the chief of staff, the + assistant, threads and agent limits, through Mos on 2026-10-14 (lead + decisions 141 and 142). It is never edited in place. Changes are a new + version. +- Version 1.2 source, Jason's words relayed by Mos: + - Q147 (full text in lead decision 141): "COS should focus on COS + duties. This will include hire/terminate authority for agents, org + structure, etc. ... This necessitates the creation of a new role for + user interaction. ... The user should be allowed to have 1 - N + sessions with this agent to allow for topics of focus in a given + thread. ... The interaction agent in each session is the user's main + agent." + - Q148, Mos's read-back of Q147: "Q148: Yes". + - Q149, on the 1.2 draft: "approved as long as the agent limits are + tunable via "Settings" in the WebUI and via the CLI tooling." + - Q150: "No hard cap on agent limits. All tunable." The five kinds of + limit are quoted under Launching. + - Q151, Mos's read-back of Q150, with the default that launches over a + limit are refused and logged and a run that hits its token limit is + stopped: "Q151: yes". - Owner: Jason. Sage writes it from the PRDY interview. - Template: PRDY "software" (`v1/packages/prdy/src/templates.ts`), filled by hand until PRDY is ported. @@ -89,21 +108,49 @@ parent requirement is refused. - the credentials it needs, by service and scope. Any action the file doesn't list is gated. -- **REQ-ROLE-2.** Each role instance has one holder at a time. A claim - takes a lock and logs it, and releasing the role or ending the run frees - it. Revoking a stuck holder is gated, and the revoke cites a resolved - decision. +- **REQ-ROLE-2.** Each role instance has one holder at a time. The + assistant is the exception: it has one holder per thread at a time. A + claim takes a lock and logs it, and releasing the role or ending the run + frees it. The chief of staff may end another role's run, and that act is + logged with its reason. Anyone else who revokes a stuck holder needs a + resolved decision, and the revoke cites it. - **REQ-ROLE-3.** An organization file declares the role instances, - the arbiters and the credential references. The user writes it, the stack - never writes it, and a missing or invalid file fails closed. -- **REQ-ROLE-4.** The first organization is Mosaic Stack, with four role + the arbiters and the credential references. The user and the chief of + staff write it. The chief of staff's writes go through a broker verb + that logs each change. No other role writes it. A missing or invalid + file fails closed. (Q133, confirmed as Q140: "We need the human and the + Chief of Staff to be able to edit the Business file(s)".) +- **REQ-ROLE-4.** The first organization is Mosaic Stack, with six role instances: + - chief of staff; + - assistant; - PM, held by Sage; - CTO, held by Darkwing; - coder; - reviewer. - The schema can also declare CEO, CFO and the other C-suite roles. + The schema can also declare CEO, CFO and the other C-suite roles. The + assistant's name is set in the organization file. Jason's may be named + Mos. + +Added in version 1.2: + +- **REQ-COS-1.** The chief of staff runs the organization. It hires and + terminates role instances, owns the organization's structure and is + the only role that launches sessions (REQ-LAUNCH-1). It takes work + from the assistant and assigns it through the roles that do it. It + never talks to the user. Gated decisions still reach the human + through the inbox (REQ-DEC-2, REQ-DEC-4). +- **REQ-ASSIST-1.** The assistant is the user's main agent. Each user has + one assistant role per organization. It talks with the user, and it + passes work for the organization to the chief of staff. It doesn't + direct other agents, create or assign tasks, or launch sessions. +- **REQ-ASSIST-2.** The broker limits the assistant's messages, not its + contract alone: + - the assistant may send only to the user, in the thread, and to the + chief of staff; + - only the user and the chief of staff may send to the assistant; + - every refused send is logged with its reason. ### Variables @@ -159,9 +206,12 @@ parent requirement is refused. ### Messages -- **REQ-MSG-1.** Messages are addressed to a role, not a thread. They are - append-only and go to whoever currently holds the role. T3 and Discord - carry messages; the address is still the role. +- **REQ-MSG-1.** Messages are addressed to a role. They are append-only + and go to whoever currently holds the role. A message to or from the + assistant also names its thread and goes to that thread's holder. When + the assistant sends work to the chief of staff, the reply comes back to + the same thread. T3 and Discord carry messages; the address is still + the role. ### Tasks @@ -185,26 +235,85 @@ parent requirement is refused. ### Interface - **REQ-CLI-1.** `mosaic` is the front door. From it Jason can: - - talk to the PM; + - talk to the assistant in a project thread they choose or create; - see the decision inbox and resolve decisions; - see tasks and agents; - follow the trail of any piece of work. -- **REQ-CLI-2.** The PM session that `mosaic` talks to is one the stack +- **REQ-CLI-2.** The assistant session that `mosaic` talks to is one the stack launches and owns, running Pi or Claude Code without a window. The product doesn't depend on T3. (Round 2, answer 5A.) - **REQ-WEB-1.** The WebUI shows the same data as the CLI: conversations, - the inbox, tasks, agents and trails. + the inbox, tasks, agents and trails. It has a chat area that lists the + user's projects and the named threads in each, with one conversation + view per thread where the user talks to the assistant. The user creates + and names projects and threads there without a terminal. Its Settings + view shows every agent limit, the usage counted against each, and the + model each role instance runs, and lets the user change them + (REQ-LIMIT-1 to REQ-LIMIT-3). ### Launching -- **REQ-LAUNCH-1.** The PM launches role sessions within limits written in - the organization file: +- **REQ-LAUNCH-1.** The chief of staff launches role sessions within the + agent limits written in the organization file (REQ-LIMIT-1 to + REQ-LIMIT-3): - role instances only; - - at most 4 Opus and 4 Sonnet sessions at once; - - every launch logged; + - a launch that would exceed any agent limit is refused, and the + refusal is logged with the limit it hit; + - every launch is logged with its harness, provider, model, and the + account or key it runs on; - revocable with one word. - (Round 2, answer 6A.) + Assistant thread sessions are the exception to who launches. The stack + starts one when the user opens or writes to a thread, and ends it after + the thread has been idle for the time the organization file sets. A + running thread session counts against the limits like any other. An + idle thread holds no session and counts against none. The stack starts + the chief of staff itself. (Round 2, answer 6A; Q147; Q150.) + +Added in version 1.2. Jason, Q150, verbatim: "No hard cap on agent +limits. All tunable. Agent limit: A parallel execution limit arbitrarily +set by the user or COS. This limit can apply to: overall executing agent +limit across all models; provider parallel agent limit; provider parallel +agent limit by model; daily quota limit based on OAuth account limit or +CLIProxyAPI config in Mosaic Stack; absolute token limit per agent, +model, provider, or API key". + +- **REQ-LIMIT-1.** Agent limits are settings with no ceiling in code. The + user and the chief of staff view and change them from the WebUI's + Settings view and from a `mosaic` command, without editing a file. The + chief of staff changes them through its organization-file broker verb + (REQ-ROLE-3). The same places view and change the model each role + instance runs. The running-session limits are: + - the total number of sessions running at once, across all models; + - the number running at once per provider; + - the number running at once per provider and model. The default is 4 + Opus and 4 Sonnet, as a default that can be changed, not a cap. + + Any kind may be left unset, which means no limit of that kind. A value + is a whole number of 0 or more, and 0 stops new launches of that kind. + A change is checked by the same rules as the organization file, then + written to it and logged with who made it and the old and new values. + An invalid value is refused, and the old value stays. A change applies + to the next launch without a restart, and lowering a limit doesn't end + sessions already running. +- **REQ-LIMIT-2.** A daily quota per OAuth account, or per client key of + the CLIProxyAPI that Mosaic Stack configures. The stack counts the + tokens its sessions use against the account or key each ran on, and the + day resets at a time and time zone set with the quota. When an account + or key reaches its quota, new launches on it are refused, and running + sessions on it stop at the end of their current turn. Both are logged. + The count covers sessions the stack ran. Use of the same account + outside the stack isn't counted, and Settings says so. Measuring the + quota in tokens is a draft position: Q150 names no unit, and OAuth + plans meter by usage windows, not daily tokens. +- **REQ-LIMIT-3.** A token limit per role instance, model, provider or API + key. Each limit counts the tokens its subject has used since the limit + was set or last reset, and the user and the chief of staff can reset + it. A count is the sum of every kind the harness reports (input, + output, cache write and cache read), and Settings shows each kind. A + launch whose subject is at its limit is refused, and a running session + that reaches a limit is stopped at the end of its current turn. Both + are logged with the limit and the count. ### Meta-harness @@ -246,20 +355,30 @@ Added in version 1.1 (decision 03130d08). - **REQ-USER-1.** Users and role-based access control exist at install and organization level. An agent belongs to one organization and reaches only its allowed projects and threads. +- **REQ-USER-2.** Only the user who owns a thread reads it or writes to + it, plus that user's assistant and the chief of staff's replies on work + the thread sent. This fills in REQ-USER-1's "threads" for the chat + area. Added in version 1.2. - **REQ-THREAD-1.** Threads live under projects. +- **REQ-THREAD-2.** The user creates projects and names threads inside + them, from the CLI or the WebUI. Each thread is a separate assistant + session. A thread's messages are kept. When the user comes back to a + thread, after an idle stop or a restart, the assistant picks up where + it left off with that history. One thread's conversation never appears + in another's. Added in version 1.2. - **REQ-TPL-1.** Templates exist for agent roles and for organization types. - **REQ-FED-1.** Installs can federate with each other. This is post-v1. ## Acceptance criteria and success measures -v1 is done when Jason gives one-sentence requests in the CLI and Mosaic -Stack builds pieces of itself from them, five pieces in a row. For each -piece: +v1 is done when Jason gives one-sentence requests to the assistant, in a +thread, from the CLI or the WebUI, and Mosaic Stack builds pieces of +itself from them, five pieces in a row. For each piece: - only gated decisions reach Jason; - every step leaves a trail in the CLI and the WebUI. -(Round 1, answer A.) +(Round 1, answer A; the assistant and threads from version 1.2.) ## Technical considerations @@ -280,6 +399,70 @@ piece: DELETE and REPLACE. Run records stay write-once files. - None of the three harnesses' hooks fails closed by default except Pi's `tool_call`. Source: `agents/filbert/work/meta-harness-survey-2026-10-04.md`. +- Version 1.2: + - The organization file's `projects` key names git repositories to + clone (`packages/seat/src/checkout.mjs:282-296`). A REQ-ORG-2 project + is the user's container for threads. The build has to keep the two + apart, or define one in terms of the other, before the chat area + stores projects. + - Threads change the bus schema: messages, claims and deliveries gain a + thread. The bus refuses a database whose schema doesn't match + (`store.mjs:113-115`), so this needs a migration and a re-pin with + downtime. + - Claude Code resumes a conversation only inside one launch today, because + its session directory and HOME are per run (`launcher.mjs:204-206`, + `sandbox.mjs:157`). REQ-THREAD-2 needs a per-thread session store that + outlives the run, or a rebuild of context from the thread's messages. + - Limits today: `launch.max` is keyed by model family, and a launch's + family is the one key its model name contains + (`packages/seat/src/session.mjs:52-57`). Each count must be 0 to + `LAUNCH_CEILING = { opus: 4, sonnet: 4 }` + (`packages/business/src/vocabulary.mjs:86`, `business.mjs:129-137`). + The launcher reads the file once at start (`launcher.mjs:123`), so a + change needs a bus restart. REQ-LIMIT-1 removes the ceiling, replaces + family matching with a model table that names each model's provider, + and re-reads limits at each launch. Jason's file needs a one-time + migration from `{ opus: 4, sonnet: 4 }`. + - The stack doesn't know a session's provider today. The only provider + setting is the system-level `execution.provider` (`vars.mjs:84-87`), + read by `sessionModel` (`packages/harness/src/bundle.mjs:49-55`). + Claude Code sessions reach whatever `ANTHROPIC_BASE_URL` points at, or + Anthropic when it's unset. + - Tokens are on disk today, and nothing reads them: + - Claude Code: the adapter uses `--output-format text` + (`adapters/claude/adapter.sh`), so the runner sees only the answer. + Claude Code's own transcript, in the run's HOME at + `home/.claude/projects/