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.
This commit is contained in:
1 parent
2ad4b30ebd
commit
bf65ea9802
2 files changed
+573
No files matched your search
@@ -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
|
||||
|
||||
@@ -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-<decision>` 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 `<dataRoot>/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.<id>` 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/<name>/index.mjs`, exporting `interfaceVersion = 1` and `starterPack()`, which returns the document | Reviewed commit |
|
||||
| Installed | PL1 hash-pinned plug-ins under `<dataRoot>/plugins`, kind `starter-pack` | Instance owner, at the host (R10) |
|
||||
| Saved by a user | `<configDir>/templates/<account>/<name>.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.<p>.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/<id>/packs/preview`, `POST /api/orgs/<id>/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-<decision>` 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/<id>/templates/preview`, `POST /api/orgs/<id>/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-<decision>` 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:<name> --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.<p>.board`, `projects.<p>.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.
|
||||
Reference in new issue
Block a user