feat(fleet): system-type profiles (H2) #660

Merged
jason.woltje merged 1 commits from feat/h2-system-profiles into main 2026-06-24 16:02:26 +00:00
Owner

H2 — System-type profiles (declarative roster + topology)

Implements North Star goal H2: a declarative mapping from a system type to a persona roster + org topology, plus a loader/validator and a mosaic fleet profile CLI. Profiles are DATA (yaml seeded like roles), so an operator declares a system type and gets the matching roster from the baseline library with no code change (NS-9 / AC-NS-6).

Profile yaml schema

id:           kebab system-type id (== filename stem)
title:        human name
description:  one paragraph
lead:         persona class that coordinates the roster (the orchestrating seat)
floor:        [persona class]      # persistent minimum that stays staffed
roster:                            # full default roster
  - class:        <persona class>  # MUST resolve to a real role's class
    reports_to:   <persona class>  # optional; omit for lead; encodes topology
    multiplicity: <int, default 1>
notes:        optional

The full schema lives commented in software-delivery.yaml.

5 baseline profiles

id lead roster size (seats, w/ multiplicity)
software-delivery planner 14
personal-assistant personal-assistant 5
research lead-researcher 8
business (company-in-a-box) ceo 10
marketing marketing-lead 8

Loader / validator

packages/mosaic/src/commands/fleet-profiles.tsloadProfiles / loadProfile / parseProfile / validateProfile. Resolves <mosaicHome>/fleet/profiles/*.yaml via the same MOSAIC_HOME helper as the rest of fleet code (tests use a dir-override param). listPersonaClasses() derives the set of valid classes from the role library by unioning three signals: inline `class: X` markers (handles the newline-wrapped support-agent marker), LIBRARY.md index rows, and role filenames — so marker-less engineering personas (planner, decomposition) resolve. Validation rejects unknown lead/floor/roster.class/reports_to, duplicate ids, and a reports_to not present in the roster.

CLI

mosaic fleet profile list [--json] and mosaic fleet profile show <id> [--json]. Invalid profiles / unknown ids exit non-zero with a readable message.

Library-drift validation test

fleet-profiles.spec.ts includes the key guard: every class referenced by every baseline profile resolves against the real committed role library — so roster/library drift fails CI. Also covers parse defaults, list/show shape, and unknown-class / unknown-reports_to rejection via a temp dir.

Deviation

The task spec asked for lead: orchestrator on software-delivery, but orchestrator has no role file or class: marker — roles/planner.md states "the planner role IS the existing orchestrator class". To keep every referenced class resolvable (the hard validation requirement), software-delivery uses planner as lead and [planner, enhancer] as floor. Documented inline in the yaml.

Gates

typecheck ✓ · lint ✓ · prettier ✓ · vitest 585 passed (incl. 16 new profile tests) ✓ · CLI smoke-tested from dist/cli.js.

🤖 Generated with Claude Code

## H2 — System-type profiles (declarative roster + topology) Implements North Star goal **H2**: a declarative mapping from a *system type* to a persona roster + org topology, plus a loader/validator and a `mosaic fleet profile` CLI. Profiles are **DATA** (yaml seeded like roles), so an operator declares a system type and gets the matching roster from the baseline library with **no code change** (NS-9 / AC-NS-6). ### Profile yaml schema ``` id: kebab system-type id (== filename stem) title: human name description: one paragraph lead: persona class that coordinates the roster (the orchestrating seat) floor: [persona class] # persistent minimum that stays staffed roster: # full default roster - class: <persona class> # MUST resolve to a real role's class reports_to: <persona class> # optional; omit for lead; encodes topology multiplicity: <int, default 1> notes: optional ``` The full schema lives commented in `software-delivery.yaml`. ### 5 baseline profiles | id | lead | roster size (seats, w/ multiplicity) | |---|---|---| | software-delivery | planner | 14 | | personal-assistant | personal-assistant | 5 | | research | lead-researcher | 8 | | business (company-in-a-box) | ceo | 10 | | marketing | marketing-lead | 8 | ### Loader / validator `packages/mosaic/src/commands/fleet-profiles.ts` — `loadProfiles` / `loadProfile` / `parseProfile` / `validateProfile`. Resolves `<mosaicHome>/fleet/profiles/*.yaml` via the same MOSAIC_HOME helper as the rest of fleet code (tests use a dir-override param). `listPersonaClasses()` derives the set of valid classes from the role library by **unioning** three signals: inline `` `class: X` `` markers (handles the newline-wrapped `support-agent` marker), `LIBRARY.md` index rows, and role filenames — so marker-less engineering personas (`planner`, `decomposition`) resolve. Validation rejects unknown `lead`/`floor`/`roster.class`/`reports_to`, duplicate ids, and a `reports_to` not present in the roster. ### CLI `mosaic fleet profile list [--json]` and `mosaic fleet profile show <id> [--json]`. Invalid profiles / unknown ids exit non-zero with a readable message. ### Library-drift validation test `fleet-profiles.spec.ts` includes the key guard: **every class referenced by every baseline profile resolves against the real committed role library** — so roster/library drift fails CI. Also covers parse defaults, list/show shape, and unknown-class / unknown-reports_to rejection via a temp dir. ### Deviation The task spec asked for `lead: orchestrator` on software-delivery, but `orchestrator` has no role file or `class:` marker — `roles/planner.md` states "the planner role IS the existing orchestrator class". To keep every referenced class resolvable (the hard validation requirement), software-delivery uses **`planner`** as lead and `[planner, enhancer]` as floor. Documented inline in the yaml. ### Gates typecheck ✓ · lint ✓ · prettier ✓ · vitest **585 passed** (incl. 16 new profile tests) ✓ · CLI smoke-tested from `dist/cli.js`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jason.woltje added 1 commit 2026-06-24 15:42:57 +00:00
feat(fleet): system-type profiles — declarative roster+topology mapping (H2)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
fb61b26818
Add declarative system-type profiles: framework/fleet/profiles/*.yaml map a
system type to a persona roster + org topology (reports_to, multiplicity).
Profiles are DATA, seeded like roles, so an operator declares a system type and
gets the matching roster from the baseline library with no code change
(NS-9 / AC-NS-6).

- 5 baseline profiles: software-delivery, personal-assistant, research,
  business (company-in-a-box), marketing.
- fleet-profiles.ts: loadProfiles/loadProfile/parseProfile/validateProfile +
  listPersonaClasses (extracts valid classes from the role library by unioning
  inline `class:` markers, LIBRARY.md rows, and role filenames so marker-less
  personas like planner/decomposition resolve).
- CLI: `mosaic fleet profile list|show [--json]`; invalid profiles exit non-zero.
- Spec covers parse/validate, the library-drift guard (every referenced class
  resolves against the real role library), and unknown-class/reports_to rejection.
- install.sh: profiles seed via the existing rsync (comment clarified; the
  preserved top-level `fleet/*.yaml` glob does not shadow fleet/profiles/*.yaml).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
jason.woltje merged commit a738ac1410 into main 2026-06-24 16:02:26 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#660