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:
@@ -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)
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user