Compare commits

...

2 Commits

Author SHA1 Message Date
ec5e1e346c style: format AGENTS.md (glm-5.1 table alignment)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 08:17:04 -05:00
b5a53308df feat(framework): superpowers enforcement, typecheck hook, file-ownership rules
- Add PostToolUse typecheck hook (typecheck-hook.sh) that runs tsc --noEmit
  after TS/TSX edits for immediate type error feedback
- Add Superpowers Enforcement section to AGENTS.md requiring active use of
  skills, hooks, MCP tools, and plugins — not just passive availability
- Add self-evolution captures (framework-improvement, tooling-gap, friction)
- Add file-ownership/partitioning rules to ORCHESTRATOR.md preventing parallel
  worker file collisions
- Add settings audit to launch.ts that validates ~/.claude/settings.json has
  required hooks and plugins at mosaic claude launch time
- Document required Claude Code settings in RUNTIME.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 08:17:04 -05:00
7 changed files with 267 additions and 9 deletions

View File

@@ -59,9 +59,9 @@ pnpm typecheck && pnpm lint && pnpm format:check # Quality gates
The `agent` column specifies the required model for each task. **This is set at task creation by the orchestrator and must not be changed by workers.**
| Value | When to use | Budget |
| -------- | ----------------------------------------------------------- | -------------------------- |
| --------- | ----------------------------------------------------------- | -------------------------- |
| `codex` | All coding tasks (default for implementation) | OpenAI credits — preferred |
| `glm-5` | Cost-sensitive coding where Codex is unavailable | Z.ai credits |
| `glm-5.1` | Cost-sensitive coding where Codex is unavailable | Z.ai credits |
| `haiku` | Review gates, verify tasks, status checks, docs-only | Cheapest Claude tier |
| `sonnet` | Complex planning, multi-file reasoning, architecture review | Claude quota |
| `opus` | Major cross-cutting architecture decisions ONLY | Most expensive — minimize |

View File

@@ -73,6 +73,27 @@ Spawn a worker instead. No exceptions. No "quick fixes."
- Wait for at least one worker to complete before spawning more
- This optimizes token usage and reduces context pressure
## File Ownership & Partitioning (Hard Rule for Parallel Workers)
When dispatching parallel workers, the orchestrator MUST assign **non-overlapping file scopes** to each worker. File collisions between parallel workers cause merge conflicts, lost edits, and wasted tokens.
**Rules:**
1. **Exclusive file ownership.** Each file may be assigned to at most one active worker. The orchestrator records ownership in the worker dispatch (prompt or task definition).
2. **Partition by directory or module.** Prefer assigning entire directories/modules to one worker rather than splitting files within a directory across workers.
3. **Shared files are serialized.** If two tasks must modify the same file (e.g., a shared types file, a barrel export), they MUST run sequentially — never in parallel. Mark the second task with `depends_on` pointing to the first.
4. **Test files follow source ownership.** If Worker A owns `src/auth/login.ts`, Worker A also owns `src/auth/__tests__/login.test.ts`. Do not split source and test across workers.
5. **Config files are orchestrator-reserved.** Files like `package.json`, `tsconfig.json`, and CI config are owned by the orchestrator and modified only between worker cycles, never during parallel execution.
6. **Document ownership in dispatch.** When spawning a worker, include an explicit `Files:` section listing owned paths/globs. Example:
```
Files (exclusive — do not touch files outside this scope):
- apps/web/src/components/auth/**
- apps/web/src/lib/auth.ts
```
7. **Conflict recovery.** If a worker edits a file outside its scope, the orchestrator MUST flag the violation, assess the diff, and either revert the out-of-scope change or re-run the affected worker with the corrected file.
## Delegation Mode Selection
Choose one delegation mode at session start:

View File

