From bf65ea9802bc8875e2a9143c798b6c0c963e7661 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Thu, 12 Nov 2026 14:25:04 -0600 Subject: [PATCH] docs(plans): starter packs design; system-type toolsets design superseded Design only, per Jason's 2026-11-12 starter-packs ruling. Inventory of existing building blocks, pack format, apply and re-apply, customizing from inside, saved templates, system-type retirement, five shipped packs, build slices and three open questions. --- .../2026-11-10_system-type-toolsets-design.md | 2 + docs/plans/2026-11-12_starter-packs-design.md | 571 ++++++++++++++++++ 2 files changed, 573 insertions(+) create mode 100644 docs/plans/2026-11-12_starter-packs-design.md diff --git a/docs/plans/2026-11-10_system-type-toolsets-design.md b/docs/plans/2026-11-10_system-type-toolsets-design.md index bdcbab5ea..67b1fcd1d 100644 --- a/docs/plans/2026-11-10_system-type-toolsets-design.md +++ b/docs/plans/2026-11-10_system-type-toolsets-design.md @@ -1,5 +1,7 @@ # System-type toolsets at launch +Superseded 2026-11-12 by `docs/plans/2026-11-12_starter-packs-design.md` under Jason's starter-packs ruling; do not build this design. + Status: design only. Nothing here is built and no `roles/` or contract file is changed. Prepared 2026-11-10 against `refactor` `8630b8dfc` for phase P2 of #1873 (unified workspace). PRD requirement: REQ-SYS-2, "An agent working in a diff --git a/docs/plans/2026-11-12_starter-packs-design.md b/docs/plans/2026-11-12_starter-packs-design.md new file mode 100644 index 000000000..5bdc06bb0 --- /dev/null +++ b/docs/plans/2026-11-12_starter-packs-design.md @@ -0,0 +1,571 @@ +# Starter packs + +Status: design only. Nothing here is built. No `roles/`, `contracts/` or +schema file is changed. Prepared 2026-11-12 against `refactor` `2ad4b30eb`. +It replaces `docs/plans/2026-11-10_system-type-toolsets-design.md`, which is +superseded and must not be built. + +## The ruling + +Jason, 2026-11-12, about 20:05Z: + +> I agree. Starter packs instead of over-restrictive configurations. We +> provide a handful of pre-configured options for system types, then the user +> can customize to their needs. Agent roles will be the main limiter or +> permitter of actual capabilities in the system. The default starter packs +> can affect the various Kanban styles, workflow templates, agent roles, and +> other primitives in the system. The user and their agents will be able to +> customize the system operations by allowing the import and implementation of +> the various roles, workflows, and other available items as needed. The user +> will also have the option to create new workflows within their system. The +> agent roles will be customizable within the absolute constraints that are +> offered. We have discussed that no agent can grant permissions beyond those +> they already possess. The org or project configurations will establish the +> "sandbox" for agent operations. The user and chief/assistant can work +> together to customize the org/project as needed to accomplish a goal. The +> user can also save a custom org/project template for use repeatedly to meet +> their needs. + +Earlier he said a system type is there "to provide a basic configuration using +templates for agent setup and system function", and that the user customizes +the system while working inside it. He judged the toolset gating design +counterproductive. + +What this design takes from that: + +- A pack is a starting point that is copied in once. It is not a switch that + stays on and gates what agents can do. +- Roles are the limit. A pack grants nothing; every agent it proposes is hired + through the existing hire decision, bounded by the chief's own role. +- The organization or project is the sandbox. Nothing a pack, a saved + template or an agent does reaches outside it. +- Customizing from inside uses the paths that already exist: the T1 definition + verbs for people, hire and change decisions for the chief, and the chief's + `organization.change` grant for settings that carry no capability. No new + human gate is added. + +## 1. Inventory + +Status means: **exists** (built and usable by a pack as is), **partial** +(built, but a pack cannot set it or it lacks a piece a pack needs), **missing** +(not found in the code). + +| Item | Where | Status | Notes | +|---|---|---|---| +| System-type plug-in kind | `packages/plugins/src/kinds.mjs:84-86` (`switch: "list"`, export `systemType`) | exists | A pure label today. | +| The five system-type modules | `packages/plugins/system-type/{coding,creative-writing,marketing,montage,business-management}/index.mjs`, `systemType()` | partial | Each returns `{id, label, description, toolsets: []}`. Nothing else. | +| Loading system types | `packages/plugins/src/system-types.mjs:5` `installedSystemTypes` | exists | Any refused module, or keys other than `description,id,label,toolsets`, throws `system-type-invalid`. | +| Org enable | `plugins['system-type']` in the org file; checked at `packages/organization/src/organization-config.mjs:360-365`; fenced by `systemTypesFence`, `packages/organization/src/organization.mjs:126-131` (`organization-system-types-human-only`) | exists | Read back by `system-types.current`, `packages/bus/src/runtime.mjs:904`. Console `GET/POST /api/system-types` (`packages/webui/src/system-types-http.mjs:4-9`), right `org.setup` (`packages/organization/src/org-rights.mjs:90`). | +| Project selection | `project.system-types[.set]`, `packages/bus/src/broker.mjs:8476-8495`; table `project_system_types` in `packages/bus/src/migrations/3t-3u.sql` (append-only) | exists | Human only. CLI `mosaic project system-types` and `system-types-set`, `packages/cli/src/project.mjs:17-18`. | +| System type effect on agents | launcher, harness, `packages/organization/src/resolve.mjs` | missing | No launch path reads system types (no hits in those files). Every module's `toolsets` is empty. | +| Shipped role templates | `roles/*.json` + `.md` | exists | V2 roles: assistant, chief-executive-officer, chief-financial-officer, chief-information-officer, chief-information-security-officer, chief-marketing-officer, chief-of-staff, coder, companion, continuity, cto, fact-checker, ideas, merge-gate, pm, proofreader, research, reviewer, security-reviewer. `researcher.json` is V1 and refused by `readTemplate`. | +| Template identity | `packages/organization/src/definitions.mjs:174,180` `templateHash`, `templateHashes` | exists | Name plus sha256. | +| Org definitions: import, invent, edit, remove | `packages/organization/src/definition-verbs.mjs:61` `definitionVerbs`; CLI `mosaic org definitions ...` (`packages/cli/src/org-definitions.mjs:15`) | exists | `authorize` (line 38) refuses any agent (`human-required`) and needs `org.hire`. Writes go through `writer.setDefinition`; a definition in use refuses `definition-in-use`. | +| Template diff | `packages/organization/src/definitions.mjs:252` `diffDefinition` | exists | Compares a copy with its template's current text. | +| Composition check | `packages/organization/src/composition.mjs:443` `checkComposition` | exists | Refuses hard waits (R4). Flags every line above the chief's own role (tools, network, actions, credentials, messaging) and every resolve right. | +| Plug-in role templates | `roleTemplates` in `packages/plugins/src/manifest.mjs:48` `checkManifest`; read by `packages/organization/src/composition.mjs` | partial | A PL1 manifest may declare templates with plugin-prefixed names. I did not find the hire path reading them. | +| Hire as a decision | `packages/organization/src/hire-decisions.mjs:65` `hireDecisions` (`prepare`); `authorizeHire` line 32; broker `#raiseHire`, `packages/bus/src/broker.mjs:6578` | exists | `instance.hire` fails `decision-required` (6236). Only the chief raises (`role-not-chief`, 6583). A human with `org.hire` starts and approves in one step through `hire.start.console`. Flagged and credential lines need the owner; root needs the instance owner. An approved hire writes definition `hire-` and the instance (hire-decisions.mjs lines 307-309). | +| Autonomy setting | `packages/organization/src/autonomy.mjs:2-4` | exists | Classes cross-role, merge, policy, authority. Authority defaults to in the loop. Owner-only (`autonomy.*` null in `VERB_RIGHTS`). | +| The chief's own settings grant | `organization.change` in `roles/chief-of-staff.json`; broker `organization.set`, `packages/bus/src/broker.mjs:6247-6340` | exists | The chief changes limits directly under its within-role grant. The trail records each change. | +| Task board columns | `STORE_STATES`, `packages/bus/src/broker.mjs:334`; `packages/tasks/src/startup.mjs:6` `BUCKETS`; `packages/webui/src/public/tasks-board.js:21` `STATES` | partial | Five fixed states (todo, in-progress, in-review, blocked, done) with fixed labels. Nothing configures them. | +| Kanban styles | `packages/webui/src/public/tasks-board.js:146` `kanban`, `:156` `list` | missing | Two layouts (REQ-WS-8). No per-org or per-project style, label or order. | +| Workflow templates | grep for "workflow" in `packages`, `scripts`, `roles`, `contracts`, `missions` | missing | Only refusal text in `packages/bus/src/refusals.mjs`. No workflow document, store or engine. | +| Mission and task templates | `missions/hello.json`; `tasks/*.json`; schemas in `scripts/mosaic-task.mjs:94,139` | partial | These drive headless worker runs (`run-task.sh`), not org operations. `missions/` holds one file. A pack does not carry them. | +| Skills | repo `skills/` (16 skills); `scripts/skill.sh` install/activate into `/skills-enabled`; role `skills` key resolved in `packages/harness/src/bundle.mjs:126-192` | exists | Machine-scoped. A role names skills; launch refuses a missing one. A pack can name skills but cannot install them. | +| Plug-ins (code) | `packages/plugins/src/loader.mjs:123` `loadInstalled`; `packages/plugins/src/install.mjs:71` `installPlugin` (hash pin, read-only files) | exists | A module runs with the host's authority (loader header). Install is an instance-owner act (R10). | +| Workspace and dashboard sections | `packages/webui/src/workspace-read.mjs:13` `WORKSPACE_SECTIONS` | partial | Fixed: projects, sessions, inbox, tasks, metrics. No per-org configuration found. | +| `mosaic org template render` | `packages/organization/src/org-service.mjs:92` `templateRender`; `packages/organization/src/org-template.json` | exists | Renders human, chief, assistant and one `work` project. Presets from harness and model-provider modules (`discoverPresets`, line 61) overlay `plugins`, `launch` and assistant vars. Console `GET /api/org-template`, `/api/org-presets` (`packages/webui/src/org-admin.mjs:413-419`). | +| Project settings | org file `projects.` keys root, repo, remote, git, agents (`packages/organization/src/organization-config.mjs:306`); repo file `.mosaic/project.json` (`packages/organization/src/project.mjs`, read only) | partial | No board or workflow setting per project. | +| Agent levels | `packages/organization/src/agent-levels.mjs` (`AGENT_LEVELS` line 15, `checkProjectAgents` line 111, `resolveAgentLevels` line 207) | exists | Root and project definitions refuse bound keys: credentials, holder, tracker, identity, publish, hosts (line 21). | +| Copy credential bindings | `copyBindings` fence, `packages/organization/src/organization.mjs:32-36`; writer at line 550 | exists | Owner-approved binding decision only. | +| Pack format, apply, saved templates | none | missing | This design. | + +Missing building blocks, plainly: workflow templates, Kanban styles (labels, +order, hidden columns), any per-org or per-project board setting, a pack +format, a pack apply path, and saved org or project templates. Montage has no +video roles or tools in the repository; the OpenMontage integration was not +found. + +## 2. What a pack is + +A pack is a declarative JSON document. It lists items to copy into an +organization or a project. It never runs, never stays switched on, and grants +nothing. + +### Where packs live + +| Source | Location | Who adds one | +|---|---|---| +| Shipped | Core plug-in modules `packages/plugins/starter-pack//index.mjs`, exporting `interfaceVersion = 1` and `starterPack()`, which returns the document | Reviewed commit | +| Installed | PL1 hash-pinned plug-ins under `/plugins`, kind `starter-pack` | Instance owner, at the host (R10) | +| Saved by a user | `/templates//.json`, mode 0600, written with `wx` (never overwritten) | The organization's owner, through `template.save` (section 5) | + +Shipped and installed packs follow the loader exactly: the same component and +symlink checks, the same refusal codes, a refused installed pack omitted and +logged, a refused core pack failing the listing as system types do today. A +saved template is data only. It is read with `parseJsonFileText`, never +imported or run, capped at 256 KiB, and passes the same `checkPack` as a +shipped pack. + +### The document (packVersion 1) + +```json +{ + "packVersion": 1, + "id": "coding", + "version": "1.0.0", + "label": "Coding", + "description": "A small software team with review before merge.", + "scope": "org", + "definitions": { + "coder": { "template": "coder", "sha256": "<64 hex>" }, + "release-writer": { + "from": { "template": "coder", "sha256": "<64 hex>" }, + "role": { "tools": ["read", "edit"], "authority": { "withinRole": ["record.write"] } }, + "instructions": "...", + "personality": { "summary": "..." } + } + }, + "hires": [ + { "name": "coder-1", "definition": "coder", "level": "org", "reason": "writes the code" } + ], + "board": { + "columns": [ + { "state": "todo", "label": "Backlog" }, + { "state": "in-progress", "label": "Building" }, + { "state": "in-review", "label": "Review" }, + { "state": "blocked", "label": "Blocked" }, + { "state": "done", "label": "Merged" } + ], + "layout": "kanban" + }, + "workflows": { + "change": { + "description": "One change from task to merge.", + "steps": [ + { "id": "plan", "title": "Write the task", "role": "pm", "state": "todo" }, + { "id": "build", "title": "Implement", "role": "coder", "state": "in-progress" }, + { "id": "review", "title": "Review", "role": "reviewer", "state": "in-review" }, + { "id": "merge", "title": "Merge", "role": "merge-gate", "state": "done" } + ] + } + }, + "skills": ["ms-sdlc", "ms-unslop"] +} +``` + +`checkPack` (new, in `packages/plugins/src/starter-pack.mjs`) refuses with +`starter-pack-invalid` unless all of these hold: + +- Exact top-level keys as above. `scope` is `org` or `project`. +- `id` matches `NAME` (`packages/plugins/src/kinds.mjs:20`). `version` is a + semver string. +- Each `definitions` entry is one of two shapes: + - A template reference `{template, sha256}`. The name must be a V2 role in + `roles/` and the hash must equal `templateHash` now. A stale pin refuses + `starter-pack-template-changed`, so a pack never imports text nobody + reviewed against it. + - A full entry in the T1 shape (`ENTRY_KEYS`, `definitions.mjs:30`). It + must name `from` and pass `checkDefinition`. Its role must narrow the + template named in `from`, line by line, under the new + `narrowsTemplate(role, template)`: every tool, action, skill, messaging + target and credential line is in the template, and the network is no + wider. This is "no grant above the templates". A shipped or installed pack + may not carry a role without `from`. +- `hires`: at most 8. Each `name` passes `requireId`. Each `definition` names + an entry in this pack's `definitions` or an existing V2 template. `level` + is `org` or `project`, never `root`. +- `board.columns` holds the five `STORE_STATES`, each exactly once, in any + order, each with a label of 1 to 32 characters. `layout` is `kanban` or + `list`. The tracker contract does not change (REQ-TASK-1, REQ-WS-8). +- Each `workflows` entry has 1 to 20 steps. Each step's `state` is in + `STORE_STATES` and its `role` names a definition in the pack or a template. +- `skills` entries match `NAME`. They are a list of what the roles need, not + an install. +- Every string passes the credential store's `assertClean`, as definitions do + today (`checkDefinition`, `definitions.mjs:81`). + +### What a pack never contains + +The schema has no key for any of these, so a pack carrying one refuses: + +- credentials, credential bindings, tokens, tracker bots, identity, publish, + holder or hosts; +- members, rights or the owner; +- the autonomy setting or arbiters; +- plug-in selections (`plugins`), including the task tracker and theme; +- `launch` (models, limits, keep, noHire, account); +- a root-level hire; +- any role line outside the `roles/` rails. `checkComposition` still runs on + every definition at apply time and refuses a hard wait (R4) and `role.hire` + or `role.fire` in a hired composition (R9). + +### Versioning + +`packVersion` is the schema version; an unknown one refuses. `version` is the +pack's own release. An apply records `{id, version, sha256}` where `sha256` +is the hash of the canonical JSON that was applied. A new pack version is a +new document; it never edits an organization that applied an older one. + +## 3. Applying a pack + +### What apply does + +Apply copies items in once. After that the organization or project owns them, +exactly as if a person had made them by hand. The steps: + +1. **Preview.** `pack.preview` reads the pack and the organization and returns + a plan: each item marked `add`, `same` or `kept` (section 3, re-apply), the + flagged lines each proposed hire would carry against the current chief, the + skills not enabled on this machine, and a digest of the plan plus the + organization file revision. Nothing is written. +2. **Apply.** `pack.apply` takes the digest. It refuses `pack-plan-stale` if + the revision or plan changed. In one organization-file write it: + - writes each `add` definition through `writer.setDefinition`, with `from` + kept, so `checkComposition` runs and `rev` starts at 1; + - writes the `board` and `workflows` items marked `add`; + - appends `{id, version, sha256, scope, project, at, by, proposedHires}` to + a new `packs` key. +3. **Hires.** Apply never hires. It leaves the pack's hires as proposals in + the `packs` entry. Each becomes a hire through the existing paths: + - the chief raises `hire.raise` (`broker.mjs:6237`) with role + `{definition, rev}`; the broker computes the flagged and credential + lines, and the decision routes by the authority autonomy level; + - or a person with `org.hire` starts it with `hire.start.console`, which + shows the same lines and needs the owner for any flagged one. + + A proposal is filled when an instance by that name exists. A pack applied + to a project proposes project-level hires (`level: "project"`), which land + in `projects.

