docs(prd): PRD draft 0.2 with requirement ids; lead decision 48

PRDY round 2 answers, and Researcher's Vikunja and Pocket ID report as
a record.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-04 14:48:15 -05:00
co-authored by Claude Opus 5.5
parent df9e036214
commit c57998772d
4 changed files with 564 additions and 47 deletions
+1
View File
@@ -471,3 +471,4 @@ are never rewritten or removed; corrections are new entries.
2026-10-04T19:19:14Z | Sage (T3 Claude Code, thread 1ef1e4f8) | slice 1 data model received | Darkwing's note (948b94ce) and prototype committed as records; lead decision 46 accepts 6.1-6.5, 6.7, 6.8 and sends 6.6 (PM launching sessions) to Jason in PRDY round 3
2026-10-04T19:26:12Z | Filbert (T3 Claude Code, thread 9cb9731e) | meta-harness survey done (slice 1 step 8) | agents/filbert/work/meta-harness-survey-2026-10-04.md sha256 05f83807…0989; Pi tool_call is the only fail-closed hook of the three, so hard lines are credential scope, verbs, tool ceiling and container; no commits
2026-10-04T19:26:50Z | Sage (T3 Claude Code, thread 1ef1e4f8) | meta-harness survey received | Filbert's survey (05f83807) committed as a record; lead decision 47 rules on its section 8; two DEFERRED items (host-seat --approve, worker provider-key exposure)
2026-10-04T19:48:15Z | Sage (T3 Claude Code, thread 1ef1e4f8) | PRDY round 2, PRD 0.2 | lead decision 48; PRD draft 0.2 with requirement ids; Researcher's Vikunja and Pocket ID report (fcfc970f) committed as a record (Researcher wrote no SESSIONS line, per its limits)
+20
View File
@@ -753,3 +753,23 @@ which stay with him. Each item names who decided it and what happened.
environment or files. The existing exposure of worker provider keys
goes in DEFERRED.
7. Build order: Pi, then Claude Code, then Codex.
48. **PRDY round 2 answers (2026-10-04).** Jason, thread 1ef1e4f8. The
answers fill PRD draft 0.2 (`docs/prd/mosaic-stack.md`), with
requirement ids:
1. Out of scope for v1: "all". That covers other businesses, credential
minting, Codex, Pocket ID and SSO, and access from beyond localhost.
2. "A". A gated decision reaches the CLI inbox, plus a Discord DM when
it blocks work.
3. "A". Blocking decisions arrive right away. Everything else goes into
one daily digest.
4. "A". Sage is PM and Darkwing is CTO for Mosaic Stack.
5. "A". `mosaic` talks to an agent session the stack launches and owns,
running Pi or Claude Code headless. T3 stays a development tool.
6. "A". The PM launches role sessions within limits set in the business
file: role instances only, 4 Opus and 4 Sonnet, each launch logged,
revocable with one word. That settles open question 6.6 from
decision 46.
Researcher's report
(`agents/researcher/work/2026-10-04_vikunja-pocketid.md`, sha256
fcfc970f…) was committed as a record with this entry. The PRD's
technical considerations draw on it.
+199 -47
View File
@@ -1,81 +1,219 @@
# PRD: Mosaic Stack
- Status: draft, version 0.1. Jason approves it, and once approved it is
- Status: draft, version 0.2. Jason approves it, and once approved it is
never edited in place. Changes after approval are a new version.
- 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.
- Interview record: Sage's thread 1ef1e4f8. Round 1 was answered on
2026-10-04 and is recorded as lead decision 45.
- Interview record: Sage's thread 1ef1e4f8. Round 1 is lead decision 45.
Round 2 is lead decision 48. Design inputs are lead decisions 43, 44,
46 and 47.
## Introduction
### Objective
Working north star, ratified as lead decision 44: "Jason declares
The working north star, ratified as lead decision 44: "Jason declares
businesses, projects and roles. Agents in those roles carry the work end
to end under declared policy, and only gated decisions reach him."
### Context
See `docs/plans/2026-10-04_foundation-direction.md`. Agents can already do
real work here, but a person has to launch them, relay between them, hand
them credentials and correct them. There's no CLI or complete WebUI for
Jason, and no place where outstanding decisions collect.
See `docs/plans/2026-10-04_foundation-direction.md`. Agents already do
real work here. But a person has to launch them, relay between them, hand
them credentials and correct them. Jason has no CLI and no complete WebUI,
and outstanding decisions don't collect anywhere.
## Users
Jason alone for now. The stack must be built so outside users can install
it later: an installer, no paths or names specific to Jason, and
configuration through the variable layers (round 1, answer D).
For now the only user is Jason. The stack must still be installable by
outside users later, which means:
- an installer;
- no paths or names specific to Jason;
- configuration through the variable layers.
(Round 1, answer D.)
## Problem statement
In priority order (round 1):
1. **Admin falls on Jason.** He launches seats, relays between them,
1. **Admin falls on Jason.** He launches agents, relays between them,
finds credentials and corrects them.
2. **Jason can't see what the agents are doing or what's waiting on
him.**
3. **Agents drift from what the business needs.** Nothing ties a piece of
work to a stated goal.
Credential sprawl wasn't picked as a top problem. The roles work and hard
limit C cover it.
## Scope and non-goals
### Hard limits
Every one of these is a gated decision, or simply not done (round 1,
"all five"):
- A. The stack never spends money without Jason.
- B. It never speaks externally as Jason without his approval.
- C. Agents never hold Jason's personal credentials. Each role gets its own.
- D. It is not a multi-tenant SaaS in v1.
- E. It doesn't replace Claude Code, Codex or Pi. It wraps them.
The stack doesn't do any of these. Each one is either a gated decision or
off the table (round 1, "all five"):
- A. Spend money without Jason.
- B. Speak externally as Jason without his approval.
- C. Give agents Jason's personal credentials. Each role gets its own.
- D. Become a multi-tenant SaaS in v1.
- E. Replace Claude Code, Codex or Pi. It wraps them.
### Where it runs
Self-hosted first, on Jason's machines and homelab (round 1, "A first").
Cloud workers aren't ruled out later.
### In scope for v1
Slice 1 of the foundation direction:
- roles, variables and credentials per role;
- decision records and messages addressed by role;
- tasks in Vikunja through its API;
- the `mosaic` CLI, then the WebUI;
- the meta-harness.
Self-hosted, on Jason's machines and homelab (round 1, "A first"). Cloud
workers aren't ruled out later.
### Out of scope for v1
To be set in round 2.
Round 2, "all":
- businesses other than Mosaic Stack (SetSpark joins after v1);
- minting credentials (v1 hands out tokens Jason creates);
- Codex (v1 covers Pi and Claude Code, and Codex comes next);
- Pocket ID and SSO;
- access from beyond localhost.
## Requirements
To be set in rounds 2 and 3. Each requirement gets a stable id
(`REQ-<area>-<n>`). Every task the stack creates must cite one.
Every task the stack creates cites one of these ids. A task with no
parent requirement is refused.
### Roles
- **REQ-ROLE-1.** Each role is a reviewed file, `roles/<name>.json` at
version 2. The file holds:
- a contract;
- an authority map over a closed vocabulary of actions;
- 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-3.** A business 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 business is Mosaic Stack, with four role
instances:
- PM, held by Sage;
- CTO, held by Darkwing;
- coder;
- reviewer.
The schema can also declare CEO, CFO and the other C-suite roles.
### Variables
- **REQ-VAR-1.** Variables come in four layers: system, business, project
and agent. Every key is declared in code with a type, the layers allowed
to set it, and a merge rule.
- The most specific layer wins for plain values.
- Limits intersect, so a lower layer can only narrow them.
- An unknown key is refused, and so is a key set at a layer it isn't
allowed in.
- **REQ-VAR-2.** `~/.config/mosaic-dev/config.json` stays the only system
config, and nothing writes it automatically. A secret appears only as a
reference, either a file path or an environment variable name. The
stack checks a referenced file with `stat` and never reads its
contents.
### Credentials
- **REQ-CRED-1.** Every role instance has its own token for each service
(Gitea, Vikunja). In v1 Jason creates these tokens by hand. The broker
holds them, and they never enter an agent's environment or files.
- **REQ-CRED-2.** A session that finds only founder credentials stops.
### Decisions
- **REQ-DEC-1.** Every decision is a record in an append-only SQLite
table. The record holds:
- the role and run that raised it;
- its class and action;
- the options and a recommendation;
- who resolved it;
- its timestamps.
A correction is a new row.
- **REQ-DEC-2.** Routing follows the decision's class:
- routine and within-role decisions are logged;
- cross-role decisions go to the business's arbiter for that domain;
- gated decisions go to the human.
- **REQ-DEC-3.** A human resolution comes only from a `mosaic` CLI session
started outside any agent run. Agents reach the decision store only
through a broker. The broker stamps role and run from the launch record.
- **REQ-DEC-4.** A gated decision that blocks work reaches Jason right
away: in the CLI inbox, plus a Discord DM. Everything else goes into one
daily digest. (Round 2, answers 2A and 3A.)
### 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.
### Tasks
- **REQ-TASK-1.** Tasks live in Vikunja, reached through `/api/v2` with a
bot token for each role. Each task cites a requirement id. Only the
assigned role writes a task's mutable fields. A person's edits come in
as events.
- **REQ-TASK-2.** Polling for changes since the last check is the source
of truth, and webhooks only trigger a check sooner.
- **REQ-TASK-3.** The installer offers two choices: point at an existing
Vikunja, or deploy the bundled one. The bundled one is the unmodified
upstream image. No Vikunja code enters the repository.
- **REQ-TASK-4.** The queue keeps the agents' lock, review rounds and
audit log. No field syncs in both directions.
### Interface
- **REQ-CLI-1.** `mosaic` is the front door. From it Jason can:
- talk to the PM;
- 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
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.
### Launching
- **REQ-LAUNCH-1.** The PM launches role sessions within limits written in
the business file:
- role instances only;
- at most 4 Opus and 4 Sonnet sessions at once;
- every launch logged;
- revocable with one word.
(Round 2, answer 6A.)
### Meta-harness
- **REQ-HARN-1.** The meta-harness generates each session's launch bundle
from the role and the resolved variables:
- the prompt;
- the policy;
- skills;
- typed tools for the vocabulary actions;
- a manifest.
Pi comes first, then Claude Code. Codex comes after v1.
- **REQ-HARN-2.** Four layers actually enforce the rules:
- credential scope;
- verbs that refuse without a resolved decision;
- the harness's tool limit;
- a container.
Hooks only refuse early and log, and no document may call them
enforcement. A probe run against the live harnesses must pass before any
build relies on a block.
### Events
- **REQ-EVT-1.** Every step in slice 1 emits an event to the append-only
store. Measures are computed from events, never from tagging chat
messages by hand.
## Acceptance criteria and success measures
@@ -89,20 +227,34 @@ piece:
## Technical considerations
Ratified as lead decision 44:
- Vikunja is integrated through its API, never annexed. Mosaic Stack's
own work uses a dedicated local instance. The installer offers an
existing instance or the bundled one.
- Decisions and messages live in SQLite, in append-only tables. Run
records stay as write-once files.
- People sign in through Pocket ID, wired in after slice 1. Agents use
service tokens per role.
- Vikunja v2.7.0 is AGPL-3.0. Its API tokens can't create users or mint
more tokens. A Mosaic-owned account mints one bot user and one scoped,
expiring token per role. The owner password for that account is the one
high-value Vikunja secret. Instance admin features need a paid licence,
and the plan doesn't use them. Source:
`agents/researcher/work/2026-10-04_vikunja-pocketid.md`.
- Gitea tokens never expire, and creating one needs a password or the host
shell. Rotation will be a scheduled step with a record.
- Pocket ID v2.17.0 is BSD-2. It offers passkey-only login for people and
a client-credentials flow, but it can't issue tokens that Vikunja or
Gitea accept. Agents use per-service role tokens. Pocket ID is wired in
after v1.
- Decisions, messages, role claims and events share one SQLite file,
`<dataRoot>/bus/bus.sqlite`. A guard on every table refuses UPDATE,
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`.
## Risks and open questions
To be set in round 3.
Round 3 sets these. Known so far:
- Agents running as the same OS user as Jason can write anything that
user can write. Until seats run as another user or in a container, the
broker is a rule they follow, not a wall.
- The Vikunja owner password and Gitea token creation are gated. Jason
holds them.
## Milestones
Slice 1 first, in the order on the foundation direction page. The
milestones get set once the requirements exist.
Slice 1, in the order on the foundation direction page. The slice 1 brief
maps each step to requirement ids.