@@ -151,11 +151,68 @@ When delegating work to subagents, you MUST select the cheapest model capable of
**Runtime-specific syntax**: See the runtime reference for how to specify model tier when spawning subagents (e.g., Claude Code Task tool `model` parameter).
## Superpowers Enforcement (Hard Rule)
Mosaic provides capabilities beyond basic code editing: **skills**, **hooks**, **MCP tools**, and **plugins**. These are not optional extras — they are force multipliers that agents MUST actively use when applicable. Under-utilization of superpowers is a framework violation.
### Skills
Skills are domain-specific instruction sets in `~/.config/mosaic/skills/` that encode best practices, patterns, and guardrails. They are loaded into agents via the runtime's skill mechanism (e.g., Claude Code slash commands, Pi `--skill` flag).
**Rules:**
1. Before starting implementation, scan available skills (`ls ~/.config/mosaic/skills/`) and load any that match the task domain.
2. When a skill exists for the technology being used (e.g., `nestjs-best-practices` for NestJS work), you MUST load it.
3. When spawning workers, include skill loading in the kickstart prompt.
4. If you complete a task without loading a relevant available skill, that is a quality gap.
### Hooks
Hooks provide automated quality gates (lint, format, typecheck) that fire on file edits. They are configured in the runtime settings and run automatically.
**Rules:**
1. Do NOT bypass or suppress hook output. If a hook reports errors, fix them before proceeding.
2. Hook failures are immediate feedback — treat them like failing tests.
3. If a hook is consistently failing on valid code, report it as a framework issue rather than working around it.
### MCP Tools
MCP servers extend agent capabilities with external integrations (sequential-thinking, web search, memory, browser automation, etc.). Available MCP tools are listed at session start.
**Rules:**
1. **sequential-thinking** is REQUIRED for planning, architecture, and multi-step reasoning. Use it — do not skip structured thinking for complex decisions.
2. **OpenBrain** (`capture`, `search`, `recent`) is the cross-agent memory layer. Capture discoveries and search for prior context at session start.
3. When a task involves web research, browser testing, or external data, use the available MCP tools (web-search, chrome-devtools, web-reader) rather than asking the user to look things up.
4. Check available MCP tools at session start and use them proactively throughout the session.
### Plugins (Runtime-Specific)
Runtime plugins (e.g., Claude Code's `feature-dev`, `pr-review-toolkit`, `code-review`) provide specialized agent capabilities like code review, architecture analysis, and test coverage analysis.
**Rules:**
1. After completing a significant code change, use code review plugins proactively — do not wait for the user to ask.
2. Before creating a PR, use PR review plugins to catch issues early.
3. When designing architecture, use planning/architecture plugins for structured analysis.
### Self-Evolution
The Mosaic framework should improve over time based on usage patterns:
1. When you discover a recurring pattern that should be codified, capture it to OpenBrain with `type: "framework-improvement"`.
2. When a hook, skill, or tool is missing for a common task, capture the gap to OpenBrain with `type: "tooling-gap"`.
3. When a framework rule causes friction without adding value, capture the observation to OpenBrain with `type: "framework-friction"`.
These captures feed the framework's continuous improvement cycle.
## Skills Policy
- Use only the minimum required skills for the active task.
- Load skills that match the active task domain before starting implementation.
- Do not load unrelated skills.
- Follow skill trigger rules from the active runtime instruction layer.
- Actively check `~/.config/mosaic/skills/` for applicable skills rather than passively waiting for them to be mentioned.
## Session Closure Requirement

View File

@@ -102,3 +102,30 @@ claude mcp add --scope user <name> -- npx -y <package>
`--scope local` = default, local-only (not committed).
Do NOT add `mcpServers` to `~/.claude/settings.json` — that key is ignored for MCP loading.
## Required Claude Code Settings (Enforced by Launcher)
The `mosaic claude` launcher validates that `~/.claude/settings.json` contains the required Mosaic configuration. Missing or outdated settings trigger a warning at launch.
**Required hooks:**
| Event | Matcher | Script | Purpose |
| ----------- | ------------------------ | ------------------------- | ---------------------------------------------- |
| PreToolUse | `Write\|Edit\|MultiEdit` | `prevent-memory-write.sh` | Block writes to `~/.claude/projects/*/memory/` |
| PostToolUse | `Edit\|MultiEdit\|Write` | `qa-hook-stdin.sh` | QA report generation after code edits |
| PostToolUse | `Edit\|MultiEdit\|Write` | `typecheck-hook.sh` | Inline TypeScript type checking |
**Required plugins:**
| Plugin | Purpose |
| ------------------- | -------------------------------------------------------------------------------------------------------- |
| `feature-dev` | Subagent architecture: code-reviewer, code-architect, code-explorer |
| `pr-review-toolkit` | PR review: code-simplifier, comment-analyzer, test-analyzer, silent-failure-hunter, type-design-analyzer |
| `code-review` | Standalone code review capabilities |
**Required settings:**
- `enableAllMcpTools: true` — Allow all configured MCP tools without per-tool approval
- `model: "opus"` — Default to opus for orchestrator-level sessions (workers use tiered models via Task tool)
If `mosaic claude` detects missing hooks or plugins, it will print a warning with the exact settings to add. The session will still launch — enforcement is advisory, not blocking — but agents operating without these settings are running degraded.

View File

@@ -23,6 +23,16 @@
"timeout": 60
}
]
},
{
"matcher": "Edit|MultiEdit|Write",
"hooks": [
{
"type": "command",
"command": "~/.config/mosaic/tools/qa/typecheck-hook.sh",
"timeout": 30
}
]
}
]
},

View File