.agents` and refuse bound keys + (`agent-levels.mjs:21`). + +### The surface + +| Layer | Name | +|---|---| +| CLI (owner verb) | `mosaic org pack list`, `mosaic org pack preview ID PACK [--project P]`, `mosaic org pack apply ID PACK --digest D [--project P]` | +| Console route | `GET /api/packs`, `POST /api/orgs//packs/preview`, `POST /api/orgs//packs/apply` | +| Bus ops | `packs` (read), `pack.preview.console`, `pack.apply.console`; and for the chief, `pack.preview` and `pack.apply` under `organization.change` | +| `VERB_RIGHTS` | `packs` to `board.read`; `pack.preview.console` and `pack.apply.console` to `org.hire` | + +`org.hire` fits because the only parts of a pack that could ever matter for +capability are role definitions, and T1 already gives definition writes to +`org.hire`. Board and workflows carry no capability. + +### The chief applying a pack + +The roles-and-rails design says the chief proposes a definition only inside a +decision (section 5). The chief's `pack.apply` respects that: + +- it writes `board` and `workflows` directly under the chief's + `organization.change` grant, the same way `organization.set` writes limits + today (`broker.mjs:6247-6340`); +- it writes no definitions. Each proposed hire the chief raises carries the + pack's composition as role `{inline}` or `{template, sha256}`, so the broker + computes the lines against the chief and the approved hire writes + `hire-` as it does now. + +### A second pack, and re-applying + +Items merge by name and nothing is overwritten: + +| Item in the pack | Organization already has | Result | +|---|---|---| +| Definition | nothing by that name | `add` | +| Definition | same composition, instructions and personality | `same`, no write | +| Definition | different (edited, or a newer pack version) | `kept`. The preview shows `diffDefinition`. The person may import the pack's version under another name with `--as`. | +| Board | no `board` key | `add` | +| Board | a different board | `kept` | +| Workflow | nothing by that name | `add` | +| Workflow | a different workflow by that name | `kept`, with `--as` | +| Proposed hire | an instance or open hire decision by that name | dropped from the new proposals | + +There is no forced overwrite flag. To take a newer pack version of a definition +a hired agent uses, the person or chief raises a change decision, which is the +existing path. + +### Removing a pack + +Removing a pack takes nothing away. Items were copied, so the organization +keeps them. The `packs` entry stays as history. Uninstalling an installed pack +plug-in uses `removePlugin` (`install.mjs:99`); a pack is never "enabled", so +`plugin-enabled` never refuses it, and no organization changes. + +## 4. Customizing from inside + +The ruling asks that the user and their agents can import roles, workflows and +other items, create new workflows, and customize roles inside fixed limits. +The table shows who does what. Every row reuses a path that exists or adds a +verb at the same level as its neighbours. None adds a person to a path that +had none. + +| Change | A person does it directly | The chief does it | The limit at that step | +|---|---|---|---| +| Import a role template | `definition.import` (T1, `org.hire`) | Inside a hire or change decision, role `{template, sha256}` | `checkComposition`. Nothing runs until a hire. | +| Customize or invent a role | `definition.edit` or `invent` (T1) | Inside a hire or change decision, role `{inline}` | `checkComposition`; lines above the chief are flagged and only the owner approves them (R8). Editing a definition in use refuses, so a running agent never widens without a change decision. | +| Hire, fire, change an agent | `hire.start.console` (`org.hire`) | `hire.raise` (only the chief, R9) | Broker-computed flagged and credential lines; authority autonomy level; root needs the instance owner. | +| Apply a pack | `pack.apply.console` (`org.hire`) | `pack.apply` under `organization.change`, no definitions | As above for every hire it later proposes. | +| Import a workflow or board from a pack | Part of apply | Part of the chief's apply | No capability. | +| Create or edit a workflow | `workflow.set.console` (`org.hire`) | `workflow.set` under `organization.change` | Steps name existing definitions or templates and the five states. A workflow grants nothing. | +| Change board labels or order | `board.set.console` (`org.hire`) | `board.set` under `organization.change` | The five states stay. | +| Project agents, board and workflow | The same verbs with `--project` | The same, under `organization.change` | Project agents refuse bound keys (`agent-levels.mjs:21`). | +| Enable a skill on the machine | `scripts/skill.sh activate` (instance owner) | Not available | Machine-scoped. | +| Install a pack plug-in | `installPlugin` (instance owner, R10) | Not available | Host authority. | +| Autonomy level | Owner only | Never (R12) | Unchanged. | + +**"No agent grants beyond its own permissions", step by step.** + +1. A pack: its definitions narrow the shipped templates (`narrowsTemplate`). +2. Apply: definitions pass `checkComposition`; apply writes no instance. +3. The chief's proposal: the broker, not the chief, computes the flagged lines + against the chief's own role (`checkComposition` step 7, + `composition.mjs:491`). The chief cannot omit them. +4. Resolve: an agent resolver can resolve only a plain hire with no flagged + or credential lines, not at root, not about itself (`authorizeHire`, + `hire-decisions.mjs:39-42`). Anything flagged goes to the owner. +5. A hired agent: `role.hire` and `role.fire` refuse in its composition (R9), + so it cannot hire in turn. +6. Saved templates go through steps 2 to 5 again in the new organization. + +**The sandbox.** Every agent a pack proposes is an org or project agent. It +runs in one organization, sandboxed as the instance uid with only its role's +tools (R6, R7). A project agent sees only that project's workspace. A pack +cannot name another organization, a host, a credential or a root-level hire. + +**The assistant.** The assistant does not hire, direct agents or assign tasks +(REQ-ASSIST-1). It helps the user pick and preview a pack and passes the +request to the chief. It gets no new verb. + +## 5. Saving a template + +### The verb + +| Layer | Name | +|---|---| +| CLI (owner verb) | `mosaic org template save ID NAME [--project P] --digest D`, with a preview `mosaic org template save ID NAME --preview` | +| Console route | `POST /api/orgs//templates/preview`, `POST /api/orgs//templates` | +| Bus op | `template.save.console`, `VERB_RIGHTS` null (owner only) | +| Lists | `mosaic org template list`, `GET /api/templates`: only the caller's own | + +Owner only, because a saved template copies the organization's role text, +which is the owner's work product, out of the organization. The preview shows +the exact JSON that will be written; save takes its digest. + +### What is captured + +- `definitions`: role, instructions, personality and `from`. Definitions named + `hire-` are renamed after the instance that uses them, so no + decision id leaves the organization. +- `hires`: one proposal per org instance (or project agent, with `--project`): + instance name, definition and level. Never the chief or the assistant, + which every organization already has. +- `board` and `workflows`. +- `skills`: the union of the captured roles' `skills`. +- `packs`: the ids and versions applied before, as provenance text. + +The result is a pack document with `source: "saved"`. A role in a saved +template may lack `from` (an invented role); that is the one difference from a +shipped pack, and it still passes `checkComposition` on apply. + +### What is stripped + +Everything not listed above. In particular: + +- the owner, members, accounts and rights; +- identities: `human`, instance `identity`, `publish`, `holder`, `hosts`, + tracker bot names and ids; +- credentials: role `credentials` lines, instance credentials, `copyBindings` + and their `copyId`, `orgIncarnation` and `generation`; +- `launch` (models, limits, keep, noHire, account, grant scope), `autonomy`, + `arbiters`, `plugins`, `appearance`, `usage`, `replyLimits`, `retired`; +- instance and organization `vars`; +- project roots, repos, remotes and git state; +- definition `rev` counters and `hireDecision` references; +- everything on the bus: run history, sessions, threads, tasks, decisions, + the trail. + +Stripping role `credentials` lines means a template never carries a request +for a credential. A role that needs one gets it after hire through the +owner-approved binding, as today. + +Before writing, save runs `assertClean` on every string, as definitions do. +A hit refuses `template-secret-suspected` and names the field path, never the +text. + +### Applying one to a new organization + +1. `mosaic org template render ID --output FILE`, then `mosaic org create ID + --from FILE`: the base organization with human, chief and assistant, as + today. +2. `mosaic org pack apply ID saved: --digest D`: the same preview and + apply as a shipped pack. A saved pack applies only to an organization the + caller owns. +3. The chief raises the proposed hires. + +There is no create-time shortcut that skips the hire decisions. + +## 6. System types + +**Decision: the kind is replaced.** The `system-type` kind becomes +`starter-pack`. A pack's `label` is what the UI shows as the system type. The +reasons: + +- Nothing reads system types today except the enable and select verbs, and + every module's `toolsets` is empty. A list switch that grants nothing has no + job once packs exist. +- Keeping both would leave a second, empty configuration surface next to the + real one. + +### Migration + +- **Org files.** A print-only conversion in the style of `migrateLaunch` + (`packages/organization/src/migrate-launch.mjs`, decision 145) prints the + file without `plugins['system-type']`. The owner applies it through the + organization writer, so the write gets the usual receipt and the trail + event keeps the old list as evidence. Nothing is applied for it, since the + old modules carried nothing. The Console offers the matching packs once. + After the kind is removed, the existing unknown-module check + (`organization-config.mjs:360-365`) refuses a file that still names + `system-type`, so an unmigrated file fails closed. The refusal text points + at the conversion. +- **`project_system_types`.** The table stays, rows and triggers unchanged + (write-once, R2). `project.system-types.set` refuses with a new code, + `verb-retired` (not found today). The read verb keeps working for history + until a later PRD removes it. No DDL change. +- **Code removed.** `systemTypesFence`, `system-types.console`, the system + types Console route and CLI words, and `installedSystemTypes`, each with its + tests. The five modules move to `packages/plugins/starter-pack/`. + +### REQ-SYS-1 and REQ-SYS-2 + +Current (PRD 1.20, `docs/prd/mosaic-stack.md:1247-1252`): + +- REQ-SYS-1: "System types are a plug-in kind. Its modules include coding, + creative writing, marketing, Mosaic Montage (the OpenMontage fork) and + business management. An organization enables a list of them." +- REQ-SYS-2: "A project may use any system type its organization enables, and + none is required. An agent working in a project gets the toolsets of the + system types that project uses." + +Proposed: + +- **REQ-SYS-1.** Starter packs are a plug-in kind. Mosaic Stack ships five: + coding, creative writing, marketing, Mosaic Montage and business + management. A pack is a starting configuration of role definitions, + proposed hires, a board style and workflow templates. An organization or + project copies a pack in once and then owns and changes what it copied. A + user can save an organization or project as their own template and apply it + the same way. +- **REQ-SYS-2.** Applying a pack grants nothing by itself. Every agent it + proposes is hired through the hire decision (REQ-AGENT-3), bounded by the + chief's own role, with any line above it approved by the owner. A pack never + sets credentials, rights, the autonomy setting or plug-in choices. Removing + a pack removes nothing it copied. + +## 7. The five shipped packs + +Every organization already has a chief and an assistant from +`org-template.json`, so no pack lists them. Columns map onto the five fixed +states in the order todo, in-progress, in-review, blocked, done. Every role +named is a shipped V2 template. + +### Coding + +| Item | Contents | +|---|---| +| Definitions | `coder`, `reviewer`, `security-reviewer`, `pm`, `merge-gate`, `cto` (template references) | +| Proposed hires | `pm-1` (pm), `coder-1` (coder), `reviewer-1` (reviewer) | +| Board | Backlog, Building, Review, Blocked, Merged; kanban | +| Workflows | `change`: pm writes the task, coder implements, reviewer reviews, merge-gate merges | +| Skills | ms-sdlc, ms-unslop, ms-file-read, ms-file-write, ms-goal, ms-communications | + +`cto` holds `decision.resolve.technical`, a resolve right, so it is flagged on +hire and the owner approves it. It is a definition, not a proposed hire. + +### Creative writing + +| Item | Contents | +|---|---| +| Definitions | `ideas`, `research`, `proofreader`, `fact-checker`, `continuity`, `companion` | +| Proposed hires | `ideas-1` (ideas), `proofreader-1` (proofreader), `continuity-1` (continuity) | +| Board | Ideas, Drafting, Editing, On hold, Finished; kanban | +| Workflows | `chapter`: ideas outlines, the user or companion drafts, continuity checks, proofreader edits | +| Skills | ms-unslop | + +### Marketing + +| Item | Contents | +|---|---| +| Definitions | `chief-marketing-officer`, `research`, `ideas`, `proofreader`, `fact-checker` | +| Proposed hires | `cmo` (chief-marketing-officer), `research-1` (research), `proofreader-1` (proofreader) | +| Board | Ideas, In progress, Approval, Blocked, Live; kanban | +| Workflows | `campaign`: research finds the angle, ideas drafts, fact-checker checks claims, proofreader edits, the user approves publishing | +| Skills | ms-unslop | + +Publishing outside the organization is `message.external` or a hard wait; no +role here holds it, so the user publishes. + +### Mosaic Montage + +| Item | Contents | +|---|---| +| Definitions | `ideas`, `research`, `proofreader`, `reviewer` | +| Proposed hires | `ideas-1` (ideas), `research-1` (research) | +| Board | Concept, Script, Review, Blocked, Final; kanban | +| Workflows | `episode`: research gathers sources, ideas writes the script, proofreader edits, reviewer checks | +| Skills | ms-unslop | + +This pack is a placeholder for scripting work. No video or montage role or +tool exists in the repository, and the OpenMontage integration was not found. +The module name is still open (PRD 1.20 open question 1). + +### Business management + +| Item | Contents | +|---|---| +| Definitions | `chief-executive-officer`, `chief-financial-officer`, `chief-information-officer`, `chief-information-security-officer`, `pm`, `research`, `continuity` | +| Proposed hires | `pm-1` (pm), `research-1` (research) | +| Board | To do, Doing, Waiting on review, Blocked, Done; list | +| Workflows | `decision-brief`: research gathers facts, pm writes the task, the relevant officer drafts, the user decides | +| Skills | ms-unslop, ms-goal, ms-communications | + +The officer roles hold only `message.send` and `record.write` today +(`roles/chief-*.json`). They are definitions to hire when wanted, not +proposals. + +## 8. Build slices + +Each slice lands with its own tests. "Sign-off" marks a slice that touches +`roles/`, `contracts/`, a schema or a security boundary; Jason approves it +before build. + +| Slice | Scope | Acceptance | Test that fails first | Sign-off | +|---|---|---|---|---| +| SP1 | `checkPack` and `narrowsTemplate` in `packages/plugins/src/starter-pack.mjs`; kind `starter-pack` in `kinds.mjs`; loader listing | A valid pack loads; each forbidden key, stale template hash, role wider than its template, root hire, ninth hire, bad state and secret-shaped string refuses with its code | `packages/plugins/tests/starter-pack.test.mjs`: a pack with `credentials` in a definition loads (red until `checkPack` exists) | Yes: new plug-in kind, a pack schema | +| SP2 | The five shipped pack modules | Each loads through SP1; every template pin equals `templateHash` now; no proposed hire carries a flagged line against `roles/chief-of-staff.json` | A test that loads `starter-pack/coding` and checks its pins against `templateHashes` | No (data only, built on SP1) | +| SP3 | Org file keys `packs`, `board`, `workflows`, `projects.

