docs: establish canonical documentation architecture (#1210)
ci/woodpecker/push/publish Pipeline failed

This commit was merged in pull request #1210.
This commit is contained in:
mos-dt-0
2026-08-13 17:56:13 +00:00
parent f82307c4dc
commit 7a6fb024b4
241 changed files with 4722 additions and 1579 deletions
@@ -0,0 +1,19 @@
# Monorepo consolidation planning bundle
> **Status:** Historical planning evidence. The five source records were moved byte-identically from migration quarantine on 2026-08-10.
This bundle records the decision and proposed work packages for consolidating prior Forge, MACP, and OpenClaw framework work into this monorepo.
## Records
- [Consolidation brief](brief.md) — original scope, target layout, constraints, and success criteria.
- [Board review](board-review.md) — historical deliberation and conditional approval.
- [WP1: Forge package](wp1-forge-package.md) — proposed TypeScript Forge implementation.
- [WP2: MACP package](wp2-macp-package.md) — proposed protocol, gate, credential, and event implementation.
- [WP3: Mosaic framework plugin](wp3-mosaic-framework-plugin.md) — proposed OpenClaw framework plugin port.
## Current boundary
`packages/forge`, `packages/macp`, and `plugins/mosaic-framework` exist in the current checkout. That existence is sufficient to classify this bundle as historical planning, but it does **not** prove that every stated success criterion, integration, coverage target, or behavior remains satisfied.
Use current package source, manifests, and tests for implementation truth. Do not use this bundle as an active task ledger or as authority to change package behavior.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,231 @@
# Brief: Monorepo Consolidation — mosaic/stack → mosaic/mosaic-stack
## Source
Architecture consolidation — merge the mosaic/stack repo (Forge pipeline, MACP protocol, framework tools) into mosaic/mosaic-stack (Harness Foundation platform). Two repos doing related work that need to converge.
## Context
**mosaic/stack** (OLD) contains:
- Forge progressive refinement pipeline (stages, agents, personas, rails, debate protocol, brief classification)
- MACP protocol (JSON schemas, deterministic Python controller, dispatcher, event system, gate runner)
- Credential resolver (Python — OC config, mosaic files, ambient env, JSON5 parser)
- OC framework plugin (injects Mosaic rails into all agent sessions)
- Profiles (runtime-neutral context packs for tech stacks and domains)
- Stage adapter (Forge→MACP bridge)
- Board tasks (multi-agent board evaluation)
- OpenBrain specialist memory (learning capture/recall)
- 17 guides, 5 universal skills
**mosaic/mosaic-stack** (NEW) contains:
- Harness Foundation platform (NestJS gateway, Next.js web, Drizzle ORM, Pi SDK runtime)
- 5 provider adapters, task classifier, routing rules, model capability matrix
- MACP OC plugin (ACP runtime backend with Pi bridge)
- TS coord package (mission runner, tasks file manager, status tracker — 1635 lines)
- BullMQ job queue, OTEL telemetry, channel plugins (Discord, Telegram)
- CLI with TUI, 65/65 tasks done, v0.2.0
**Decision:** NEW repo is the base. All unique work from OLD gets ported into NEW as packages.
## Scope
### Work Package 1: Forge Pipeline Package (`packages/forge`)
Port the entire Forge progressive refinement pipeline as a TypeScript package.
**From OLD:**
- `forge/pipeline/stages/*.md` — 11 stage definitions
- `forge/pipeline/agents/{board,generalists,specialists,cross-cutting}/*.md` — all persona definitions
- `forge/pipeline/rails/*.md` — debate protocol, dynamic composition, worker rails
- `forge/pipeline/gates/` — gate reviewer definitions
- `forge/pipeline/orchestrator/run-structure.md` — file-based observability spec
- `forge/templates/` — brief and PRD templates
- `forge/pipeline/orchestrator/board_tasks.py` → rewrite in TS
- `forge/pipeline/orchestrator/stage_adapter.py` → rewrite in TS
- `forge/pipeline/orchestrator/pipeline_runner.py` → rewrite in TS
- `forge/forge` CLI (Python) → rewrite in TS, integrate with `packages/cli`
**Package structure:**
```
packages/forge/
├── src/
│ ├── index.ts # Public API
│ ├── pipeline-runner.ts # Orchestrates full pipeline run
│ ├── stage-adapter.ts # Maps stages to MACP/coord tasks
│ ├── board-tasks.ts # Multi-agent board evaluation task generator
│ ├── brief-classifier.ts # strategic/technical/hotfix classification
│ ├── types.ts # Stage specs, run manifest, gate results
│ └── constants.ts # Stage sequence, timeouts, labels
├── pipeline/
│ ├── stages/ # .md stage definitions (copied)
│ ├── agents/ # .md persona definitions (copied)
│ │ ├── board/
│ │ ├── cross-cutting/
│ │ ├── generalists/
│ │ └── specialists/
│ │ ├── language/
│ │ └── domain/
│ ├── rails/ # .md rails (copied)
│ ├── gates/ # .md gate definitions (copied)
│ └── templates/ # brief + PRD templates (copied)
└── package.json
```
**Key design decisions:**
- Pipeline markdown assets are runtime data, not compiled — ship as-is in the package
- `pipeline-runner.ts` calls into `packages/coord` for task execution (not a separate controller)
- Stage adapter generates coord-compatible tasks, not MACP JSON directly
- Board tasks use `depends_on_policy: "all_terminal"` for synthesis
- Per-stage timeouts from `STAGE_TIMEOUTS` map
- Brief classifier supports CLI flag, YAML frontmatter, and keyword auto-detection
- Run output goes to project-scoped `.forge/runs/{run-id}/` (not inside the Forge package)
**Persona override system (new):**
- Base personas ship with the package (read-only)
- Project-level overrides in `.forge/personas/{role}.md` extend (not replace) base personas
- Board composition configurable via `.forge/config.yaml`:
```yaml
board:
additional_members:
- compliance-officer.md
skip_members: []
specialists:
always_include:
- proxmox-expert
```
- OpenBrain integration for cross-run specialist memory (when enabled)
### Work Package 2: MACP Protocol Package (`packages/macp`)
Port the MACP protocol layer, event system, and gate runner as a TypeScript package.
**From OLD:**
- `tools/macp/protocol/task.schema.json` — task JSON schema
- `tools/macp/protocol/` — event schemas
- `tools/macp/controller/gate_runner.py` → rewrite in TS as `gate-runner.ts`
- `tools/macp/events/` — event watcher, webhook adapter, Discord formatter → rewrite in TS
- `tools/macp/dispatcher/credential_resolver.py` → rewrite in TS as `credential-resolver.ts`
- `tools/macp/memory/learning_capture.py` + `learning_recall.py` → rewrite in TS
**Package structure:**
```
packages/macp/
├── src/
│ ├── index.ts # Public API
│ ├── types.ts # Task, event, result, gate types
│ ├── schemas/ # JSON schemas (copied)
│ ├── gate-runner.ts # Mechanical + AI review quality gates
│ ├── credential-resolver.ts # Provider credential resolution (mosaic files, OC config, ambient)
│ ├── event-emitter.ts # Append events to ndjson, structured event types
│ ├── event-watcher.ts # Poll events.ndjson with cursor persistence
│ ├── webhook-adapter.ts # POST events to configurable URL
│ ├── discord-formatter.ts # Human-readable event messages
│ └── learning.ts # OpenBrain capture + recall
└── package.json
```
**Integration with existing packages:**
- `packages/coord` uses `packages/macp` for event emission, gate running, and credential resolution
- `plugins/macp` uses `packages/macp` for protocol types and credential resolution
- `packages/forge` uses `packages/macp` gate types for stage gates
### Work Package 3: OC Framework Plugin (`plugins/mosaic-framework`)
Port the OC framework plugin that injects Mosaic rails into all agent sessions.
**From OLD:**
- `oc-plugins/mosaic-framework/index.ts` — `before_agent_start` + `subagent_spawning` hooks
- `oc-plugins/mosaic-framework/openclaw.plugin.json`
**Structure:**
```
plugins/mosaic-framework/
├── src/
│ └── index.ts # Plugin hooks
└── package.json
```
**This is separate from `plugins/macp`:**
- `mosaic-framework` = injects Mosaic rails/contracts into every OC session (passive enforcement)
- `macp` = provides an ACP runtime backend for MACP task execution (active runtime)
### Work Package 4: Profiles + Guides + Skills
Port reference content as a documentation/config package or top-level directories.
**From OLD:**
- `profiles/domains/*.json` — HIPAA, fintech, crypto context packs
- `profiles/tech-stacks/*.json` — NestJS, Next.js, FastAPI, React conventions
- `profiles/workflows/*.json` — API development, frontend component, testing workflows
- `guides/*.md` — 17 guides (auth, backend, QA, orchestrator, PRD, etc.)
- `skills-universal/` — jarvis, macp, mosaic-standards, prd, setup-cicd skills
**Destination:**
```
profiles/ # Top-level (same as OLD)
guides/ # Top-level (same as OLD)
skills/ # Top-level (renamed from skills-universal)
```
These are runtime-neutral assets consumed by any agent or profile loader — they don't belong in a compiled package.
## Out of Scope
- Rewriting the NestJS orchestrator app from OLD (`apps/orchestrator/`) — its functionality is subsumed by `packages/coord` + `apps/gateway`
- Porting the FastAPI coordinator from OLD (`apps/coordinator/`) — its functionality (webhook receiver, issue parser, quality orchestrator) is handled by `packages/coord` + `apps/gateway` in the new architecture
- Porting the Prisma schema or OLD's `apps/api` — Drizzle migration is complete
- Old Docker Compose configs (Traefik, Matrix, OpenBao) — NEW has its own infra setup
## Success Criteria
1. `packages/forge` exists with all 11 stage definitions, all persona markdowns, all rails, and TS implementations of pipeline-runner, stage-adapter, board-tasks, and brief-classifier
2. `packages/macp` exists with gate-runner, credential-resolver, event system, and learning capture/recall — all in TypeScript
3. `plugins/mosaic-framework` exists and registers OC hooks for rails injection
4. Profiles, guides, and skills are present at top-level
5. `packages/forge` integrates with `packages/coord` for task execution
6. `packages/macp` credential-resolver is used by `plugins/macp` Pi bridge
7. All existing tests pass (no regressions)
8. New packages have test coverage ≥85%
9. `pnpm lint && pnpm typecheck && pnpm build` passes
10. `.forge/runs/` project-scoped output directory works for at least one test run
## Technical Constraints
- All new code is ESM with NodeNext module resolution
- No Python in the new repo — everything rewrites to TypeScript
- Pipeline markdown assets (stages, personas, rails) are shipped as package data, not compiled
- Credential resolver must support: mosaic credential files, OC config (JSON5), ambient environment — same resolution order as the Python version
- Must preserve `depends_on_policy` semantics (all, any, all_terminal)
- Per-stage timeouts must be preserved
- JSON5 stripping must use the placeholder-extraction approach (not naive regex on string content)
## Estimated Complexity
High — crosses 4 work packages with protocol porting, TS rewrites, and integration wiring. Each work package is independently shippable.
**Suggested execution order:**
1. WP4 (profiles/guides/skills) — pure copy, no code, fast win
2. WP2 (packages/macp) — protocol foundation, needed by WP1 and WP3
3. WP1 (packages/forge) — the big one, depends on WP2
4. WP3 (plugins/mosaic-framework) — OC integration, can parallel with WP1
## Dependencies
- `packages/coord` must be stable (it is — WP1 integrates with it)
- `plugins/macp` must be stable (it is — WP2 provides types/credentials to it)
- Pi SDK (`@mariozechner/pi-agent-core`) already in the dependency tree
@@ -0,0 +1,265 @@
# WP1: packages/forge — Forge Pipeline Package
## Context
Port the Forge progressive refinement pipeline from Python (~/src/mosaic-stack/forge/) to TypeScript as `packages/forge` in this monorepo. The pipeline markdown assets (stages, agents, personas, rails, gates, templates) are already copied to `packages/forge/pipeline/`. This task is the TypeScript implementation layer.
**Board decisions that constrain this work:**
- Abstract TaskExecutor interface — packages/forge must NOT hard-import packages/coord. Define an abstract interface; coord satisfies it.
- Clean index.ts exports, no internal path leakage, no hardcoded paths
- 85% test coverage on TS implementation files (markdown assets excluded)
- Test strategy for non-deterministic AI orchestration: fixture-based integration tests
- OpenBrain is OUT OF SCOPE
- ESM only, zero Python
**Dependencies available:**
- `@mosaicstack/macp` (packages/macp) is built and provides: GateEntry, GateResult, Task types, credential resolution, gate running, event emission
## Source Files (Python → TypeScript)
### 1. types.ts
Define all Forge-specific types:
```typescript
// Stage specification
interface StageSpec {
number: string;
title: string;
dispatch: 'exec' | 'yolo' | 'pi';
type: 'research' | 'review' | 'coding' | 'deploy';
gate: string;
promptFile: string;
qualityGates: (string | GateEntry)[];
}
// Brief classification
type BriefClass = 'strategic' | 'technical' | 'hotfix';
type ClassSource = 'cli' | 'frontmatter' | 'auto';
// Run manifest (persisted to disk)
interface RunManifest {
runId: string;
brief: string;
codebase: string;
briefClass: BriefClass;
classSource: ClassSource;
forceBoard: boolean;
createdAt: string;
updatedAt: string;
currentStage: string;
status: 'in_progress' | 'completed' | 'failed' | 'interrupted' | 'rejected';
stages: Record<string, StageStatus>;
}
// Abstract task executor (decouples from packages/coord)
interface TaskExecutor {
submitTask(task: ForgeTask): Promise<void>;
waitForCompletion(taskId: string, timeoutMs: number): Promise<TaskResult>;
}
// Persona override config
interface ForgeConfig {
board?: {
additionalMembers?: string[];
skipMembers?: string[];
};
specialists?: {
alwaysInclude?: string[];
};
}
```
### 2. constants.ts
**Source:** Top of `~/src/mosaic-stack/forge/lib` (ALL_STAGES, LABELS, STAGE_SPECS equivalent) + `~/src/mosaic-stack/forge/pipeline/orchestrator/stage_adapter.py` (STAGE_TIMEOUTS)
```typescript
export const STAGE_SEQUENCE = [
'00-intake',
'00b-discovery',
'01-board',
'01b-brief-analyzer',
'02-planning-1',
'03-planning-2',
'04-planning-3',
'05-coding',
'06-review',
'07-remediate',
'08-test',
'09-deploy',
];
export const STAGE_TIMEOUTS: Record<string, number> = {
'00-intake': 120,
'00b-discovery': 300,
'01-board': 120,
'02-planning-1': 600,
// ... etc
};
export const STAGE_LABELS: Record<string, string> = {
'00-intake': 'INTAKE',
// ... etc
};
```
Also: STRATEGIC_KEYWORDS, TECHNICAL_KEYWORDS for brief classification.
### 3. brief-classifier.ts
**Source:** `classify_brief()`, `parse_brief_frontmatter()`, `stages_for_class()` from `~/src/mosaic-stack/forge/lib`
- Auto-classify brief by keyword analysis (strategic vs technical)
- Parse YAML frontmatter for explicit `class:` field
- CLI flag override
- Return stage list based on classification (strategic = full pipeline, technical = skip board, hotfix = skip board + brief analyzer)
### 4. stage-adapter.ts
**Source:** `~/src/mosaic-stack/forge/pipeline/orchestrator/stage_adapter.py`
- `mapStageToTask()`: Convert a Forge stage into a task compatible with TaskExecutor
- Stage briefs written to `{runDir}/{stageName}/brief.md`
- Result paths at `{runDir}/{stageName}/result.json`
- Previous results read from disk at runtime (not baked into brief)
- Per-stage timeouts from STAGE_TIMEOUTS
- depends_on chain built from stage sequence
### 5. board-tasks.ts
**Source:** `~/src/mosaic-stack/forge/pipeline/orchestrator/board_tasks.py`
- `loadBoardPersonas()`: Read all .md files from `pipeline/agents/board/`
- `generateBoardTasks()`: One task per persona + synthesis task
- Synthesis depends on all persona tasks with `depends_on_policy: 'all_terminal'`
- Persona briefs include role description + brief under review
- Synthesis script merges independent reviews into board memo
### 6. pipeline-runner.ts
**Source:** `~/src/mosaic-stack/forge/pipeline/orchestrator/pipeline_runner.py` + `~/src/mosaic-stack/forge/lib` (cmd_run, cmd_resume, cmd_status)
- `runPipeline(briefPath, projectRoot, options)`: Full pipeline execution
- Creates run directory at `{projectRoot}/.forge/runs/{runId}/`
- Generates tasks for all stages, submits to TaskExecutor
- Tracks manifest.json with stage statuses
- `resumePipeline(runDir)`: Pick up from last incomplete stage
- `getPipelineStatus(runDir)`: Read manifest and report
**Key difference from Python:** Run output goes to PROJECT-scoped `.forge/runs/`, not inside the Forge package.
### 7. Persona Override System (NEW — not in Python)
- Base personas read from `packages/forge/pipeline/agents/`
- Project overrides read from `{projectRoot}/.forge/personas/{role}.md`
- Merge strategy: project persona content APPENDED to base persona (not replaced)
- Board composition configurable via `{projectRoot}/.forge/config.yaml`
- If no project config exists, use defaults (all base personas, no overrides)
## Package Structure
```
packages/forge/
├── src/
│ ├── index.ts
│ ├── types.ts
│ ├── constants.ts
│ ├── brief-classifier.ts
│ ├── stage-adapter.ts
│ ├── board-tasks.ts
│ ├── pipeline-runner.ts
│ └── persona-loader.ts
├── pipeline/ # Already copied (WP4) — markdown assets
│ ├── stages/
│ ├── agents/
│ ├── rails/
│ ├── gates/
│ └── templates/
├── __tests__/
│ ├── brief-classifier.test.ts
│ ├── stage-adapter.test.ts
│ ├── board-tasks.test.ts
│ ├── pipeline-runner.test.ts
│ └── persona-loader.test.ts
├── package.json
├── tsconfig.json
└── vitest.config.ts
```
## Package.json
```json
{
"name": "@mosaicstack/forge",
"version": "0.0.1",
"type": "module",
"exports": {
".": "./src/index.ts"
},
"dependencies": {
"@mosaicstack/macp": "workspace:*"
},
"devDependencies": {
"vitest": "workspace:*",
"typescript": "workspace:*"
}
}
```
Only dependency: @mosaicstack/macp (for gate types, event emission).
## Test Strategy (Board requirement)
**Deterministic code (brief-classifier, stage-adapter, board-tasks, persona-loader, constants):**
- Standard unit tests with known inputs/outputs
- 100% of classification logic, stage mapping, persona loading covered
**Non-deterministic code (pipeline-runner):**
- Fixture-based integration tests using a mock TaskExecutor
- Mock executor returns pre-recorded results for each stage
- Tests verify: manifest progression, stage ordering, dependency enforcement, resume behavior, error handling
- NO real AI calls in tests
**Markdown assets:** Excluded from coverage measurement (configure vitest to exclude `pipeline/` directory).
## ESM Requirements
- `"type": "module"` in package.json
- NodeNext module resolution in tsconfig
- `.js` extensions in all imports
- No CommonJS
## Key Design: Abstract TaskExecutor
```typescript
// In packages/forge/src/types.ts
export interface TaskExecutor {
submitTask(task: ForgeTask): Promise<void>;
waitForCompletion(taskId: string, timeoutMs: number): Promise<TaskResult>;
getTaskStatus(taskId: string): Promise<TaskStatus>;
}
// In packages/coord (or wherever the concrete impl lives)
export class CoordTaskExecutor implements TaskExecutor {
// ... uses packages/coord runner
}
```
This means packages/forge can be tested with a mock executor and deployed with any backend.
## Asset Resolution
Pipeline markdown assets (stages, personas, rails) must be resolved relative to the package installation, NOT hardcoded paths:
```typescript
// Use import.meta.url to find package root
const PACKAGE_ROOT = new URL('..', import.meta.url).pathname;
const PIPELINE_DIR = path.join(PACKAGE_ROOT, 'pipeline');
```
Project-level overrides resolved relative to projectRoot parameter.
@@ -0,0 +1,150 @@
# WP2: packages/macp — MACP Protocol Package
## Context
Port the MACP protocol layer from Python (in ~/src/mosaic-stack/tools/macp/) to TypeScript as `packages/macp` in this monorepo. This package provides the foundational protocol types, quality gate execution, credential resolution, and event system that `packages/coord` and `plugins/macp` depend on.
**Board decisions that constrain this work:**
- No Python in the new repo — everything rewrites to TypeScript
- OpenBrain learning capture/recall is OUT OF SCOPE (deferred to future brief)
- 85% test coverage on TS implementation files
- Credential resolver behavior must be captured as test fixtures BEFORE rewrite
- Clean index.ts exports, no internal path leakage
## Source Files (Python → TypeScript)
### 1. credential-resolver.ts
**Source:** `~/src/mosaic-stack/tools/macp/dispatcher/credential_resolver.py`
Resolution order (MUST preserve exactly):
1. Mosaic credential files (`~/.config/mosaic/credentials/{provider}.env`)
2. OpenClaw config (`~/.openclaw/openclaw.json`) — env block + models.providers.{provider}.apiKey
3. Ambient environment variables
4. CredentialError (failure)
Key behaviors to preserve:
- Provider registry: anthropic, openai, zai → env var names + credential file paths + OC config paths
- Dotenv parser: handles single/double quotes, comments, blank lines
- JSON5 stripping: placeholder-extraction approach (NOT naive regex) — protects URLs and timestamps inside string values
- OC config permission check: warn on world-readable, skip if wrong owner
- Redacted marker detection: `__OPENCLAW_REDACTED__` values skipped
- Task-level override via `credentials.provider_key_env`
### 2. gate-runner.ts
**Source:** `~/src/mosaic-stack/tools/macp/controller/gate_runner.py`
Three gate types:
- `mechanical`: shell command, pass = exit code 0
- `ai-review`: shell command producing JSON, parse findings, fail on blockers
- `ci-pipeline`: placeholder (always passes for now)
Key behaviors:
- `normalize_gate()`: accepts string or dict, normalizes to gate entry
- `run_gate()`: executes single gate, returns result with pass/fail
- `run_gates()`: executes all gates, emits events, returns (all_passed, results)
- AI review parsing: `_count_ai_findings()` reads stats.blockers or findings[].severity
- `fail_on` modes: "blocker" (default) or "any"
### 3. event-emitter.ts
**Source:** `~/src/mosaic-stack/tools/macp/controller/gate_runner.py` (emit_event, append_event functions) + `~/src/mosaic-stack/tools/macp/events/`
- Append structured events to ndjson file
- Event types: task.assigned, task.started, task.completed, task.failed, task.escalated, task.gated, task.retry.scheduled, rail.check.started, rail.check.passed, rail.check.failed
- Each event: event_id (uuid), event_type, task_id, status, timestamp, source, message, metadata
### 4. types.ts
**Source:** `~/src/mosaic-stack/tools/macp/protocol/task.schema.json`
TypeScript types for:
- Task (id, title, status, dispatch, runtime, depends_on, depends_on_policy, quality_gates, timeout_seconds, metadata, etc.)
- Event (event_id, event_type, task_id, status, timestamp, source, message, metadata)
- GateResult (command, exit_code, type, passed, output, findings, blockers)
- TaskResult (task_id, status, completed_at, exit_code, gate_results, files_changed, etc.)
- CredentialError, ProviderRegistry
### 5. schemas/ (copy)
Copy `~/src/mosaic-stack/tools/macp/protocol/task.schema.json` as-is.
## Package Structure
```
packages/macp/
├── src/
│ ├── index.ts
│ ├── types.ts
│ ├── credential-resolver.ts
│ ├── gate-runner.ts
│ ├── event-emitter.ts
│ └── schemas/
│ └── task.schema.json
├── __tests__/
│ ├── credential-resolver.test.ts
│ ├── gate-runner.test.ts
│ └── event-emitter.test.ts
├── package.json
├── tsconfig.json
└── vitest.config.ts
```
## Package.json
```json
{
"name": "@mosaicstack/macp",
"version": "0.0.1",
"type": "module",
"exports": {
".": "./src/index.ts"
},
"dependencies": {},
"devDependencies": {
"vitest": "workspace:*",
"typescript": "workspace:*"
}
}
```
Zero external dependencies. Uses node:fs, node:path, node:child_process, node:crypto only.
## Test Requirements
Port ALL existing Python tests as TypeScript equivalents:
- `test_resolve_from_file` → credential file resolution
- `test_resolve_from_ambient` → ambient env resolution
- `test_resolve_from_oc_config_env_block` → OC config env block
- `test_resolve_from_oc_config_provider_apikey` → OC config provider
- `test_oc_config_precedence` → mosaic file wins over OC config
- `test_oc_config_missing_file` → graceful fallback
- `test_json5_strip` → structural transforms
- `test_json5_strip_urls_and_timestamps` → URLs/timestamps survive
- `test_redacted_values_skipped` → redacted marker detection
- `test_oc_config_permission_warning` → file permission check
- `test_resolve_missing_raises` → CredentialError thrown
- Gate runner: mechanical pass/fail, AI review parsing, ci-pipeline placeholder
- Event emitter: append to ndjson, event structure validation
## ESM Requirements
- `"type": "module"` in package.json
- NodeNext module resolution in tsconfig
- `.js` extensions in all imports
- No CommonJS (`require`, `module.exports`)
## Integration Points
After this package is built:
- `packages/coord` should import `@mosaicstack/macp` for event emission and gate types
- `plugins/macp` should import `@mosaicstack/macp` for credential resolution and protocol types
@@ -0,0 +1,63 @@
# WP3: plugins/mosaic-framework — OC Rails Injection Plugin
## Context
Port the OpenClaw framework plugin from ~/src/mosaic-stack/oc-plugins/mosaic-framework/ to `plugins/mosaic-framework` in this monorepo. This plugin injects Mosaic framework contracts (rails, completion gates, worktree requirements) into every OpenClaw agent session.
**This is SEPARATE from plugins/macp:**
- `mosaic-framework` = passive enforcement — injects rails into all OC sessions
- `macp` = active runtime — provides ACP backend for MACP task execution
## Source Files
**Source:** `~/src/mosaic-stack/oc-plugins/mosaic-framework/`
- `index.ts` — plugin hooks (before_agent_start, subagent_spawning)
- `openclaw.plugin.json` — plugin manifest
- `package.json`
## What It Does
### For OC native agents (before_agent_start hook):
- Injects Mosaic global hard rules via `appendSystemContext`
- Completion gates: code review ✓ | security review ✓ | tests GREEN ✓ | CI green ✓
- Worker completion protocol: open PR → fire system event → EXIT — never merge
- Worktree requirement: `~/src/{repo}-worktrees/{task-slug}`, never `/tmp`
- Injects dynamic mission state via `prependContext` (reads from project's `.mosaic/orchestrator/mission.json`)
### For ACP coding workers (subagent_spawning hook):
- Writes `~/.codex/instructions.md` or `~/.claude/CLAUDE.md` BEFORE the process starts
- Full runtime contract: mandatory load order, hard gates, mode declaration
- Global framework rules + worktree + completion gate requirements
## Implementation
Port the TypeScript source, updating hardcoded paths to be configurable. The OC plugin SDK imports should reference the installed OpenClaw location dynamically (not hardcoded `/home/jarvis/` paths like the OLD version).
**Structure:**
```
plugins/mosaic-framework/
├── src/
│ └── index.ts
├── openclaw.plugin.json
├── package.json
└── tsconfig.json
```
## Key Constraint
The plugin SDK imports in the OLD version use absolute paths:
```typescript
import type { OpenClawPluginApi } from '/home/jarvis/.npm-global/lib/node_modules/openclaw/dist/plugin-sdk/index.js';
```
This must be resolved dynamically or via a peer dependency. Check how `plugins/macp` handles this in the new repo and follow the same pattern.
## Tests
Minimal — plugin hooks are integration-tested against OC runtime. Unit test the context string builders and config resolution.