@@ -0,0 +1,63 @@
#!/bin/bash
# Lightweight PostToolUse typecheck hook for TypeScript files.
# Runs tsc --noEmit on the nearest tsconfig after TS/TSX edits.
# Returns non-zero with diagnostic output so the agent sees type errors immediately.
# Location: ~/.config/mosaic/tools/qa/typecheck-hook.sh
set -eo pipefail
# Read JSON from stdin (Claude Code PostToolUse payload)
JSON_INPUT=$(cat)
# Extract file path
if command -v jq &>/dev/null; then
FILE_PATH=$(echo "$JSON_INPUT" | jq -r '.tool_input.file_path // .tool_response.filePath // .file_path // empty' 2>/dev/null || echo "")
else
FILE_PATH=$(echo "$JSON_INPUT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"\([^"]*\)"$/\1/' | head -1)
fi
# Only check TypeScript files
if ! [[ "$FILE_PATH" =~ \.(ts|tsx)$ ]]; then
exit 0
fi
# Must be a real file
if [ ! -f "$FILE_PATH" ]; then
exit 0
fi
# Find nearest tsconfig.json by walking up from the file
DIR=$(dirname "$FILE_PATH")
TSCONFIG=""
while [ "$DIR" != "/" ] && [ "$DIR" != "." ]; do
if [ -f "$DIR/tsconfig.json" ]; then
TSCONFIG="$DIR/tsconfig.json"
break
fi
DIR=$(dirname "$DIR")
done
if [ -z "$TSCONFIG" ]; then
# No tsconfig found — skip silently
exit 0
fi
# Run tsc --noEmit from the tsconfig directory
# Use --pretty for readable output, limit to 10 errors to keep output short
TSCONFIG_DIR=$(dirname "$TSCONFIG")
cd "$TSCONFIG_DIR"
# Run typecheck — capture output and exit code
OUTPUT=$(npx tsc --noEmit --pretty --maxNodeModuleJsDepth 0 2>&1) || STATUS=$?
if [ "${STATUS:-0}" -ne 0 ]; then
# Filter output to only show errors related to the edited file (if possible)
BASENAME=$(basename "$FILE_PATH")
RELEVANT=$(echo "$OUTPUT" | grep -A2 "$BASENAME" 2>/dev/null || echo "$OUTPUT" | head -20)
echo "TypeScript type errors detected after editing $FILE_PATH:"
echo "$RELEVANT"
exit 1
fi
exit 0

View File

@@ -78,6 +78,82 @@ function checkSoul(): void {
}
}
// ─── Claude settings validation ─────────────────────────────────────────────
interface SettingsAudit {
warnings: string[];
}
function auditClaudeSettings(): SettingsAudit {
const warnings: string[] = [];
const settingsPath = join(homedir(), '.claude', 'settings.json');
const settings = readJson(settingsPath);
if (!settings) {
warnings.push('~/.claude/settings.json not found — hooks and plugins will be missing');
return { warnings };
}
// Check required hooks
const hooks = settings['hooks'] as Record<string, unknown[]> | undefined;
const requiredPreToolUse = ['prevent-memory-write.sh'];
const requiredPostToolUse = ['qa-hook-stdin.sh', 'typecheck-hook.sh'];
const preHooks = (hooks?.['PreToolUse'] ?? []) as Array<Record<string, unknown>>;
const postHooks = (hooks?.['PostToolUse'] ?? []) as Array<Record<string, unknown>>;
const preCommands = preHooks.flatMap((h) => {
const inner = (h['hooks'] ?? []) as Array<Record<string, unknown>>;
return inner.map((ih) => String(ih['command'] ?? ''));
});
const postCommands = postHooks.flatMap((h) => {
const inner = (h['hooks'] ?? []) as Array<Record<string, unknown>>;
return inner.map((ih) => String(ih['command'] ?? ''));
});
for (const script of requiredPreToolUse) {
if (!preCommands.some((c) => c.includes(script))) {
warnings.push(`Missing PreToolUse hook: ${script}`);
}
}
for (const script of requiredPostToolUse) {
if (!postCommands.some((c) => c.includes(script))) {
warnings.push(`Missing PostToolUse hook: ${script}`);
}
}
// Check required plugins
const plugins = (settings['enabledPlugins'] ?? {}) as Record<string, boolean>;
const requiredPlugins = ['feature-dev', 'pr-review-toolkit', 'code-review'];
for (const plugin of requiredPlugins) {
const found = Object.keys(plugins).some((k) => k.startsWith(plugin) && plugins[k]);
if (!found) {
warnings.push(`Missing plugin: ${plugin}`);
}
}
// Check enableAllMcpTools
if (!settings['enableAllMcpTools']) {
warnings.push('enableAllMcpTools is not true — MCP tools may require per-tool approval');
}
return { warnings };
}
function printSettingsWarnings(audit: SettingsAudit): void {
if (audit.warnings.length === 0) return;
console.log('\n[mosaic] Claude Code settings audit:');
for (const w of audit.warnings) {
console.log(`${w}`);
}
console.log(
'[mosaic] Run: mosaic doctor — or see ~/.config/mosaic/runtime/claude/RUNTIME.md for required settings.\n',
);
}
function checkSequentialThinking(runtime: string): void {
const checker = fwScript('mosaic-ensure-sequential-thinking');
if (!existsSync(checker)) return; // Skip if checker doesn't exist
@@ -407,6 +483,10 @@ function launchRuntime(runtime: RuntimeName, args: string[], yolo: boolean): nev
switch (runtime) {
case 'claude': {
// Audit Claude Code settings and warn about missing hooks/plugins
const settingsAudit = auditClaudeSettings();
printSettingsWarnings(settingsAudit);
const prompt = buildRuntimePrompt('claude');
const cliArgs = yolo ? ['--dangerously-skip-permissions'] : [];
cliArgs.push('--append-system-prompt', prompt);