.board`, `projects.

.workflows` in `organization-config.mjs`; writer support | Unknown keys inside each refuse; board needs all five states once; workflow steps name known definitions or templates | `organization-config` test: a file with `board` refuses today as an unknown top key; flip to accept the valid shape and refuse the invalid ones | Yes: org file schema | +| SP4 | `pack.preview` and `pack.apply` (owner verbs, bus ops, `VERB_RIGHTS`) | Preview writes nothing; apply writes add items only and the `packs` entry; stale digest refuses; second apply of the same pack is all `same`; an edited definition is `kept`; apply raises no decision | Broker test: `pack.apply.console` by a caller without `org.hire` refuses `right-required` (red until the verb exists), then the re-apply case | Yes: new verbs in `VERB_RIGHTS` | +| SP5 | The chief's `pack.apply`, `board.set` and `workflow.set` under `organization.change`; proposed hires surfaced in `packs` | The chief's apply writes no definition; a hire the chief raises from a proposal carries broker-computed flagged lines; a hired non-chief agent's apply refuses `not-authorized` | Broker test: a coder session calling `pack.apply` refuses (red until the authority check is wired) | Yes: chief authority surface | +| SP6 | Console: pack picker, preview, apply; board labels on `tasks-board.js`; workflow view and editor | Board reads labels and order from the org or project; no label set means today's labels | `tasks-board` test: an org with a `board` shows its labels (red today, labels are fixed at line 21) | No | +| SP7 | `template.save` and saved-template apply | Save writes a file with none of the stripped keys; a seeded secret refuses; list shows only the caller's own; apply of a saved template goes through SP4 | Test: save an org whose instance has `credentials` and `copyBindings`; assert neither key appears anywhere in the output (red until the stripper exists) | Yes: data leaving an organization | +| SP8 | System-type retirement: print-only conversion, retired verbs, PRD REQ-SYS-1/2 text, removal of `systemTypesFence` and the Console and CLI system-type surface | An org file with `plugins['system-type']` refuses until converted; the applied write's trail event holds the old list; `project.system-types.set` refuses `verb-retired`; `project_system_types` rows unchanged | Migration test with a fixture org holding `["coding"]` | Yes: PRD and data migration | + +Order: SP1, SP2, SP3, SP4, SP5, SP6, SP7, SP8. SP8 can run after SP4 if the +Console needs the space earlier. + +## 9. Open questions for Jason + +1. **Retire system types as a separate kind?** This design replaces the + `system-type` kind with `starter-pack`, migrates org files and keeps + `project_system_types` as history. Recommendation: yes. The modules carry + nothing today, and two surfaces for one idea would confuse users. +2. **May the chief change board styles and workflows directly, as it changes + limits today?** This design puts `board.set`, `workflow.set` and the + non-definition half of `pack.apply` under the chief's existing + `organization.change` grant, with no decision. Recommendation: yes. They + carry no capability, the trail records each change, and a decision here + would be a new gate. Role and hire changes stay decisions. +3. **Board styles as labels and order over the five fixed states, or custom + states?** Custom states would change the task tracker contract, every + tracker module and the Vikunja bucket setup. Recommendation: labels, order + and layout only for now; revisit custom states when a pack needs one.