7984c8a3c86f2b8a1ac7b93aaece22ef7cfef1d8
10
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7984c8a3c8 |
feat(lease-broker): add the missing promotion client
The enforcement half of the lease broker ships and denies; the promotion half has no production caller anywhere in the package. Verified across 0.0.48, 0.0.49 and 0.0.50-next.2207: begin_verification / observe_receipt / promote_lease are invoked only by broker-test-client.ts, the acceptance spec, unit tests, and two probes under docs/. Consequence: no lease on any host can reach VERIFIED, so mutator-gate denies every mutator with MUTATOR_UNVERIFIED via a gate that nothing shipped can satisfy. Runtimes that enforce the gate in-process (pi, via mosaic-extension's tool_call hook) are bricked for mutators; runtimes whose gate is wired through a settings hook escape only when that hook is absent — i.e. by being ungated. This adds the client. It implements protocol steps 1, 4 and 5: 1. begin_verification -> mint a challenge, return the exact receipt text 2. the MODEL emits that text verbatim as its entire latest message 3. the runtime adapter ships that message to the observer socket 4. observe_receipt -> PENDING_PROMOTION 5. promote_lease -> VERIFIED Step 2 is deliberately NOT implemented here, and that is the point. is_verbatim_receipt uses hmac.compare_digest against the exact minted string — explicitly "not a transcript substring" — which makes promotion a LIVENESS PROOF: it requires a live model that received the challenge in its context and echoed it exactly. receipt-observer-client.py will post ANY string as the latest assistant message. A promotion client that posted its own receipt would satisfy the broker while proving nothing — a gate-disabler indistinguishable from a working fix unless someone specifically looks. Emitting the receipt therefore belongs to the runtime adapter, where a real model turn happens. A local diagnostic that posts its own receipt exists in the operator's repo and is deliberately NOT shipped here. The construction binds the exact normative source bytes, so a VERIFIED lease means "this agent is running THIS law", not merely "this session id is known". h_source/h_payload are derived by importing the framework's own normative_fragments.build_payload rather than reimplementing it: the broker derives them the same way and any divergence yields PAYLOAD_BINDING_MISMATCH. There must be exactly one implementation. session_identity() prefers the generation FILE over the env var, matching lease_generation.py. Sending a generation higher than the broker's would revoke the session's own authority (daemon.py:342-344), so it never guesses. Verified end-to-end on sb-it-1-dt under a real lease-gated anchor: a mutator denied rc=2 MUTATOR_UNVERIFIED, then begin -> observe -> promote -> VERIFIED, then the same mutator allowed rc=0. Negative controls pass: a fresh session is still denied, and an unrelated session still reads UNVERIFIED — promotion is per-session and does not leak. Still open: adapter wiring for step 2. Lazy promotion on first mutator attempt avoids colliding with the Constitution's first-response mode declaration, since compare_digest requires the receipt to be the WHOLE message. |
||
|
|
5c61d1f1a5 |
feat(launch): isolate harness homes and record immutable launch provenance
Mosaic wrote into the operator's harness base installs — ~/.claude, ~/.pi/agent, ~/.codex, ~/.config/opencode — for settings, instructions, and a 102-symlink skill farm per harness. Any experiment with hooks or gating therefore mutated the operator's own tooling, and a broken framework change could take out the very harness needed to repair it. Harness home isolation ---------------------- Each runtime now reads config from a dedicated mosaic-owned home via the harness's own config-dir variable: claude CLAUDE_CONFIG_DIR ~/.config/mosaic/.claude pi PI_CODING_AGENT_DIR ~/.config/mosaic/.pi (replaces ~/.pi/agent) codex CODEX_HOME ~/.config/mosaic/.codex opencode XDG_CONFIG_HOME ~/.config/mosaic/.opencode These paths are manifest-UNKNOWN, so rule 3 (#791) resolves them to operator ownership and a keep-mode upgrade can neither overwrite nor prune them. A bare `claude` / `pi` keeps its own config AND auth, making it a structural break-glass rather than one depending on restoring a file under pressure. opencode is blunter than the rest: it has no dedicated variable and follows XDG, so isolation also relocates XDG lookups for anything it spawns. Documented in place. mosaic-sync-skills now links into those homes and cleans the legacy farms it previously planted in base installs. Ownership is proven by RESOLUTION, not by name — only symlinks resolving inside the canonical/local skills dirs are removed, mirroring the refusal already in commands/skill.js. Verified against a real install: codex's own .system directory survived while its 102 mosaic links were removed. Both resolution prefixes are length-checked first; an empty prefix would make "$resolved" == "$prefix/"* match every absolute path and delete foreign symlinks. Immutable launch record ----------------------- Every launch now appends one record to fleet/run/sessions/events.ndjson before exec. Mandatory, mechanical, no model involvement. pi rewrites its own argv to a bare `pi`, so /proc/<pid>/cmdline destroys the launch evidence — that has already produced a confident wrong diagnosis ("this agent bypassed the launcher"), disproved only by the parent's argv and only because the parent had not yet exited. A record written before exec is the only place this survives. The path is the #797 Runtime Session Ledger, already operator-classified and already covered by test-upgrade-manifest-guard.sh, which seeds it and proves a populated ledger survives keep-mode upgrades — but nothing shipped ever wrote it. This implements it in the shape that guard already asserts (0600 files under a 0700 dir). `mosaic` writes session.launch; launch-runtime.py appends lease.register with the broker session id and activation capability. They correlate by an explicit MOSAIC_LAUNCH_ID, never by pid: execRuntime uses spawnSync, so the runtime is a child with a different pid. Records normative fragment digests (CONSTITUTION/AGENTS/SOUL/USER/STANDARDS/ TOOLS/RUNTIME) — the same set the broker hashes for promotion, so drift is mechanically detectable rather than a matter of judgement. Credential-safe: env is captured as PRESENT NAMES ONLY, and argv values over 256 bytes become a sha256 + length rather than being inlined. Also fixes CLI_VERSION resolution: '@mosaicstack/mosaic/package.json' is not in the package exports map and always throws ERR_PACKAGE_PATH_NOT_EXPORTED. resolveTool() uses that same failing specifier, which is why its documented preference for bundled tools over the deployed ~/.config/mosaic copy has never once applied — noted in place, not fixed here. Verified on sb-it-1-dt: isolated homes written and base installs byte-identical for all four harnesses; 408 legacy symlinks removed with 1 foreign entry preserved; launch records paired across the spawn boundary. typecheck shows zero errors in launch.ts (the @mosaicstack/types failures are pre-existing and reproduce on a pristine origin/main worktree). |
||
|
|
7bc2dfb6c8 |
skills: add glpi-* family (solve, followup, sweep, list, create)
ci/woodpecker/pr/ci Pipeline was successful
GLPI helpdesk workflow skills written against the portable tools/glpi/ tooling (session-init.sh, ticket-list.sh, ticket-create.sh), cross-linked via [[glpi-*]]: - glpi-solve — close a ticket by setting status Solved (5); GLPI auto-closes - glpi-followup — add a followup via the top-level /ITILFollowup endpoint - glpi-sweep — read-only hunt for done-but-open tickets needing Solve - glpi-list — query tickets by status/recency - glpi-create — open a new ticket Core rule encoded: completing work means setting status Solved, not just posting a resolution followup (a followup documents; only Solved auto-closes). Note: illustrative examples in the bodies are USC-flavored (M2M / helpdesk ticket numbers) and can be genericized in review if preferred. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_019GjBgrb9tHgvq414Fqj37c |
||
|
|
f05b198882 |
fix: remove stale bootstrap repo references from CLI error messages
Replace 'cd ~/src/mosaic-bootstrap && bash install.sh' with 'npm install -g @mosaic/mosaic' now that bootstrap is archived. |
||
|
|
6e6ee37da0 |
feat: complete framework migration — PowerShell, adapters, guides, profiles, tests
Completes the bootstrap repo migration with remaining files: - PowerShell scripts (.ps1) for Windows support (bin/ + tools/) - Runtime adapters (claude, codex, generic, pi) - Guides (17 .md files) and profiles (domains, tech-stacks, workflows) - Wizard test suite (6 test files from bootstrap tests/) - Memory placeholder, audit history Bootstrap repo (mosaic/bootstrap) is now fully superseded: - All 335 files accounted for - 5 build config files (package.json, tsconfig, etc.) not needed — monorepo has its own at packages/mosaic/ - skills-local/ superseded by monorepo skills/ with mosaic-* naming - src/ already lives at packages/mosaic/src/ |
||
|
|
b38cfac760 |
feat: integrate framework files into monorepo under packages/mosaic/framework/
Moves all Mosaic framework runtime files from the separate bootstrap repo into the monorepo as canonical source. The @mosaic/mosaic npm package now ships the complete framework — bin scripts, runtime configs, tools, and templates — enabling standalone installation via npm install. Structure: packages/mosaic/framework/ ├── bin/ 28 CLI scripts (mosaic, mosaic-doctor, mosaic-sync-skills, etc.) ├── runtime/ Runtime adapters (claude, codex, opencode, pi, mcp) ├── tools/ Shell tooling (git, prdy, orchestrator, quality, etc.) ├── templates/ Agent and repo templates ├── defaults/ Default identity files (AGENTS.md, STANDARDS.md, SOUL.md, etc.) ├── install.sh Legacy bash installer └── remote-install.sh One-liner remote installer Key files with Pi support and recent fixes: - bin/mosaic: launch_pi() with skills-local loop - bin/mosaic-doctor: --fix auto-wiring for all 4 harnesses - bin/mosaic-sync-skills: Pi as 4th link target, symlink-aware find - bin/mosaic-link-runtime-assets: Pi settings.json patching - bin/mosaic-migrate-local-skills: Pi skill roots, symlink find - runtime/pi/RUNTIME.md + mosaic-extension.ts Package ships 251 framework files in the npm tarball (278KB compressed). |
||
|
|
e599f5fe38 |
fix(web): add public/ directory — fixes Docker build COPY failure
Kaniko fails when COPY --from=builder references a path that doesn't exist. The web app had no public/ directory, causing build-web to fail with 'no such file or directory' on the public assets COPY step. |
||
|
|
92998e6e65 | fix(ci): use gitea_token secret for npm publish | ||
|
|
13934d4879 |
feat: npm publish pipeline + package versioning (0.0.1-alpha.1)
Publish pipeline:
- Add publish-npm step to .woodpecker/publish.yml — publishes all
@mosaic/* packages to Gitea npm registry on main push/tag
- Requires gitea_npm_token Woodpecker secret (package:write scope)
- publish-npm runs after build, parallel with Docker image builds
- pnpm publish resolves workspace:* to concrete versions automatically
Package configuration:
- All 20 packages versioned at 0.0.1-alpha.1
- publishConfig added to all packages (Gitea registry, public access)
- files field added to all packages (ship only dist/)
- @mosaic/forge includes pipeline/ assets in published package
Meta package (@mosaic/mosaic):
- Now depends on @mosaic/forge, @mosaic/macp, @mosaic/prdy,
@mosaic/quality-rails, @mosaic/types
- npm install @mosaic/mosaic pulls in the standalone framework
Build fixes:
- Fix forge and macp tsconfig rootDir: '.' -> 'src' so dist/index.js
resolves correctly (was dist/src/index.js)
- Exclude __tests__ and vitest.config from build includes
- Clean stale build artifacts from old rootDir config
Required Woodpecker secret:
woodpecker secret add mosaic/mosaic-stack \
--name gitea_npm_token --value '<token>' \
--event push,manual,tag
|
||
|
|
2ee7206c3a |
feat: mosaic-* skill naming, new board/forge/prdy skills, doctor --fix auto-wiring
Skills: - Rename all repo skills to mosaic-<name> convention (jarvis -> mosaic-jarvis, etc.) - Update frontmatter name: fields to match directory names - New mosaic-board skill: standalone Board of Directors multi-persona review - New mosaic-forge skill: standalone Forge specialist pipeline - New mosaic-prdy skill: PRD lifecycle (init/update/validate/status) Wizard (packages/mosaic): - Add mosaic-board, mosaic-forge, mosaic-prdy, mosaic-standards, mosaic-macp to RECOMMENDED_SKILLS - Add new skills to SKILL_CATEGORIES for categorized browsing Framework scripts (~/.config/mosaic/bin): - mosaic (launcher): load skills from both skills/ and skills-local/ for Pi - mosaic-doctor: add --fix flag for auto-wiring skills into all harnesses, Pi skill dir checks, Pi settings.json validation, mosaic-* presence checks - mosaic-sync-skills: add Pi as 4th link target, fix find to follow symlinks in skills-local/, harden is_mosaic_skill_name() with -L fallback - mosaic-link-runtime-assets: add Pi settings.json skills path patching, remove duplicate extension copy (launcher --extension is single source) - mosaic-migrate-local-skills: add Pi to skill_roots, fix find for symlinks YAML fixes: - Quote description values containing colons in mosaic-deploy and mosaic-woodpecker SKILL.md frontmatter (fixes Pi parse errors) |