1797 lines
102 KiB
Markdown
1797 lines
102 KiB
Markdown
# PRD: Mosaic Stack
|
|
|
|
- Status: approved, version 1.15. Jason approved draft 0.4 unchanged as
|
|
1.0 on 2026-10-05 (lead decision 61). They approved version 1.1, the
|
|
Organization requirements, in decision 03130d08-ddce-480d-a601-e59f64744fc3
|
|
on 2026-10-14. They 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). Version 1.3 records their rulings on plug-ins
|
|
and token counting, Q153 to Q155, relayed by Mos on 2026-10-14 (lead
|
|
decision 143). Mos reviewed the 1.3 text before it landed. Version 1.4
|
|
adds REQ-WEB-3 and REQ-INST-1, approved by Jason in decisions
|
|
021af0c8 (prd.approve, yes; request dfebf8ce) and 1ea053cc (prd.approve,
|
|
yes; request b28979c9). Version 1.5 records Jason's Q167 ruling and
|
|
his added Q167 text, relayed by Mos on 2026-10-15. Under Q167 Jason's
|
|
confirmation of the text is the approval, so there is no in-Stack
|
|
prd.approve for it. Version 1.6 records Jason's ruling Q169 of
|
|
2026-10-16, on who removes and who configures the assistant. It is
|
|
never edited in place. Changes are a new version. Version 1.7 routes the
|
|
chief of staff's hire and fire actions and the coder's push to its own
|
|
fork, and adds agent host access through the credential store, approved
|
|
by Jason in decision d52febb5 (prd.approve, yes). Version 1.8 records
|
|
Jason's ruling Q188 of 2026-10-20: trusted actions within role
|
|
guardrails by default, a manual mode for per-use raises, and grants the
|
|
chief of staff requests and the user approves. Jason approved it in T3,
|
|
relayed by Mos on 2026-10-21 (DECISIONS Q192), so there is no in-Stack
|
|
prd.approve for it. Version 1.9 adds REQ-WEB-2 and amends REQ-DEC-3:
|
|
the Console decide buttons Jason approved in decision 00ed58e2
|
|
(vikunja:19/266), signed in as his Q175 ruling set, and OIDC-only as he
|
|
chose in Q203, relayed by Mos on 2026-10-21 (mos-1202). Version 1.10
|
|
adds REQ-INST-2, post-v1: the second sentence of Jason's Q203 answer,
|
|
with Mos's reading, relayed by Mos on 2026-10-21 (mos-1202, mos-1204).
|
|
Version 1.11 records Jason's ruling Q211 of 2026-10-21: v1 is the 10-27
|
|
goal. It updates the lines that the 10-27 rulings settle and adds
|
|
REQ-INST-3. Mos's reading of Q211 sets the path: one seat drafts, a
|
|
second seat reviews, and Sage lands it. So there is no in-Stack
|
|
prd.approve for it. Version 1.12 adds requirement ids for the Q176
|
|
items the PRD lacked, drafted from the approved designs, and updates
|
|
two stale lines. It takes the same path as 1.11 (mos-1229,
|
|
vikunja:19/462). Version 1.13 adds the session requirements from the
|
|
approved T1 item 7 design and replaces REQ-ROLE-2 and REQ-THREAD-2. It
|
|
takes the same path as 1.11 (mos-1231, vikunja:19/463). Version 1.14
|
|
adds the playground levels to REQ-LIB-2 and a draft universe to
|
|
REQ-LIB-3, from the approved playground ruling. It takes the same path
|
|
as 1.11 (mos-1233, mos-1238, mos-1241, vikunja:19/464). Version 1.15
|
|
rewrites REQ-LIB-6 to Jason's Q223 and Q226 rulings and adds supporting
|
|
folders to REQ-LIB-1 and REQ-LIB-2. Mos ordered it in mos-1320 item 8,
|
|
and Jason gets a report.
|
|
- Version 1.15 source: Jason's Q223, answering Q29: "The agents are not
|
|
allowed to write the prose into the writing projects. Agents are
|
|
allowed to CRUD character sheets, info summaries, cross-link info, and
|
|
supporting documentation. They are NOT allowed to actually write any of
|
|
the story." and "They are permitted to freely converse with the writer
|
|
via chat interface." His Q226: "Q30: yes." to Mos's reading that a
|
|
folder nobody has marked counts as story, and "F43: citations should be
|
|
requireable. Tunable setting." Mos's reading of F43: "require-citation
|
|
is a setting changed by a human only. Mos's default is off." The text
|
|
is drafted from the Case 2 design's ruling after r11, "agents never
|
|
write story", b68d79663 on `gosalyn/case2-design`.
|
|
- Version 1.14 source: Jason's Q176 lines TARGET.md:92 "Brainstorm ideas
|
|
in a "playground" where new universes can be created", :93 "Brainstorm
|
|
ideas in a "playground" for books in a universe" and :94 "This means
|
|
universe-level and book-level playgrounds must be provided". Mos asked
|
|
for a ruling (mos-1233). Mos ruled that the levels come in 1.14, after
|
|
1.13, once Webby approves the ruling (mos-1238 A, mos-1241). The text
|
|
is drafted from the playground ruling after r11 in the Case 2 design,
|
|
51fdfb7e2 on `gosalyn/case2-design`, approved by Webby in webby-0089
|
|
(7c00c8345 on `webby/reviews`).
|
|
- Version 1.13 source, Mos's ruling Q1 in mos-1231 on 2026-10-21: "T1
|
|
item 7 is v1." It quotes Jason's Q176 lines, TARGET.md:57 "Agents can
|
|
have multiple independent sessions within a given project (thread)",
|
|
:104 "User must be able to see the number of compactions that have
|
|
occurred for a session" and :105 "User must be able to easily clear the
|
|
context for the agent to trigger a new session". Mos's reading of Q211:
|
|
"where REQ-ROLE-2 and REQ-THREAD-2 differ from line 57, line 57 wins."
|
|
And: "The ids and the REQ-ROLE-2 and REQ-THREAD-2 changes come in 1.13
|
|
from the approved design." Mos's further readings, mos-1235 and
|
|
mos-1236, are in the Version 1.13 technical note.
|
|
- Version 1.12 source, Mos's answers to the 1.11 questions in mos-1229 on
|
|
2026-10-21: "M2: agreed. 1.11 adds no ids for the Given list or Case 2
|
|
items. You draft 1.12 from the approved #414 and #416 designs as soon as
|
|
Della approves 1.11. Vikunja 462." and "M4: fold both items into 1.12,
|
|
Vikunja 462." The two M4 items are the slice 1 Risks line and the
|
|
REQ-DEC-3 title in `packages/tasks/requirements.json`.
|
|
- Version 1.11 source, Jason's answer to Q23 in T3, relayed by Mos on
|
|
2026-10-21 (DECISIONS Q211, mos-1227): "It appears that I have expanded
|
|
the requirements for v1. My recent goal for the 10-27 release is the
|
|
goal. The PRD may need to be updated to reflect this change. The PRD can
|
|
be considered partly stale." Mos's reading, which this version follows:
|
|
- The Console's own OIDC sign-in (REQ-WEB-2) is v1.
|
|
- v1 is the 10-27 goal: Q176 (the Given list and Cases 1 and 2) plus the
|
|
later rulings that put items on the 10-27 path, such as Q179, Q184,
|
|
Q187, Q188, Q189 and Q190. Where the PRD and those rulings differ, the
|
|
rulings win.
|
|
- The answer adds to v1 and removes nothing. Cutting a v1 item goes to
|
|
Jason.
|
|
- Rulings that keep an item off the 10-27 path still hold: Q186, Q198's
|
|
timing, Q203's dragon-lin line and Q208. REQ-INST-2 stays post-v1.
|
|
- Version 1.10 source, the second sentence of Jason's Q203 answer quoted
|
|
under 1.9 below, Mos's reading of it in mos-1202, and his ruling in
|
|
mos-1204 on 2026-10-21 to add it as drafted and mark it post-v1 the
|
|
way REQ-FED-1 is (vikunja:19/458).
|
|
- Version 1.9 source, Jason's answer to Q203 in T3, relayed by Mos on
|
|
2026-10-21 (DECISIONS Q203, mos-1202): "Let's use O6. If a user does
|
|
not have an OIDC provider to configure, we will need to use a bundled
|
|
Pocket ID instances to handle this traffic." O6, as Mos put it to him:
|
|
"keep the REQ-WEB-2 wording OIDC-only. Identity is the (issuer,
|
|
subject) pair from the Console's own verified OIDC sign-in. Local
|
|
accounts come from a provider, and the Console never holds passwords."
|
|
The second sentence is not part of 1.9. It becomes its own requirement
|
|
in a later version (vikunja:19/458).
|
|
- Version 1.8 source, Jason's approval in T3, relayed by Mos on 2026-10-21
|
|
(DECISIONS Q192): "PRD 1.8: I am preemptively approving it. Do not
|
|
surface in the Mosaic Stack board. Just proceed."
|
|
- Version 1.8 source, Jason's ruling Q188 (DECISIONS, 2026-10-20), his
|
|
answers to Q8 and Q10, in part. Q8: "I would rather grant the grant
|
|
right to an agent that runs with strict guardrails. That agent presents
|
|
the final authorization for the user. Upon approval, the grant is
|
|
created programmatically. I see this as: User configures their PATs, API
|
|
tokens, authorizations within the WebUI. The agent presents the request
|
|
for grant with X rights for another agent. The user reviews, then clicks
|
|
Approve/Deny. Click of Approve fires off protected mechanical methods to
|
|
handle the grants on Github, Gitea, .... services as needed. The tooling
|
|
would need to exist and must be guarded." And "Disallowing the agents to
|
|
create grants autonomously is a necessary evil for better security.
|
|
Requiring the user to manually perform the steps is a no-fly." Q10:
|
|
"Agents should have tools and command access based on roles. Those roles
|
|
dictate the allowed tools and commands. The use of a tool or command
|
|
should not be raised to the user unless the system is configured with a
|
|
manual mode that requires user interaction. By default I want to have
|
|
the agents capable of running commands and tools at will within their
|
|
sandbox/guardrails. This allows autonomous actions by agents within
|
|
their lanes. Perhaps a "Trusted actions within approved guardrails"
|
|
methodology." And "The main agent or chief of staff would be responsible
|
|
for surfacing the request to the user's inbox for approval. Not all
|
|
agents are capable or authorized to request directly. It must follow the
|
|
chain of command properly." He agreed with Mos's Q10 points 3 to 6:
|
|
protected stack code does every step on Approve, his tokens are entered
|
|
in the WebUI and agents never see them, a command on the approved list
|
|
runs without a click and any other is refused, and he, Mos or the tester
|
|
can revoke a grant at once.
|
|
- Version 1.8 source, Jason's ruling Q190 (DECISIONS, 2026-10-20), his
|
|
answer "Q12: O1": each agent seat gets its own account on his Gitea,
|
|
created through the Q188 approval path once the Gitea grants exist.
|
|
- Version 1.8 source, Jason's ruling Q191 (DECISIONS, through Mos in
|
|
mos-1149), that the assistant and the chief of staff are separate roles,
|
|
and only the chief raises a grant request: "Q13: that looks better".
|
|
- Version 1.7 source, TARGET.md line 66: "Chief of staff agent has
|
|
hire/fire authority for agents as needed; unless user forbids per
|
|
agent". And Jason through Mos (mos-1067), DECISIONS Q183, in part: "I
|
|
will still want to allow infra agent(s) on my .53 instance to access
|
|
other servers, etc. However, not all agents will need to have that
|
|
access. I envision a credential store within Mosaic Stack that works as
|
|
some sort of variable for the agent to call. The system will enforce
|
|
access to the credentials to keep the agents sandboxed with proper
|
|
security. I need to be able to trust my agents with assisting me. This
|
|
will require sudo access to several systems. If we can utilize the
|
|
credential store in Mosaic Stack and allow agents to perform their jobs
|
|
with NOPASSWD sudo on various machines, I am a happy man." DECISIONS
|
|
Q184, on whether that is in place by 10-27: "Q5: by 10.27"
|
|
- Version 1.6 source, Jason's ruling Q169 (DECISIONS, brain repo,
|
|
2026-10-16): "The only agent that should be able to remove the
|
|
assistant role is the chief of staff. The COS and the user should have
|
|
the ability to (re)configure the assistant role and seat name. The
|
|
user via WebUI or CLI, the COS via the proper tooling."
|
|
- Version 1.5 source, Jason's words relayed by Mos on 2026-10-15:
|
|
- Q167: "Me having to approve every decision within the Stack is not
|
|
working for me. I gave a directive, I want it to be done." and "Use
|
|
the T3 seats to make these updates and changes, so I can have a
|
|
functional system."
|
|
- Q167, added text: "All north star specs should be visible and
|
|
modifiable by the user within each given Project. I need to be able
|
|
to read and make the changes ad-hoc without an agent when desired.
|
|
This will allow review and revise to occur outside the chat. The
|
|
agent will be able to see the changes of course. Changes made should
|
|
use git (at least locally) to maintain the change history.
|
|
Organization of data in a Project is critical. We need a data
|
|
structure with json files and templates for everything. Markdown
|
|
files with a WYSIWYG editor for the north star/spec files.
|
|
Documentation within the project. Consistent storage of docs, reqs,
|
|
decisions, etc. should be kept in the project for reference as
|
|
needed. We will need to have these agents for a coding workflow: -
|
|
coder - code review - security review - merge gate. The appropriate
|
|
agent profile will be assigned to the agents. The roles and tools
|
|
allow agentic control of the needed workflow steps. Autonomy within
|
|
the rails is encouraged. Agents are proactive. The rest of your
|
|
reading is accurate."
|
|
- On the revised row list (task 314, comment 225): "Your decisions look
|
|
good. Proceed."
|
|
- Jason's waits list, as Mos gave it: spending money, deleting data,
|
|
anything irreversible, new internet exposure, new external accounts,
|
|
messages to people outside the fleet, and force-push or history
|
|
rewrite. Mos's reading, Q5: "Q167 covers shrinking GATED_ONLY and the
|
|
role grants through rows 135 and 139." Sage's plan for the rows adds
|
|
that any change to the list itself, and any grant of a listed action
|
|
to a role, also goes to Jason.
|
|
- Mos's reading, Q4: agents land into the business working
|
|
repository's protected branch through the host. This repository's
|
|
canonical `refactor` branch stays the lead's landing.
|
|
- Version 1.3 source, Jason's words relayed by Mos:
|
|
- Q153: "2. agreed. Make it modular though. We should be able to
|
|
extend without code change on the core app." Mos's reading, which
|
|
Jason confirmed: the stack counts tokens itself for now, with no
|
|
CLIProxyAPI queue reader. Usage sources and quota enforcement sit
|
|
behind a plug-in interface. The first source reads the stack's own
|
|
harness transcripts. Later sources are separate modules switched on
|
|
in config, with no change to core bus or broker code.
|
|
- Q154: "Q154: yes. In fact, the whole app should use plug-in
|
|
interface. The core should allow for extension". Mos read the second
|
|
sentence back as Q155.
|
|
- Q155: "Q155: yes", to this read-back: every part the core calls out
|
|
to gets a registered plug-in interface: harnesses, model providers,
|
|
usage sources, the task tracker, the git forge, and channels such as
|
|
Discord. Adding one means adding a module and switching it on in
|
|
config, with no core code change. This applies to new work now.
|
|
Existing hard-coded parts convert as rows touch them, not in one big
|
|
rewrite.
|
|
- Plug-ins from outside the repository are a security call Q155 didn't
|
|
make. Mos is taking it to Jason (Vikunja #286).
|
|
- 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.
|
|
- Interview record: Sage's thread 1ef1e4f8. Round 1 is lead decision 45.
|
|
Round 2 is lead decision 48. Round 3 is lead decision 53. Design
|
|
inputs are lead decisions 43, 44, 46, 47 and 49 to 52.
|
|
|
|
## Introduction
|
|
|
|
### Objective
|
|
|
|
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 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
|
|
|
|
v1 has two users, each on their own instance: Jason on Case 1, the
|
|
software factory, and Melanie on Case 2, the creative writing hub (Q176,
|
|
Q211). 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. The 1.10 text began "For now the only user is
|
|
Jason.")
|
|
|
|
## Problem statement
|
|
|
|
In priority order (round 1):
|
|
1. **Admin falls on Jason.** Jason launches agents, relays between them,
|
|
finds credentials and corrects them.
|
|
2. **Jason can't see what the agents are doing or what's waiting for
|
|
Jason.**
|
|
3. **Agents drift from what the business needs.** Nothing ties a piece of
|
|
work to a stated goal.
|
|
|
|
## Scope and non-goals
|
|
|
|
### Hard limits
|
|
|
|
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 Jason's approval.
|
|
- C. Give agents Jason's personal credentials. Each role gets its own.
|
|
- D. Become a multi-tenant SaaS in v1. There is no hosted SaaS in v1.
|
|
- E. Replace Claude Code, Codex or Pi. It wraps them.
|
|
|
|
### Where it runs
|
|
|
|
Mosaic Stack stays self-hosted open source. The licence is open, and Jason
|
|
decides it later.
|
|
|
|
Self-hosted, on Jason's machines and homelab (round 1, "A first"). Cloud
|
|
workers aren't ruled out later.
|
|
|
|
v1 runs as two instances on VMs on the PVE node: Case 1 on VM 1008 and
|
|
Case 2 on VM 1012. Each instance runs under its own OS user without sudo.
|
|
Jason's workstation, dragon-lin, is for dev work only. (Q180, Q181, Q211.)
|
|
|
|
### Out of scope for v1
|
|
|
|
Round 2, "all", as version 1.11 updates it (Q211):
|
|
- businesses other than Mosaic Stack on Case 1 (SetSpark joins after
|
|
v1). Case 2's hub runs its own organization on its own instance, and
|
|
that is v1 (Q176);
|
|
- Codex (v1 covers Pi and Claude Code, and Codex comes next);
|
|
- the bundled Pocket ID (REQ-INST-2, Q203).
|
|
|
|
Version 1.11 moves three round 2 items into v1:
|
|
- Minting credentials. On the user's Approve, protected stack code makes
|
|
the key, the token or a seat's own Gitea user (REQ-GRANT-2; Q188, Q190).
|
|
- SSO. The Console runs its own OIDC sign-in (REQ-WEB-2; Q175, Q211).
|
|
- Access from beyond localhost. Each case runs on its own VM, and people
|
|
get access across the two instances (Q176, Q179, Q180). The Console's
|
|
own sign-in (Q175) comes first for any instance that a second user or
|
|
another instance can reach (Q176). A new listener reachable from outside
|
|
the host is still a `network.expose` hard wait (REQ-WAIT-1).
|
|
|
|
## Requirements
|
|
|
|
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. The
|
|
assistant is the exception: within a thread it can have several
|
|
independent sessions, each with one holder at a time. No other role
|
|
holds a thread session. A claim takes a lock and logs it. An assistant
|
|
claim names the organization, thread, instance and session. Releasing
|
|
the role or ending the run frees only that holder. Creating or clearing
|
|
a session grants no role authority, and a pending approval never moves
|
|
to another session. (Version 1.13.) 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. The assistant is the
|
|
exception here too (version 1.6, Q169): the chief of staff is the only
|
|
agent that removes it. The chief of staff removes it by ending its
|
|
runs, and that end needs no decision. A revoke of the assistant, the
|
|
chief's included, is a hard wait under REQ-WAIT-1. Anyone else's revoke
|
|
of the assistant must cite a decision the human resolved through the
|
|
CLI. A decision an arbiter resolved doesn't count, and that revoke is
|
|
refused.
|
|
- **REQ-ROLE-3.** An organization file declares the role instances,
|
|
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
|
|
assistant's name is set in the organization file. Jason's may be named
|
|
Mos. Since version 1.6 (Q169), the user and the chief of staff can
|
|
configure the assistant's role entry and its seat name: the user
|
|
through the WebUI or the CLI, the chief of staff through its broker
|
|
tools, which log each change. No other role can, and a change can't
|
|
remove the assistant's protection under REQ-ROLE-2.
|
|
|
|
Added in version 1.5 (Q167):
|
|
|
|
- **REQ-ROLE-5.** The coding workflow has four roles, each with its own
|
|
role file:
|
|
- coder, which writes the change;
|
|
- reviewer, which gives the code review verdict;
|
|
- security-reviewer, which reviews a candidate for security only and
|
|
approves or blocks with the reason. It has read-only tools and the
|
|
verdict, and no shell, no write tools and no push;
|
|
- merge-gate, which takes a candidate the reviewers approved, raises
|
|
the merge decision for it in the technical domain, so the CTO
|
|
decides, and lands it once the decision is resolved (REQ-LAND-1).
|
|
Otherwise it reports the refusal. Its one grant is
|
|
`git.merge.protected` as a cross-role action, which is what landing
|
|
checks. Raising a decision needs no grant. It has no write tools.
|
|
Because only the instance that raised an approval can consume it
|
|
(REQ-DEC-5), the role that lands is the role that raises.
|
|
|
|
Instances of these roles are added through the chief of staff's
|
|
organization change verb (REQ-ROLE-3).
|
|
- **REQ-ROLE-6.** Agents are proactive. Every role contract says: within
|
|
your grants, act on what you see without waiting to be asked, and
|
|
raise a decision or send a message for anything outside them.
|
|
|
|
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-COS-2.** The PM asks the chief of staff for staff. A staff request
|
|
names the roles and how many of each. The chief of staff launches them
|
|
through role.launch, within the agent limits (REQ-LIMIT-1). (Version
|
|
1.5.)
|
|
- **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.
|
|
- **REQ-ASSIST-3.** The assistant tells the user what other roles sent it
|
|
in its own words. It summarizes and doesn't relay their text. (Version
|
|
1.5.)
|
|
|
|
Added in version 1.7:
|
|
|
|
- **REQ-COS-3.** The chief of staff hires and fires role instances without
|
|
a decision each time. Hiring adds a role instance to the organization
|
|
file and lists it for launch. Firing ends the instance's runs and
|
|
removes it from the launch list. It stays in the organization file. Only
|
|
the user deletes an instance. These actions are `role.hire` and
|
|
`role.fire`. They leave the hard waits and route under this requirement,
|
|
within these bounds:
|
|
- The chief acts only in its own organization.
|
|
- The chief hires only role definitions that need no credentials, until
|
|
a later version adds credentialed roles.
|
|
- The chief hires only the role kinds its role file lists. Changing that
|
|
list is a reviewed commit.
|
|
- The chief hires only a role whose every action is on a fixed list of
|
|
plain work actions: sending messages, writing records, asking for
|
|
review, updating its assigned tasks, and the scope and working-push
|
|
actions of an assigned task. A role holding any other action, such as
|
|
launch, end, organization, naming, hire, review verdict or merge
|
|
authority, or any action added later, is never hired. So the chief
|
|
never hires a chief, never picks its own reviewers or merge gate, and
|
|
the author is never the reviewer. This holds whatever the role file's
|
|
list says. Adding to that list is a PRD change.
|
|
- The chief may set a hired instance's model and narrow its limits, and
|
|
nothing else about it.
|
|
- The user can forbid per agent. The user marks an instance so the chief
|
|
can't fire it, end its runs or change its model, and marks role kinds
|
|
the chief can't hire. Only the user changes these marks, through the
|
|
WebUI or the CLI.
|
|
- The kill switch stops every hire and fire while it is on.
|
|
- Every hire and fire is logged with the chief's instance, its run and
|
|
the reason.
|
|
|
|
### 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. Only
|
|
the broker reads a secret's contents. It holds them in memory and
|
|
never logs or writes them. Everything else checks a referenced file
|
|
with `stat`.
|
|
|
|
### Credentials
|
|
|
|
- **REQ-CRED-1.** Every role instance has its own token for each service
|
|
(Gitea, Vikunja). The broker holds them, and they never enter an agent's
|
|
environment or files. In v1 Jason creates them by hand from a runbook
|
|
Sage writes (round 3, 1A):
|
|
- in Gitea, a new bot user per role, named `<business>-<role>-bot`,
|
|
for example `mosaic-stack-pm-bot` (round 3, 2A; lead decision 58);
|
|
- in Vikunja, a `bot-<business>-<role>` user per role, plus one
|
|
read-only `bot-<business>-sync` that does all polling (lead
|
|
decisions 52 and 58).
|
|
|
|
Since version 1.8, a token or key for a grant is made by the grant code
|
|
on the user's Approve (REQ-GRANT-2), not by hand. Tokens that exist stay
|
|
as they are.
|
|
|
|
Since version 1.11, Gitea follows Q190: each agent seat gets its own
|
|
Gitea user through a grant (REQ-GRANT-1, REQ-GRANT-2), not a bot user
|
|
per role made by hand. Vikunja is unchanged.
|
|
- **REQ-CRED-2.** A session that finds only founder credentials stops.
|
|
|
|
Added in version 1.7:
|
|
|
|
- **REQ-CRED-3.** An agent with a grant can run commands with sudo on
|
|
another host. The agent asks for the host credential by name. The stack
|
|
checks that a grant exists for that agent and that host before the
|
|
credential is used. The agent never sees the key or any other secret
|
|
value (REQ-CRED-1, REQ-VAR-2). An agent without a grant for that host is
|
|
refused. Not every agent gets a grant. Who grants a host credential, and
|
|
how, is set by the #424 design, which Jason approves.
|
|
|
|
Added in version 1.8 (Q188):
|
|
|
|
- **REQ-CRED-4.** An action a role definition lists within-role, and that
|
|
uses a grant, runs without a decision for each use only when all of
|
|
these hold:
|
|
- the definition declares the credential kind the action uses;
|
|
- a grant names that agent, and that host or service;
|
|
- for a command, the command matches the grant's allowlist. A grant
|
|
lists exact argv prefixes. A wildcard grant is refused;
|
|
- the agent's key or token for that grant is issued and not revoked.
|
|
|
|
A command off the allowlist is refused, and adding one takes a new grant
|
|
request (REQ-GRANT-1). An action whose definition doesn't list it
|
|
within-role still needs a decision for each use. Only a reviewed role
|
|
change adds an action to a definition. `host.sudo` routes under this
|
|
requirement.
|
|
- **REQ-GRANT-1.** No agent creates or writes a grant. A grant request
|
|
follows the chain of command, and only the chief of staff raises it to
|
|
the user's inbox. Any other role that needs a grant for itself or for an
|
|
agent it directs asks the chief of staff, through its chain: a worker
|
|
role through its PM, the PM and the CTO directly. The assistant passes
|
|
the user's own request to the chief of staff (REQ-ASSIST-1). The request
|
|
names the agent, the grant method and its target, the exact rights, and
|
|
a rotate-by or expiry date. The chief raises one only for an agent whose
|
|
reviewed role definition allows that kind of credential, and the broker
|
|
refuses any other. A grant can't name a wildcard, a shell or an empty
|
|
command. The request is a decision with the action `credential.mint`, so
|
|
it goes to the user as a hard wait (REQ-WAIT-1). A grant whose method
|
|
makes an account, such as a seat's own Gitea user (Q190), is the same
|
|
one decision: the method in the grant says it makes an account, the
|
|
request names the account, and the inbox shows the account name before
|
|
Approve. The user's one resolution covers the account and its
|
|
credential, so the hard-waits list doesn't change. An `account.create`
|
|
raise isn't a grant request and routes as version 1.7 has it. The broker
|
|
checks only that the chief of staff raised the request. The chain of
|
|
command before that is in the messaging lists and the role contracts,
|
|
not a broker check. The assistant and the chief of staff are separate
|
|
roles. No agent holds both, and the broker refuses a claim that would.
|
|
- **REQ-GRANT-2.** The user approves or denies each grant request in the
|
|
inbox. Approve is the only thing that creates a grant, and the code uses
|
|
a grant only when it has a matching Approve record. No agent creates a
|
|
grant. A grant written into the business file by hand makes nothing. Row
|
|
210's hand-written grants stay a test path until Vikunja #436a moves
|
|
`host.run` to grants made by Approve. On Approve, protected stack code
|
|
does every step, not an agent and not the user: it records the grant,
|
|
makes the key or token, installs it on the machine or creates it on the
|
|
service, and logs each step. On Deny nothing is made, and the denial is
|
|
logged. The grant methods are:
|
|
- machine key: a key for one agent on one enrolled host, with the
|
|
command allowlist of REQ-CRED-4. A host's identity comes from the host
|
|
side when the user approves its enrollment, never from a first
|
|
connection. A host user with sudo receives a grant only after the user
|
|
approved that user by name;
|
|
- Gitea: a token for one agent, and for an agent seat its own Gitea user
|
|
(Q190), with an expiry. The all scope and the admin scope are never
|
|
granted;
|
|
- GitHub: a grant for one agent.
|
|
|
|
The Gitea and GitHub rights units come in a later design that Jason
|
|
approves.
|
|
|
|
The approval binds the exact rights the user saw and the target or its
|
|
enrolled identity. A change to the agent, its definition, the target,
|
|
the target's identity or the rights after the raise voids it. An
|
|
approval is used once. A grant the code couldn't finish is undone at
|
|
once on the stack's side, so it is never used. What it left on the host
|
|
or service stays visible as pending until it is removed, as for a revoke
|
|
(REQ-GRANT-4). A new grant needs a new approval, never an automatic
|
|
retry. The grant code runs only on a request the user resolved. A
|
|
request resolved by an arbiter, the tester or any agent makes nothing. A
|
|
`credential.mint` decision raised before version 1.8, or without the
|
|
fields of REQ-GRANT-1, makes nothing when it is approved. Until the
|
|
Console knows the signed-in human (Vikunja #412), Approve is
|
|
`mosaic decide` in the CLI (REQ-DEC-3).
|
|
- **REQ-GRANT-3.** The user enters their own personal access tokens and
|
|
API tokens in the WebUI, or the CLI. Only the grant code reads them, to
|
|
make grants. No agent ever sees a token value or a key's private half.
|
|
Values appear in no event, log, message, prompt or agent file, and no
|
|
agent can read them back (REQ-VAR-2). Until the Console knows the
|
|
signed-in human, they are entered through the CLI.
|
|
- **REQ-GRANT-4.** A grant can be revoked at once by the user, by the
|
|
assistant for a grant in its own organization, or by the tester on a dev
|
|
instance (Q173). A revoke needs no decision and no new trust. It takes
|
|
effect at once on the stack's side, without waiting on the network, so
|
|
the next use is refused. Removing the key or token at the host or
|
|
service follows. Until that removal is done it stays visible as pending.
|
|
A revoke while the grant is being made stops it, and nothing it made
|
|
stays usable. Every revoke is logged with who made it.
|
|
|
|
### 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 and whether it
|
|
cites the project's spec (REQ-PROJ-2). Version 1.5 replaces the 1.0
|
|
text, which sent every gated decision to the human:
|
|
- routine and within-role decisions are logged;
|
|
- cross-role decisions go to the business's arbiter for that domain;
|
|
- a gated decision whose raise cites the project's current spec commit
|
|
goes to the business's arbiter for its domain, technical or delivery,
|
|
and not to the human;
|
|
- a gated decision with no spec citation goes to the human;
|
|
- a hard wait (REQ-WAIT-1) goes to the human whether or not it cites
|
|
the spec.
|
|
|
|
A raise that cites a spec commit other than the current one is
|
|
refused, and so is a raise citing a spec whose last commit isn't the
|
|
human's.
|
|
- **REQ-DEC-3.** A human resolution, by an authorized human, comes only from a `mosaic` CLI session
|
|
or a Console session signed in under REQ-WEB-2, both 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 an authorized human
|
|
right away: in the CLI inbox, plus a Discord DM sent through the existing
|
|
connector (#1509). Everything else goes into one daily digest at 08:00
|
|
Central. (Round 2, answers 2A and 3A; round 3, 4A and 5A.)
|
|
|
|
Added in version 1.5 (Q167):
|
|
|
|
- **REQ-DEC-5.** An approval outlives the run that raised it. It binds to
|
|
the decision and to the role instance and thread that raised it. A
|
|
later run of the same instance, on the same thread, may consume it
|
|
once. The first consuming action is
|
|
recorded, a second consume is refused, and another instance can't
|
|
consume it. Superseding a decision follows the same rule.
|
|
- **REQ-DEC-6.** A new spec commit never reopens a settled decision. Each
|
|
decision records the spec path and commit its raise cited. A decision
|
|
settled under one commit stays settled when a later commit lands, and
|
|
new raises cite the new commit.
|
|
|
|
### Trusted actions
|
|
|
|
Added in version 1.8 (Q188).
|
|
|
|
- **REQ-TRUST-1.** Agents act within their role guardrails without asking.
|
|
The default mode is "trusted actions within approved guardrails". An
|
|
action a role file grants within-role is done at will, inside the
|
|
agent's sandbox, its tool limit and its grants, and is logged. It raises
|
|
nothing to the user. An action the file doesn't grant within-role still
|
|
routes by REQ-DEC-2, and a hard wait still goes to the user
|
|
(REQ-WAIT-1). Only a reviewed role change adds an action to a role file,
|
|
and REQ-WAIT-2 still keeps every hard wait out of every role file.
|
|
- **REQ-TRUST-2.** The user can put chosen actions in manual mode. The
|
|
organization file holds the list of actions in manual mode, empty by
|
|
default. While an action is on the list, every use of it by any role
|
|
becomes a decision for that use, raised to the user, and the action
|
|
waits until the user resolves it. A decision denied, or not resolved,
|
|
refuses the action. Each decision is used once. For a command on another
|
|
host, the decision names the host, the command and its input. Actions
|
|
not on the list are unchanged. Only the user changes the list, through
|
|
the WebUI or the CLI. The chief of staff's organization writes
|
|
(REQ-ROLE-3) can't change it, and no agent can. Every change is logged
|
|
with who made it. A change applies to the next use, and a run already in
|
|
progress keeps no exemption.
|
|
|
|
### Hard waits
|
|
|
|
Added in version 1.5 (Q167).
|
|
|
|
- **REQ-WAIT-1.** These are the hard waits. Each always goes to the
|
|
human, and each maps to actions in the closed vocabulary:
|
|
|
|
| Jason's wait | Actions |
|
|
| --- | --- |
|
|
| Spending money | `spend` |
|
|
| Deleting data | `data.delete`, new in 1.5 |
|
|
| Anything irreversible | `data.delete`, `git.push.protected` and REQ-WAIT-3 |
|
|
| New internet exposure | `network.expose`, new in 1.5: a listener, port, tunnel, DNS record or proxy route reachable from outside the host. `deploy` stays a hard wait too. |
|
|
| New external accounts | `account.create`, new in 1.5, and `credential.mint` |
|
|
| Messages to people outside the fleet | `message.external` |
|
|
| Force-push or history rewrite | `git.push.protected`, which covers a push to a protected branch and any force push or history rewrite on any branch |
|
|
|
|
The always-gated lists in the broker and the business vocabulary hold
|
|
exactly these actions. `git.merge.protected`, `policy.change`,
|
|
`prd.approve` and `role.revoke` leave those lists and route by
|
|
REQ-DEC-2. REQ-ROLE-2 still requires a resolved decision for a revoke.
|
|
Since version 1.6 (Q169), a `role.revoke` of the assistant is a hard
|
|
wait: its raise goes to the human, cited or not, and no arbiter
|
|
resolves it. Every other cited revoke routes by REQ-DEC-2.
|
|
- **REQ-WAIT-2.** No role file may grant a hard-wait action, at any
|
|
class, and the validator refuses a file that does. A change to the
|
|
hard-waits list, or a grant of a hard-wait action to a role, is itself
|
|
a hard wait. The list changes only by a reviewed commit to the
|
|
vocabulary, under a new PRD version that Jason approves.
|
|
- **REQ-WAIT-3.** An action added to the vocabulary is a hard wait until a
|
|
PRD version says it isn't. The reviewed commit that adds it names which
|
|
it is.
|
|
|
|
`role.hire` and `role.fire` were added as hard waits and route under
|
|
REQ-COS-3 since version 1.7. `git.push.remote` was added as a hard wait
|
|
and routes under REQ-LAND-2 since version 1.7.
|
|
|
|
`host.sudo` was added as a hard wait and routes under REQ-CRED-4 since
|
|
version 1.8.
|
|
|
|
### Messages
|
|
|
|
- **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.
|
|
- **REQ-MSG-2.** Messages can also be addressed by agent name. A role
|
|
instance may have a name, unique in its business, that equals no
|
|
instance key and no role name. A send takes a name or a role. A name
|
|
resolves to its instance, the message records both, and a role still
|
|
delivers as REQ-MSG-1 says. The human sets names through the CLI. The
|
|
chief of staff sets them once its role file grants that within-role.
|
|
(Version 1.5.)
|
|
|
|
### 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. Each task
|
|
field has one writing role, listed in the slice 1 brief's field table,
|
|
and the assigned role writes the task's state. Vikunja's token scopes
|
|
cover whole route groups, so the broker's verbs enforce this, not the
|
|
tokens. A person's edits come in as events.
|
|
- **REQ-TASK-2.** Polling is the source of truth. Every 30 seconds the
|
|
sync bot reads each project's open-task board and the tasks updated
|
|
since the last check, so column moves and deletions of open tasks show
|
|
up within one poll. An hourly full reconcile catches the rest. Slice 1
|
|
uses no webhooks. (Lead decisions 51 and 52.)
|
|
- **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.
|
|
|
|
### Projects
|
|
|
|
Added in version 1.5 (Q167).
|
|
|
|
- **REQ-PROJ-1.** Each project keeps its records in its own local git
|
|
repository, separate from its code checkout, with no remote. The
|
|
layout is fixed and versioned: `project.json`, `spec/north-star.md`,
|
|
`docs/`, `requirements/` and `decisions/` with one JSON file per
|
|
record, and `templates/` with a template for each kind. Each JSON kind
|
|
has a schema, and a record that fails it is refused. `mosaic project
|
|
init` creates the repository with its first commit as the business's
|
|
human.
|
|
- **REQ-PROJ-2.** The north-star spec is `spec/north-star.md` in the
|
|
project repository. Only the human commits to it. Agents read it and
|
|
never write it. The spec counts only when its last commit's author is
|
|
the business's human. Agents write docs, requirements and decisions as
|
|
agent-authored commits, through the layout's validators.
|
|
- **REQ-PROJ-3.** The Console has an editor for the spec and the
|
|
Markdown files in `docs/`. The user opens a file at its current commit,
|
|
edits its Markdown source beside a rendered preview, and saves it as
|
|
one local commit with the human as author. A save made from a commit
|
|
older than the file's last commit is refused and writes nothing. The
|
|
preview runs no script from the file and is built from code in this
|
|
repository. A WYSIWYG editor may replace the source view only with a
|
|
library that is vendored and pinned with a permissive license and a
|
|
recorded hash for each file, loads nothing at runtime, and needs no
|
|
change to the Console's content security policy. No library passed
|
|
that for 1.5.
|
|
- **REQ-PROJ-4.** Agents review the human's spec commits. Each human
|
|
commit to the spec saved through the Console editor (REQ-PROJ-3) sends
|
|
one notice to the PM and the CTO. A commit the human makes with git
|
|
outside the Console sends no notice yet. They check
|
|
the change against settled decisions and work in flight, and each
|
|
answers with an accept or a BLOCK that names the conflict. A BLOCK
|
|
doesn't revert the commit. It goes to the assistant through the chief
|
|
of staff (REQ-ASSIST-2), and the assistant tells the user (REQ-ASSIST-3).
|
|
|
|
### Landing
|
|
|
|
Added in version 1.5 (Q167, Mos's reading Q4).
|
|
|
|
- **REQ-LAND-1.** Agents land approved merges into the business working
|
|
repository. The run that holds an approved `git.merge.protected`
|
|
decision asks the host to land the work ref the decision names into
|
|
the working repository's `main`. The host runs the landing checks and
|
|
the project's gate:
|
|
- the decision is resolved with the approval option;
|
|
- the ref is at the reviewed commit, and a verdict approves it;
|
|
- the decision isn't superseded;
|
|
- the base hasn't moved.
|
|
|
|
A refusal is logged on the task's trail with its code, and a project
|
|
with no gate is refused. A landing is recorded as the allowed action
|
|
with the landed commit, and it consumes the decision (REQ-DEC-5). This
|
|
repository's canonical branch is never a target.
|
|
|
|
Only a role whose role file grants `git.merge.protected` as a
|
|
cross-role action can land. A merge decision raised by a role without
|
|
that grant is gated, and its approval never lands, whether the arbiter
|
|
or the human gave it. So an arbiter's judgment can't move landing to a
|
|
role REQ-ROLE-5 didn't give it. The land operation refuses a gated
|
|
decision; the check ships with whichever of rows 137 and 139 lands
|
|
second.
|
|
|
|
Added in version 1.7:
|
|
|
|
- **REQ-LAND-2.** A coder pushes its own work to its own fork. The action
|
|
is `git.push.remote`.
|
|
- What it pushes: one commit, by its oid, never a ref name. That commit
|
|
is the latest work commit the bus recorded for the coder's task, and
|
|
the coder made that push. A decision that authorizes a push names that
|
|
commit, and it doesn't authorize any other.
|
|
- Where it lands: only the branch
|
|
`refs/heads/<its Gitea user>/<branch>`. The host builds that name, the
|
|
agent never does. A push never forces.
|
|
- Which remote: the agent's own fork of the project's upstream. The
|
|
business file names the upstream, and the host never contacts it. For
|
|
each push the host builds the fork's address over https from the
|
|
upstream's host, port and repository name and the agent's own Gitea
|
|
user. The history check, the push and the credential match all use
|
|
that address. So the agent's own user owns the receiving repository on
|
|
every push, and the agent never names it.
|
|
- The host refuses an upstream on a host or port other than the agent's
|
|
Gitea, and an upstream the agent's own user owns. It refuses a fork
|
|
that is missing, empty or doesn't share the project's history. Gitea's
|
|
push-to-create stays off, so a push never creates a repository.
|
|
- Who may: the action routes under REQ-DEC-2 and is granted within-role
|
|
to the coder role only. No other role file grants it.
|
|
- Before version 1.7 the action was a hard wait under REQ-WAIT-3, so
|
|
each push needed a decision the human resolved, and that decision
|
|
named the commit.
|
|
|
|
Every push is logged with the remote, the ref, the commit and, when one
|
|
was given, the decision.
|
|
|
|
### Interface
|
|
|
|
- **REQ-CLI-1.** `mosaic` is the front door. From it Jason can:
|
|
- 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 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. 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).
|
|
- **REQ-WEB-2.** The Console resolves an open decision with one button
|
|
per option, only for a human it signed in itself, recorded via=console.
|
|
(Version 1.9, decision 00ed58e2, Q175 and Q203.)
|
|
- Identity is the (iss, sub) pair the Console verified from its own
|
|
OIDC session after `--sso` sign-in (Q175), and that pair must map to
|
|
an authorized human. The Console takes no identity from a proxy
|
|
header and none from a shared secret.
|
|
- A request that carries an agent session or a seat credential is
|
|
refused.
|
|
- The decision event records via=console and the (iss, sub) pair.
|
|
- Without a signed-in session, the Console resolves nothing and shows
|
|
the `mosaic decide` line instead.
|
|
- **REQ-WEB-3.** The Console has controls to restart the bus and to
|
|
reload the organization file. Each control is a gated, trailed action.
|
|
A reload applies `launch.instances` changes to running sessions without
|
|
a manual `systemctl restart`. (Version 1.4, decision 021af0c8.)
|
|
|
|
### Launching
|
|
|
|
- **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;
|
|
- 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.
|
|
|
|
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, from
|
|
the usage sources switched on (REQ-LIMIT-4), 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 daily quota
|
|
is a limit check (REQ-LIMIT-4). The count covers sessions the stack
|
|
ran. Use of the same account outside the stack isn't counted, and
|
|
Settings says so. The stack doesn't read the proxy's usage queue
|
|
(Q153). A per-key count from the proxy would be a later usage source.
|
|
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, from the usage sources switched on
|
|
(REQ-LIMIT-4), and the user and the chief of staff can reset it. A
|
|
count is the sum of every kind a source 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. The token limit is a limit check
|
|
(REQ-LIMIT-4).
|
|
- **REQ-LIMIT-4.** Token counting and limit enforcement are the first two
|
|
plug-in kinds (REQ-PLUG-1, Q153):
|
|
- `usage-source`: after each turn it reads what the session used and
|
|
returns records per run, role instance, provider, model and account,
|
|
with each token kind separate, or "unknown" for the turn.
|
|
- `limit-check`: from those records and the organization file's
|
|
limits, it answers whether a launch may start and whether a running
|
|
session must stop at the end of its turn.
|
|
|
|
The organization file can switch on several of each. A source that
|
|
fails during a turn, or can't read it, records the turn as unknown,
|
|
never as zero. With no source switched on, every turn is unknown.
|
|
Checks count known records only. Each unknown turn is logged, and
|
|
Settings shows the number of unknown turns next to each total, so a
|
|
limit never looks further off than it is. A limit that no switched-on
|
|
check enforces shows in Settings as not enforced. The first
|
|
source, `transcript`, reads the stack's own harness transcripts. The
|
|
first checks are `token-limit` (REQ-LIMIT-3) and `daily-quota`
|
|
(REQ-LIMIT-2). A CLIProxyAPI reader or another provider's report would
|
|
be a later source.
|
|
|
|
### Plug-ins
|
|
|
|
Added in version 1.3 (Q155).
|
|
|
|
- **REQ-PLUG-1.** Every part the core calls out to is a plug-in kind:
|
|
harnesses, model providers, usage sources, limit checks, the task
|
|
tracker, the git forge and channels. The kinds are a registry in one
|
|
file, `packages/plugins/src/kinds.mjs`. Each entry names the kind, the
|
|
exports a module of that kind must have, the kind's interface version,
|
|
and whether the organization file switches on one module of the kind
|
|
or a list. A module is a directory, `packages/plugins/<kind>/<name>/`,
|
|
whose `index.mjs` exports what its kind needs.
|
|
|
|
The organization file's `plugins` object switches modules on by name,
|
|
one key per kind, through the write path (REQ-ROLE-3). Each change is
|
|
logged with who made it and the old and new names. Core code reaches a
|
|
module only through the loader, never by importing it. Adding a module,
|
|
or switching one on or off, needs no core code change. Adding a kind is
|
|
a core change, because it adds a place the core calls out, and it lands
|
|
by reviewed commit with its first module.
|
|
|
|
The loader takes names from the organization file, never paths. It
|
|
refuses a name, and the old setting stays, when:
|
|
- the name doesn't match `^[a-z][a-z0-9-]*$`;
|
|
- no directory of that name exists under its kind;
|
|
- any part of the path, `index.mjs` included, is a symlink;
|
|
- the module fails to load;
|
|
- the module lacks an export its kind needs, or declares another
|
|
interface version.
|
|
|
|
A module runs inside the host process with the host's authority, so
|
|
only modules in the repository's `packages/plugins` load, until Jason
|
|
rules on others (Vikunja #286). A module goes live like any other code,
|
|
through a re-pin. Switching a module on gives it no authority of its
|
|
own: the human proof (REQ-DEC-3), the broker's credentials and the role
|
|
checks stay in core, and a channel module carries messages without
|
|
proving who sent them. A module's credential is a reference the broker
|
|
resolves, never the secret (invariant 3).
|
|
- **REQ-PLUG-2.** New work that calls out to a part of a plug-in kind goes
|
|
through that kind from the start. A hard-coded part converts when a row
|
|
changes it, not in one rewrite (Q155). Until it converts, Technical
|
|
considerations lists where it is hard-coded.
|
|
|
|
### 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.
|
|
|
|
### Organizations
|
|
|
|
Added in version 1.1 (decision 03130d08).
|
|
|
|
- **REQ-ORG-1.** "Business" is renamed "organization". One install holds
|
|
one or more organizations, and each organization has its own bus as the
|
|
tenant boundary.
|
|
- **REQ-ORG-2.** The data model is install, then organization, then
|
|
projects, then threads, so v1 doesn't lock in one human per
|
|
organization.
|
|
- **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. A thread holds one or more independent
|
|
sessions of its assistant, on pi or Claude Code. Each session has its
|
|
own messages, native context, workspace and compaction count, and only
|
|
one run writes its workspace at a time. A thread's messages are kept.
|
|
When the user comes back to a session, after an idle stop or a restart,
|
|
the assistant picks up where that session left off, never in another
|
|
session. A client that names only the thread uses that thread's saved
|
|
default session. One session's conversation never appears in another
|
|
session, thread or organization, under REQ-USER-2, REQ-USER-3 and
|
|
REQ-USER-4. Added in version 1.2. (Version 1.13: sessions, from the
|
|
design `docs/plans/2026-10-21_t1-sessions.md`, 2c843d190 on `huey/t1-sessions-design`, approved by Scrooge in scrooge-0007 and scrooge-0008, D1 to D3 and D9.)
|
|
- **REQ-TPL-1.** Templates exist for agent roles and for organization
|
|
types.
|
|
- **REQ-FED-1.** Installs can federate with each other. Person-to-person
|
|
federation is v1: a person gets access to another instance by signing in
|
|
to its Console (REQ-WEB-2), the broker enforces the grants that give
|
|
that access, and the access can be revoked. Agent-to-agent federation is
|
|
post-v1. (Version 1.11; Q179, Q180, Q211. The 1.10 text ended "This is
|
|
post-v1.")
|
|
|
|
Added in version 1.12 (Q176, Q211). Each one names the approved design it
|
|
is drafted from and the Q176 item it covers.
|
|
|
|
- **REQ-USER-3.** An organization can have more than one human. The
|
|
organization file's human is the owner. The owner adds other humans as
|
|
users and gives each a grant per project and instance, at one of two
|
|
levels. A collaborator creates threads and sends in them. A viewer can't
|
|
create, open or send in a thread. It only reads threads shared with it
|
|
and its own threads from an earlier collaborator grant, and only while
|
|
its grant still covers them. Only the owner adds or removes users,
|
|
changes grants and restructures the organization. The bus takes a
|
|
human's identity only from something it verifies, such as the Console's
|
|
own OIDC sign-in, never from a process's own claim. (Row 193 design r5,
|
|
e2d161e2e on `morgana/row193`, approved by Duckworth in duckworth-0018,
|
|
sections 3 and 4. Q176 Given "RBAC enforcement"; Case 1 "Additional
|
|
users can be configured for access".)
|
|
- **REQ-USER-4.** A thread is private to the user who owns it unless that
|
|
user shares it. A share is read-only, to a named user, to the
|
|
organization's owner, or to everyone granted on the thread's project.
|
|
REQ-USER-2 still holds for writes. A share never widens a grant: it
|
|
counts only while the reader's grant covers the thread, unless the
|
|
reader is the owner. If the thread belongs to a granted user rather
|
|
than the organization's owner, that user's grant must still cover the
|
|
thread too. A revoke or an expiry of either grant, or an unshare, ends
|
|
the reader's access on the next request. A user's messages stay private from the owner. What the thread's agent
|
|
does with the owner's authority stays visible to the owner: its
|
|
decisions, inbox entries, claims, tasks and project files. (Row 193
|
|
design r5, sections 5.3, 5.6 and 5.7. Q176 Case 1 "Shared and private
|
|
agent sessions available per user; RBAC".)
|
|
- **REQ-LIFE-1.** The user creates, launches, terminates, regenerates and
|
|
deletes agents whenever they choose, from the CLI and from the Console.
|
|
Regenerate starts a fresh session with the same identity and role.
|
|
Each verb is a human verb behind the human proof, and it acts on its
|
|
own instance only. Every launch goes through the one launch path, so the
|
|
agent limits and the kill switch (REQ-KILL-1) apply. Delete leaves run
|
|
records write-once. Fire and delete revoke the agent's credentials
|
|
first, and a failed revoke stops the verb and leaves the organization
|
|
file unchanged. Create, delete, hire, fire and veto changes take effect
|
|
without a bus restart. Until REQ-USER-3 is built, these verbs are
|
|
owner-only. (Row 194 design r4, 7d0788236 on `honker/row194`, approved
|
|
by Webby in e1e64ff01, sections D1, D3 and D4, and the brief's items 7
|
|
and 8. Q176 Given "User and main agent (chief of staff, or other main)
|
|
can create and spawn agents" and "User maintains ability to terminate,
|
|
regenerate, or create agents via WebUI or CLI ad-hoc".)
|
|
- **REQ-KILL-1.** One CLI command and one Console button stop all
|
|
processing on an instance at once, and it stays stopped until a human
|
|
clears it:
|
|
- agent verbs that start or continue work refuse with a fixed code.
|
|
Reads and the human's own verbs, the clear included, still work;
|
|
- every running managed session and task run gets SIGTERM, then SIGKILL
|
|
after a bounded wait, and each stop is an event;
|
|
- Discord stops and can't restart;
|
|
- every launch path refuses, the chief of staff's hires included.
|
|
|
|
The switch survives a bus restart and a reboot, and it stops one
|
|
instance only. Only a human turns it on or clears it, through the human
|
|
proof, and each act is one event with who and when. (Row 191 design r2,
|
|
approved by Dewey in comment 29473, on the brief
|
|
`docs/plans/2026-10-20_kill-switch.md`. Q176 Given "'Kill switch' is
|
|
available to stop all processing immediately".) Q198's protected mode
|
|
is a separate state. The system manager never sets or clears the
|
|
switch, and protected mode can clear itself but never a human kill
|
|
(`docs/plans/2026-10-21_q198-system-manager.md` D13 and section 5).
|
|
|
|
Added in version 1.13 (Q176, Q211, mos-1231). Drafted from the
|
|
design `docs/plans/2026-10-21_t1-sessions.md`, 2c843d190 on `huey/t1-sessions-design`, approved by Scrooge in scrooge-0007 and scrooge-0008. They cover MVP plan T1 item 7.
|
|
|
|
- **REQ-SESS-1.** The user sees how many compactions each session has
|
|
completed over its life, on pi and Claude Code. Starts, failed
|
|
compactions, branch summaries and repeated reads don't count. An idle
|
|
stop or a restart leaves the count as it is. A new session and a clear
|
|
successor start at zero, and a retired session keeps its count. When
|
|
the count can't be proven, it shows unknown with the reason, never
|
|
zero. Anyone who can read the thread sees the count. The organization's
|
|
owner can see a count and status, with opaque ids only, for another
|
|
user's thread it can't read, but no names, messages or summaries.
|
|
(Design D4 and D6, tests T3 and T5. Q176 TARGET.md:104.)
|
|
- **REQ-SESS-2.** Clear context ends one session and starts a fresh
|
|
successor for the same assistant. Two humans can create or clear a
|
|
session: the organization's owner on its own thread, subject to the
|
|
instance's policy, and a collaborator who owns the thread, while a
|
|
write grant still covers it. The organization's owner on another
|
|
user's thread, a viewer, a share recipient and an agent can't. Clear waits until the session stops at a turn boundary
|
|
with no child running, and shows that it is clearing until then. It
|
|
never force-stops a busy session. The old session's messages, results
|
|
and run evidence stay as they are. Its workspace stays at its path with
|
|
any unpushed work, and nothing writes there again. The successor gets
|
|
new native stores and a fresh checkout of the approved revision. It
|
|
gets nothing of the old context: no history, summary, prompt or pending
|
|
input. Undelivered old input is cancelled with a receipt, never
|
|
replayed. A repeated clear returns the same operation, and one clear
|
|
makes at most one successor. (Design D4, D5 and D7, tests T4 and T5.
|
|
Q176 TARGET.md:105.)
|
|
- **REQ-SESS-3.** Every start of a session goes through the same checks
|
|
as any launch: an open, a first send, a restart, an idle wake and a
|
|
clear successor. The checks are the human's current authority, the
|
|
configured role and harness, launch revocation, the kill switch
|
|
(REQ-KILL-1), the agent limits and admission. The claim is checked
|
|
again just before the spawn. A session never picks its own route or
|
|
priority. An admission service that is switched on but unavailable
|
|
refuses. While the kill switch is on, a clear or a new start refuses
|
|
with `processing-halted` and changes nothing. A clear never sets or
|
|
clears the kill switch. (Design D8, test T6.)
|
|
|
|
### Creative library
|
|
|
|
Added in version 1.12 (Q176 Case 2, Q211). Drafted from the Case 2
|
|
design r11, fb20a61b4 on `gosalyn/case2-design`, approved by Webby in
|
|
82f50d127, with the rulings recorded after r11 up to 624212842. The
|
|
library is the user's own writing repository.
|
|
|
|
- **REQ-LIB-1.** A library project maps the user's writing repository
|
|
onto universes, books, entity types such as character and place, the
|
|
manuscript, playgrounds and supporting folders. The mapping sits in the
|
|
organization file and fits the user's own folder layout. Only the
|
|
human changes it, and an agent's organization write that changes it
|
|
is refused. So
|
|
`universe.book.{character,place,...}` reads as universe, book folder,
|
|
type folder. (Design 1.1 and M9. Q176 Case 2 "Data is stored in
|
|
little-endian organizational scheme". Version 1.15: supporting
|
|
folders.)
|
|
- **REQ-LIB-2.** Playgrounds are never confused with canon. A playground
|
|
has one of three levels, set by where its prefix sits. A book-level
|
|
prefix lies inside one of its universe's book folders, and its files
|
|
have that universe and that book. A universe-level prefix lies outside
|
|
every book folder, and its files have the universe and no book. A
|
|
draft universe is where a new universe starts: a universe entry with a
|
|
name, one or more playground prefixes and no books. Every file under it
|
|
is playground, with no book. When the draft is real, the human edits
|
|
the organization file to make it a plain universe with books. The
|
|
mapping is refused when a prefix lies inside or holds another
|
|
universe's book folder, when a prefix equals or holds a book folder of
|
|
its own universe, when two prefixes overlap, when a draft has books or
|
|
no prefix, and when a hybrid names a draft as a source. Supporting
|
|
prefixes, the folders agents may write in (REQ-LIB-6), follow the same
|
|
placement rules. A file's scope comes from its path alone, prefixes
|
|
first: a Markdown file under a supporting prefix is supporting, one
|
|
under a playground prefix at any level is playground, any other
|
|
Markdown file in a book folder is canon, and everything else is
|
|
unmapped and never returned. A folder in both lists is supporting.
|
|
Lookups return canon unless the caller asks for playground or
|
|
supporting. A citation marked as canon must name a canon file, so an
|
|
agent can't cite a playground or supporting file as canon. The Console
|
|
shows each cite's scope. (Design 1.2, 5.2 and 7.4, the playground
|
|
ruling, 51fdfb7e2, and the ruling after r11. Q176 Case 2, the
|
|
playground items, TARGET.md:92-94. Version 1.14: the levels and the
|
|
draft. Version 1.15: supporting.)
|
|
- **REQ-LIB-3.** Universes stay separate. Every lookup names one universe,
|
|
and its results never leave it. A draft universe (REQ-LIB-2) counts as
|
|
a universe here. It has no canon, so a lookup in a draft asks for
|
|
playground, and a citation from another universe into a draft is
|
|
cross-universe. A universe-level or draft file has no book: a lookup
|
|
that names a book leaves it out, and the manuscript lookup doesn't read
|
|
it. (Version 1.14.) A crossover is a hybrid universe that
|
|
only a human creates, by editing the organization file. It names two or
|
|
more source universes. Its lookups see its own files plus the sources'
|
|
canon, minus the exclusions the human sets. Code checks two kinds of
|
|
constraint: an exclusion keeps a source path out of the hybrid's
|
|
lookups, and a change to a pinned value in a hybrid file is reported.
|
|
A pin doesn't stop the change. The continuity agent reads the human's other
|
|
constraints and cites them. (Design 1.4 and 3. Q176 Case 2, the
|
|
crossover items.)
|
|
- **REQ-LIB-4.** Git holds every change. The user commits and pushes with
|
|
their own tools, today Obsidian with obsidian-git. The bus keeps a
|
|
mirror of the remote, fetched with a read-only token every 60 seconds
|
|
and before any lookup when the last fetch is older than that. It only
|
|
fast-forwards. A force-push is held as `library-diverged` until a human
|
|
accepts it. Agents read only the mirror's served commit and never hold
|
|
a copy of their own, so they see the user's push within about a minute.
|
|
Bus writes and pushes come in later rows (C2-02, C2-03b). (Design D5,
|
|
D6, 7.1, 7.2 and 7.5. Q176 Case 2 "Git is used for all changes -- local
|
|
and remote" and the sync items.)
|
|
- **REQ-LIB-5.** Agents check the library through typed lookup tools:
|
|
find, get, search, manuscript and universe. Each answer names the
|
|
commit it read. Get returns a file's links out and links in, so the
|
|
connections are visible to agents. The user sees them in Obsidian's
|
|
graph and backlinks. (Design 3 and 7.1. Q176 Case 2 "The agents have
|
|
tools to check character, place, and other data", the visualization
|
|
item and "Connections are always visible".)
|
|
- **REQ-LIB-6.** The creative roles are ideas, research, proofreader,
|
|
fact-checker and continuity, plus a companion role that the user's own
|
|
named agents run as. Agents never write the story. A creative agent may
|
|
create, edit and delete Markdown files only under the supporting
|
|
folders a human marks (REQ-LIB-1), such as character sheets, summaries,
|
|
cross-link notes and research notes. Every other path in the user's
|
|
repository is read-only to it, chapters and unmarked folders included,
|
|
and the broker refuses such a write before any git call. Each agent
|
|
write is one commit by that agent's own Gitea account, with a trailer
|
|
naming the agent. The user sees a notice for it and can revert it. Its
|
|
tools are the lookups, a message to the human and the two write tools,
|
|
and research and companion also fetch web pages through the broker.
|
|
Agents talk with the user in free text. A reply may cite lines of the
|
|
repository at a commit or pages the agent fetched, and the broker
|
|
checks every citation before it stores the message. A setting,
|
|
`requireCitation`, makes every reply carry a citation, except the
|
|
runner's fixed notices for no answer, a failed turn, no answer passing
|
|
the citation check and an answer too long to send. Only the human
|
|
changes it, and it is off by default. The user sees only stored
|
|
messages, on every channel. (Design 4, 5.2 and the ruling after r11.
|
|
Q223 and Q226. Q180 for Bean and Chet. Q176 Case 2, the agent list,
|
|
"User sets strict guardrails for agent capabilities" and TARGET.md:101
|
|
"Agents NEVER write prose for the user". Version 1.15.)
|
|
- **REQ-LIB-7.** The user talks to several creative agents in one chat. A
|
|
room holds one thread per creative agent in a project. A message goes
|
|
to every agent in the room, or only to the agents named by @tags at its
|
|
start. An unknown tag is refused, and nothing is sent. The room shows
|
|
the threads as one timeline, and each agent sees only its own thread.
|
|
(Design D4 and 6, row C2-09b. Q176 Case 2 "converse with N agents in
|
|
one chat session with @tagged messages".)
|
|
|
|
### Installer
|
|
|
|
Added in version 1.4 (decision 1ea053cc).
|
|
|
|
- **REQ-INST-1.** The installer offers optional components. Each one is
|
|
pinned, health-checked and removable, and is switched on in the
|
|
organization file or system config. The first is SearXNG: JSON output
|
|
enabled, limiter off, bound to loopback only.
|
|
- **REQ-INST-2.** Jason, Q203: "If a user does not have an OIDC provider
|
|
to configure, we will need to use a bundled Pocket ID instances to
|
|
handle this traffic." This is post-v1. (Version 1.10, Q203.) Mos's
|
|
reading (mos-1202), following lead decision 44 items 5 and 6:
|
|
- The installer offers two choices: point the Console at one or more
|
|
existing OIDC providers, or deploy a bundled Pocket ID.
|
|
- The stack installs that Pocket ID as an install component under
|
|
REQ-INST-1 and writes it as the Console's one providers entry. No
|
|
Pocket ID source goes in the repository, and the Console gets no
|
|
sign-in path apart from its own OIDC sign-in (REQ-WEB-2).
|
|
- Pocket ID is passkey-only for people. Agents keep per-role service
|
|
tokens.
|
|
|
|
Added in version 1.11 (Q187, Q189, Q211):
|
|
|
|
- **REQ-INST-3.** Install and upgrade are one command each.
|
|
- Install sets up a fresh host as a named instance with its config. The
|
|
per-case setup is installer config, a profile per case, not one-off
|
|
scripts.
|
|
- Upgrade backs up, moves to the new release, and rolls back if its
|
|
checks fail.
|
|
- Both are proven on a throwaway VM on the PVE node, install, upgrade to
|
|
the next release, then rollback, before either v1 VM gets the stack.
|
|
- Both v1 profiles enable the Console unit, so the Console starts at
|
|
install and at every boot (Q189). dragon-lin is unchanged.
|
|
- The container-based install comes after v1.
|
|
|
|
## Acceptance criteria and success measures
|
|
|
|
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; the assistant and threads from version 1.2.)
|
|
|
|
Version 1.5 adds Jason's Q167 acceptance run, `docs/acceptance/314.md`.
|
|
It passes when one need goes from Jason's spec to a landed commit with
|
|
only hard waits in his inbox.
|
|
|
|
Version 1.11 adds the 10-27 goal (Q176, Q211). v1 is also done only when
|
|
both instances are installed and handle their cases: Case 1, the
|
|
software factory, and Case 2, the creative writing hub. 2026-10-27 is a
|
|
latest-by date and a hard target (Q176).
|
|
|
|
## Technical considerations
|
|
|
|
- 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`.
|
|
- 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/<dir>/<session id>.jsonl`, has `model` and
|
|
`usage` (input, output, cache write, cache read tokens) on each
|
|
answer line. Checked on run re32fc7bd8143, model claude-sonnet-5-5.
|
|
- Pi: the session file in the run's session directory has `provider`,
|
|
`model` and `usage` (input, output, cacheRead, cacheWrite,
|
|
totalTokens, cost) on each answer line. Checked on a Researcher
|
|
session, provider zai.
|
|
- The launch log has harness, model and family per launch, and no
|
|
tokens (`launcher.mjs:269`, `:294`).
|
|
- Today every Claude Code session runs on one credential, which the bus
|
|
unit's environment file sets (`SESSION_CREDENTIALS`,
|
|
`packages/seat/src/session.mjs:76`, decision 119). The stack has no
|
|
name for that account. A quota per account needs the organization file
|
|
to name each account and its credential reference (never the secret,
|
|
invariant 3), and the launch to pick one and log its name. More than
|
|
one account at a time needs the bus to hand a credential to each
|
|
session, which is the open question in the #237 design row.
|
|
- CLIProxyAPI, from Researcher's stand-in test (commit 587e64a27,
|
|
`agents/researcher/work/i1-proxy-test/REPORT.md`): usage counters are
|
|
kept per upstream credential, not per client key. Per-request events
|
|
name the client key, but they last 60 seconds, a read removes them, and
|
|
they carry the full plaintext key. All of it is behind the management
|
|
API, which no agent calls. The stand-in didn't model token counts.
|
|
So the stack can't read per-key usage from the proxy today. It counts
|
|
its own sessions' tokens instead, and a per-key quota needs the stack
|
|
to issue the keys (#237).
|
|
- Token limits stop a session at the end of a turn, because the runner
|
|
learns usage only when the turn ends. A long turn can go past its
|
|
limit. Stopping inside a turn needs the runner to read streamed usage
|
|
from each harness, which changes the adapter contract (stdout is the
|
|
answer only, `adapters/README.md`).
|
|
- Version 1.3:
|
|
- Nothing loads a module by name today. The seams that exist are the
|
|
adapter script contract (`adapters/README.md`), the tasks handle the
|
|
broker takes (`startBroker({ tasks })`, `packages/bus/src/runtime.mjs`),
|
|
the engine the Discord connector takes (`createConnector({ engine })`)
|
|
and the validated provider, account and harness records in
|
|
`packages/mosaic/src/registry.mjs`, which nothing outside
|
|
`packages/mosaic` imports.
|
|
- The loader reads the tree the stack runs from. Since row 85 that is a
|
|
pinned copy, so the copy's `packages/plugins` is the set of modules a
|
|
running stack can switch on.
|
|
- Where each kind is hard-coded today (REQ-PLUG-2), from Sage's
|
|
read-only survey on 2026-10-14:
|
|
- Harnesses: the list `["pi", "claude-code"]` and its branches in
|
|
`packages/harness/src/bundle.mjs`, the same pair in the broker and
|
|
`packages/business/src/vars.mjs`, an adapter map in
|
|
`packages/seat/src/session.mjs`, per-harness mounts in the sandbox,
|
|
and `claude --version` in the launcher. `packages/conversation`
|
|
and the Discord CLI start Pi directly.
|
|
- Model providers: the family match and `LAUNCH_CEILING` (REQ-LIMIT-1
|
|
removes both), a session environment that passes only `ANTHROPIC_*`
|
|
and the Claude OAuth token (`session.mjs`), and a free-text
|
|
`execution.provider` that nothing checks.
|
|
- Task tracker: the tasks verbs build Vikunja paths with no
|
|
interface between them and the client. The bus always loads
|
|
`packages/tasks/src/adapter.mjs`. Task refs (`vikunja:`), branch
|
|
names and the grantable services name Vikunja. `tracker.kind`
|
|
exists in `vars.mjs` and nothing reads it.
|
|
- Git forge: the Gitea host in `scripts/gitea-api.sh` and the git
|
|
credential helper, the repository path and seat-to-account mapping
|
|
in `packages/queue/src/review.mjs`, the ledger's repository paths,
|
|
and the `refactor` branch in `scripts/land-work.sh`.
|
|
`gitea.baseUrl` exists in `vars.mjs` and the scripts don't read it.
|
|
- Channels: `cli` and `webui` are channel plug-in modules, selected by
|
|
the organization's `plugins.channel` list. Both retain the core human
|
|
proof transport (`via: 'cli'`); Discord isn't connected to the bus.
|
|
- Version 1.4:
|
|
- Jason approved REQ-WEB-3 in decision 021af0c8 (prd.approve, choice
|
|
yes; the approval message was request 2e031716, from request
|
|
dfebf8ce). The requirement is the approved sentence, set as three
|
|
sentences with the same clauses.
|
|
- Jason approved REQ-INST-1 in decision 1ea053cc (prd.approve, choice
|
|
yes; the approval message was request 94a11a59, from request
|
|
b28979c9, Q162). The text is as approved. The build task under it is
|
|
the SearXNG install component, which backs the `searxng-bundled`
|
|
web source (`web.source`, vikunja:19/296). This amendment adds the
|
|
requirement only.
|
|
- Today a change to `launch.instances` reaches running sessions only
|
|
after the bus service is restarted by hand. The build tasks under
|
|
REQ-WEB-3 are the bus hot reload, the Console controls, and running
|
|
sessions picking up `launch.instances` changes. This amendment adds
|
|
the requirement only.
|
|
- REQ-WEB-2 is held for the Console decide buttons amendment
|
|
(vikunja:19/266), so its id is not reused here.
|
|
- Version 1.5:
|
|
- The 1.0 text of REQ-DEC-2 was: "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." On 2026-10-15 the Stack routed 16
|
|
decisions, and all 16 went to Jason. 9 of them were `policy.change`
|
|
or `prd.approve`, which no role file could grant.
|
|
- Before 1.5 the always-gated lists, `GATED` in
|
|
`packages/bus/src/broker.mjs` and `GATED_ONLY` in
|
|
`packages/business/src/vocabulary.mjs`, held nine actions:
|
|
`credential.mint`, `git.merge.protected`, `git.push.protected`,
|
|
`deploy`, `spend`, `message.external`, `policy.change`,
|
|
`prd.approve` and `role.revoke`. Row 139 (#1633) changes them to
|
|
REQ-WAIT-1's list and adds `data.delete`, `network.expose` and
|
|
`account.create`.
|
|
- The arbiters are the organization file's `arbiters.technical` and
|
|
`arbiters.delivery` (`packages/bus/src/broker.mjs`).
|
|
- Where each requirement is built, all under Vikunja P19 task 314:
|
|
REQ-DEC-5 is row 136 (#1630); REQ-PROJ-1 is row 147 (#1641);
|
|
REQ-PROJ-2 and REQ-DEC-6 are row 138 (#1632); REQ-COS-2 is row 140
|
|
(#1634). Those are landed. REQ-LAND-1 is row 137 (#1631);
|
|
REQ-DEC-2 and REQ-WAIT-1 to REQ-WAIT-3 are row 139 (#1633);
|
|
REQ-MSG-2 is row 141 (#1635); REQ-PROJ-4 and REQ-ASSIST-3 are row 143
|
|
(#1637); REQ-PROJ-3 is row 148 (#1642); REQ-ROLE-5 and REQ-ROLE-6
|
|
are row 149. This amendment adds the requirements only.
|
|
- The spec counts as confirmed when its last commit's author name is
|
|
the business's `human` (`packages/project/src/read.mjs`). The broker
|
|
refuses a raise that cites another commit with `stale-spec`, and an
|
|
unconfirmed spec with `spec-unconfirmed`. Until `mosaic project
|
|
init` runs for a project, spec reads and record writes for it are
|
|
refused.
|
|
- `git.push.protected` covering force pushes on any branch is new in
|
|
1.5. Today the host refuses a non-fast-forward push to the working
|
|
repository (`packages/seat/src/working.mjs`), so no role can force
|
|
push. REQ-WAIT-1 makes any future path to one a hard wait.
|
|
- REQ-PROJ-4 covers Console saves only (row 143). Noticing spec commits
|
|
made with git outside the Console is a later row.
|
|
- REQ-LAND-1's refusal of a gated merge decision is pinned in rows 137
|
|
and 139. Row 139 carries it, or row 137 if 139 lands first.
|
|
- Version 1.6:
|
|
- The 1.5 text of REQ-ROLE-2 ended at "and the revoke cites it." The
|
|
1.5 text of REQ-ROLE-4 ended at "Jason's may be named Mos." The 1.5
|
|
text of REQ-WAIT-1 ended at "REQ-ROLE-2 still requires a resolved
|
|
decision for a revoke."
|
|
- Removing the assistant, in this version, means ending or revoking
|
|
its runs. Deleting the instance from the organization file is not
|
|
covered.
|
|
The protected definitions are `END_PROTECTED` in
|
|
`packages/bus/src/broker.mjs`, which holds `assistant`.
|
|
- Configuring the assistant covers its organization entry's `vars`
|
|
and `tracker`, and its `definition` among those the broker treats as
|
|
the assistant. `holder` and `credentials` are not covered.
|
|
- Where each part is built: the refusal and the hard wait are row 139
|
|
(#1633). Configuring the assistant and its seat name, and making the
|
|
chief of staff's end or a human-approved revoke stop an assistant
|
|
run, are row 155 (#1649), using row 141's (#1635) instance names.
|
|
Until row 155 lands, the assistant's runs hold thread claims that
|
|
the end and revoke paths don't read, so neither can stop one. The
|
|
human stops one with `mosaic stop <run>`.
|
|
- Version 1.9:
|
|
- The 1.8 text of REQ-DEC-3 began: "A human resolution, by an
|
|
authorized human, comes only from a `mosaic` CLI session started
|
|
outside any agent run."
|
|
- The first text on vikunja:19/266 had the Console trust the
|
|
`X-authentik-uid` header. Q175 replaced that: the Console runs its
|
|
own OIDC sign-in and takes no identity from a proxy header. Q203 (O6)
|
|
keeps the requirement OIDC-only, so the Console holds no passwords.
|
|
- The requirement covers every open decision. The first build, row
|
|
252 (#1753), covers grant requests only (Q188). It resolves through
|
|
the human boundary row 196 (#1694) builds.
|
|
- The live Console runs without `--sso` and without `--send`, so it
|
|
resolves nothing until the Q175 phase 2 window turns both on and a
|
|
re-pin carries row 252. This amendment adds the requirement only.
|
|
- Version 1.10:
|
|
- REQ-WEB-2 (1.9) uses the Console's own OIDC sign-in from Q175. The
|
|
out-of-scope list above then still named 'Pocket ID and SSO'. Jason
|
|
ruled on that line in Q211, and version 1.11 updates it
|
|
(vikunja:19/459).
|
|
- The design row for REQ-INST-2 is row 255 (#1760). This amendment adds
|
|
the requirement only.
|
|
- Version 1.11:
|
|
- The 1.10 out-of-scope list, under Round 2, "all", was: 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.
|
|
- Q211 names Q176's Given list and Cases 1 and 2 as v1. They are
|
|
tracked on Vikunja #414, #415 and #416. This version doesn't add
|
|
requirement ids for the items in them that the PRD lacks.
|
|
- The Case 2 MVP for 10-27 is the Markdown library (#416). The WYSIWYG
|
|
editor (Q195, Q196) is an add-on that doesn't gate it.
|
|
- Today the stack has an upgrade tool with activate, rollback and a
|
|
practice run, and nothing that sets up a fresh host (Q187). The
|
|
installer row is Vikunja #432, and the throwaway VM proof is #433.
|
|
- REQ-INST-3 replaces the hand start of the Console for the two v1 VMs
|
|
only (Q189, mos-1097 item 1).
|
|
- Which OIDC provider the two v1 VMs use is open (vikunja:19/461).
|
|
REQ-INST-2 moves into v1 if Jason picks the bundled Pocket ID for
|
|
either instance.
|
|
- Version 1.12:
|
|
- The 1.11 Risks line was: "In slice 1, agents run as Jason's OS user
|
|
(round 3, 3A). They can write anything that user can write. Until
|
|
seats run in a container, which comes next, the broker is a rule they
|
|
follow, not a wall. What does hold in slice 1 is that agents never
|
|
hold service tokens." Managed sessions now run in a sandbox (#1586,
|
|
`packages/seat/src/sandbox.mjs`), so 1.12 states the risk as the
|
|
shared OS user outside that sandbox. Q181 and Q182 settle the host
|
|
user and the accepted workstation risk.
|
|
- The REQ-DEC-3 title in `packages/tasks/requirements.json` was
|
|
"Authorized-human resolutions come only from a mosaic CLI session
|
|
outside any agent run". It left out the Console session that 1.9
|
|
added. 1.12 changes the title only. The requirement text is
|
|
unchanged.
|
|
- Q176 items the PRD already covered, so 1.12 adds no id for them:
|
|
projects and threads (REQ-ORG-2, REQ-THREAD-1, REQ-THREAD-2);
|
|
federation and shared access across instances (REQ-FED-1); custom and
|
|
templated roles assigned to agents (REQ-ROLE-1, REQ-ROLE-3,
|
|
REQ-TPL-1); the credential store (REQ-CRED-1 to REQ-CRED-4,
|
|
REQ-GRANT-1 to REQ-GRANT-4); each agent's own git credentials
|
|
(REQ-LAND-2, REQ-CRED-1); the chief of staff's hire and fire with
|
|
the user's per-agent forbid, and restructuring (REQ-COS-3,
|
|
REQ-ROLE-3, REQ-USER-3); the main user and the assistant
|
|
(REQ-ASSIST-1).
|
|
- Q176 items with no approved design, so 1.12 adds no id for them:
|
|
several independent sessions per thread, a compaction count, and
|
|
clearing an agent's context to start a new session. They are MVP
|
|
plan T1 item 7 and are v1 (TARGET.md:57, :104, :105). Several
|
|
sessions per thread differs from REQ-ROLE-2 and REQ-THREAD-2, where
|
|
each thread is one assistant session. Under Mos's reading of Q211,
|
|
TARGET.md:57 wins. Row 194 refuses regenerate for a thread instance
|
|
and leaves clearing its context to that item. Huey designs it, and
|
|
Scrooge reviews (vikunja:19/463, mos-1232). Its ids and the
|
|
REQ-ROLE-2 and REQ-THREAD-2 changes come in 1.13.
|
|
- Writing in the WebUI: Q176 allows "WYSIWYG, Obsidian, or some other
|
|
method". The Case 2 design keeps Obsidian (design 7.1). The WYSIWYG
|
|
editor is the Q195 and Q196 add-on and doesn't gate 10-27.
|
|
- The Case 2 design's playground prefixes all sit inside a book folder
|
|
(design 1.1). Q176 also asks for universe-level playgrounds "where
|
|
new universes can be created". The design doesn't state one, so
|
|
REQ-LIB-2 doesn't name the level.
|
|
- The design's 10-27 slice (design 9.2) is a capacity estimate, not a
|
|
cut (Mos's reading of Q211, mos-1231). Rooms with @tags (C2-09b,
|
|
C2-10c; TARGET.md:99) and hybrid universes (C2-15; TARGET.md:82)
|
|
stay v1. If one misses 10-27, it is reported late, not cut. Bus
|
|
writes and the Console editor (C2-02, C2-03b, C2-11a, C2-11b, C2-19)
|
|
don't gate 10-27: TARGET.md:97 allows Obsidian, and Jason called the
|
|
editor an add-on that "may not make the EOW deadline" (Q195). C2-16
|
|
to C2-18 stay later, because no Q176 line asks for them.
|
|
- REQ-PROJ-1's "no remote" covers project record repositories. A
|
|
library project is a separate kind with no record repository, and its
|
|
mirror fetches from the remote (design 2.1, 7.2).
|
|
- REQ-LIB-6 has a stated residual: a supporting doc can hold any text,
|
|
a drafted scene included, and code can't tell a scene from a note.
|
|
Every agent write shows as a notice and a commit trailer, and the user
|
|
can revert it. Nothing an agent writes lands in a story path. The
|
|
agent's Gitea token can write any path of the repository, and the
|
|
bus's path check is the only path limit, which holds while the bus
|
|
code does (design, ruling after r11). (Version 1.15 replaced the
|
|
item-list residual. The old text is in the Version 1.15 note.)
|
|
- Where each id is built: REQ-USER-3 and REQ-USER-4 are rows 193a to
|
|
193d (#1691), with FED R1 to R6. REQ-LIFE-1 is row 194 (#1692) and
|
|
its follow-up row 239. REQ-KILL-1 is row 191 (#1689). The REQ-LIB ids
|
|
are the C2 rows in `docs/plans/2026-10-20_case2-rows.md` (#416). This
|
|
amendment adds the requirements only.
|
|
- Version 1.13:
|
|
- The 1.12 text of REQ-ROLE-2 began: "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 rest, from "The chief of staff
|
|
may end another role's run", is unchanged. Who may end or revoke the
|
|
assistant is unchanged.
|
|
- The 1.12 text of REQ-THREAD-2 was: "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."
|
|
- The titles of REQ-ROLE-2 and REQ-THREAD-2 in
|
|
`packages/tasks/requirements.json` change with their text.
|
|
- Mos's readings, which the design records in section 8 (mos-1235).
|
|
They are reported to Jason after this version lands and don't go to
|
|
him as questions:
|
|
- Q1: the count is for the session's whole life. A clear successor is
|
|
a new session under TARGET.md:105 and starts at zero.
|
|
- Q2: clear waits for a proven safe stop and shows that it is
|
|
pending. It adds no force-stop, and the kill switch stays separate.
|
|
- Q3: the organization's owner doesn't clear another user's session
|
|
without that user's write authority, because "A user's messages
|
|
stay private from the owner" (REQ-USER-4).
|
|
- Mos's ruling mos-1236: sessions are for the assistant (the
|
|
`THREAD_DEFINITION` instance) only. Letting other roles hold thread
|
|
sessions would change launch policy and is outside Vikunja 463.
|
|
- Build dependency (design N2, vikunja:19/466): Claude Code's format
|
|
for a completed compaction has to be pinned offline, and a reader for
|
|
the managed session stores added. Today's reader covers pi only.
|
|
REQ-SESS-1 can't pass its acceptance test until both exist, and the
|
|
count isn't shipped for either harness until then.
|
|
- Until Q198's admission step is built, REQ-SESS-3 uses the existing
|
|
launcher and limit checks, plus row 191's kill checks once they land
|
|
(design D8).
|
|
- Moving existing threads keeps their history: each becomes one
|
|
default session, bound to its existing native store, with nothing
|
|
rewritten. The old shared instance workspace is drained and kept as
|
|
history (design D9).
|
|
- The build row is Sage's to file under Vikunja 463. This amendment
|
|
adds the requirements only.
|
|
- Version 1.14:
|
|
- The 1.13 text of REQ-LIB-2 was: "Playgrounds are never confused with
|
|
canon. A file's scope comes from its path alone: a Markdown file
|
|
under a playground prefix is playground, any other Markdown file in a
|
|
book folder is canon, and everything else is unmapped and never
|
|
returned. Lookups return canon unless the caller asks for playground.
|
|
An agent can't cite a playground file as a fact, a finding or a
|
|
correction. The Console shows each cite's scope. (Design 1.2, 5.2
|
|
and 7.4. Q176 Case 2, the playground items.)"
|
|
- REQ-LIB-3 gains the two sentences on a draft universe and a file
|
|
with no book. The rest of its text is unchanged.
|
|
- This settles the Version 1.12 note's item that "REQ-LIB-2 doesn't
|
|
name the level". That note is history and stays as written.
|
|
- The ruling's refusal codes: `library-playground-other-universe`
|
|
replaces `library-playground-outside-book`, for a prefix inside or
|
|
holding another entry's book folder. `library-mapping-invalid` covers
|
|
a prefix that holds its own entry's book folder, a draft with `books`
|
|
or no `playground` prefix, a draft with keys other than `kind`,
|
|
`name` and `playground`, and a `kind` other than absent, `"hybrid"`
|
|
or `"draft"`. A prefix equal to a book folder, a prefix listed twice
|
|
and a hybrid whose `sources` name a draft stay refused.
|
|
- Lookup details from the ruling: a lookup in a draft passes
|
|
`scope: "playground"`, since the canon default returns nothing there.
|
|
A universe-level file returns `book: null`. `library_manuscript`
|
|
needs a book. `citation-cross-universe` treats a draft as its own
|
|
universe. R5 covers a canon file that refers into any playground, and
|
|
R6 one that refers into a draft. `library_universe` on a draft
|
|
returns its kind, name and prefixes.
|
|
- The titles in `packages/tasks/requirements.json` don't change. The
|
|
REQ-LIB-2 title still holds at every level.
|
|
- The build is row C2-01c in `packages/library` (`mapping.mjs`,
|
|
`scope.mjs`), before C2-05a and C2-06 read `classify`, or in their
|
|
candidates if they have started. C2-12's setup sheet gets one line
|
|
per level (design section 8). Sage files it under Vikunja 464. This
|
|
amendment adds the requirements only.
|
|
- Version 1.15:
|
|
- The 1.14 text of REQ-LIB-6 was: "The creative roles are ideas,
|
|
research, proofreader, fact-checker and continuity, plus a companion
|
|
role that the user's own named agents run as. No creative agent can
|
|
write to the user's repository. Its tools are the lookups and a
|
|
message to the human, and research and companion also fetch web pages
|
|
through the broker. Every message an agent sends the user is a short
|
|
list of items. Each item cites a line of the repository at a commit,
|
|
or a page the agent fetched, and the broker checks every cite before
|
|
it stores the message. The one exception is a message with no items
|
|
and one of three fixed notices: no cited answer, no answer, or the
|
|
turn failed. The Console shows each notice as a fixed line, with no
|
|
text from the model. The user sees only stored messages, on every
|
|
channel. (Design 4, 5.1, 5.2 and 5.3; Q180 for Bean and Chet. Q176
|
|
Case 2, the agent list and "User sets strict guardrails for agent
|
|
capabilities".)"
|
|
- The 1.12 note's REQ-LIB-6 residual was: "an `idea` item carries free
|
|
text, up to 5 items of 200 characters per reply, and code can't tell
|
|
story text from advice (design 5.1). Accepting it is Jason's or
|
|
Melanie's (design section 10, step 8). It goes to Jason through Mos
|
|
(vikunja:19/465)." Q223 removed the item list, and the residual went
|
|
with it. The note now states the new one.
|
|
- REQ-LIB-1 gains "and supporting folders" in its first sentence and a
|
|
version tag. REQ-LIB-2 gains the supporting scope, its placement rule
|
|
and the canon-cite rule, which replaces "An agent can't cite a
|
|
playground file as a fact, a finding or a correction." The rest of
|
|
both is unchanged.
|
|
- REQ-LIB-3, REQ-LIB-4, REQ-LIB-5 and REQ-LIB-7 are unchanged. REQ-LIB-4
|
|
already says bus writes and pushes come in later rows (C2-02,
|
|
C2-03b), which covers agent writes and the user's Console saves. Its
|
|
fetch still uses a read-only token, now the chief of staff's read
|
|
grant.
|
|
- The titles of REQ-LIB-1, REQ-LIB-2 and REQ-LIB-6 in
|
|
`packages/tasks/requirements.json` change with their text. The id
|
|
count stays 85.
|
|
- The new refusal codes, settings and row order are in the design's
|
|
ruling after r11 and in the Q226 briefs of
|
|
`docs/plans/2026-10-20_case2-rows.md`. Sage files the rows under
|
|
Vikunja 416. This amendment adds the requirements only.
|
|
|
|
## Risks and open questions
|
|
|
|
- On each v1 instance, the stack runs as that instance's own OS user,
|
|
without sudo (Q181). A managed role session runs in a sandbox
|
|
(REQ-HARN-2): it writes only its workspace and run directory, sees no
|
|
data root, config or other run, and holds no service token
|
|
(REQ-CRED-1). A process that runs as that OS user outside a managed
|
|
session has no sandbox and can write anything the user can. On
|
|
dragon-lin, dev agents run that way, as Jason's OS user, with his keys
|
|
and access to the other hosts. Jason accepts that risk (Q182).
|
|
(Version 1.12.)
|
|
- Vikunja doesn't enforce `If-Match`. The broker compares before it
|
|
writes, and a person editing in the same moment can still be
|
|
overwritten in an owned field (lead decision 51).
|
|
- The Vikunja owner password and Gitea token creation are gated. Jason
|
|
holds them.
|
|
- With no ceiling in code, the chief of staff can raise its own launch
|
|
capacity and spend (REQ-LIMIT-1, Q150). The controls are the change
|
|
log, with who made each change and the old and new values, and the
|
|
user's power to change it back.
|
|
- A quota or token limit counts only what the stack ran. It can't see the
|
|
provider's own remaining quota or use of the same account elsewhere.
|
|
- The `transcript` usage source reads files inside the run's HOME, which
|
|
the session can edit. Its count is the stack's best reading, not proof.
|
|
A source that reads the provider's own report would be harder to
|
|
forge.
|
|
- A plug-in module runs with the host's authority, and the organization
|
|
file only picks among modules already in the tree. The reviewed commit
|
|
that adds a module is the only check on what it does, which is why
|
|
modules from outside the repository wait for Jason (REQ-PLUG-1).
|
|
- Trusted mode lets an agent run its allowed commands at will. On another
|
|
host, an allowed command that writes a file as root or starts a shell
|
|
can plant a key, and the seat sandbox doesn't confine the network, so
|
|
root can outlive the grant and a revoke. The allowlist narrows this. A
|
|
seat sandbox with its own network namespace closes it. Until then the
|
|
host's own audit log is the check after the fact (row 210 design section
|
|
6).
|
|
|
|
## Milestones
|
|
|
|
Slice 1, in the order on the foundation direction page. The slice 1 brief
|
|
maps each step to requirement ids. CHAT-03's Gate E demonstration happens
|
|
during the slice 1 WebUI step, not separately (round 3, 7B).
|