@ionivetech/mugiwara 0.6.6 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +2 -7
- package/.codex-plugin/plugin.json +2 -7
- package/.cursor-plugin/plugin.json +2 -7
- package/.kimi-plugin/plugin.json +2 -7
- package/.opencode/mugiwara-helpers.mjs +2 -2
- package/.opencode/plugins/mugiwara.mjs +3 -18
- package/AGENTS.md +5 -4
- package/GEMINI.md +3 -3
- package/README.md +203 -331
- package/content/agents/brook-healing.md +8 -4
- package/content/agents/chopper-checkpoint.md +7 -3
- package/content/agents/eval-runner.md +4 -4
- package/content/agents/franky-gates.md +4 -4
- package/content/agents/jinbe-security.md +6 -7
- package/content/agents/luffy-orchestrator.md +11 -13
- package/content/agents/memory-keeper.md +4 -4
- package/content/agents/nami-planner.md +4 -4
- package/content/agents/resume-coordinator.md +7 -7
- package/content/agents/robin-reviewer.md +7 -3
- package/content/agents/sanji-quality.md +2 -2
- package/content/agents/skeptic-verifier.md +2 -2
- package/content/agents/usopp-brainstorm.md +3 -3
- package/content/agents/zoro-execution.md +6 -6
- package/content/skills/mugiwara-backend/SKILL.md +54 -43
- package/content/skills/mugiwara-backend/references/database.md +61 -0
- package/content/skills/mugiwara-brainstorm/SKILL.md +1 -1
- package/content/skills/mugiwara-checkpoint/SKILL.md +23 -11
- package/content/skills/mugiwara-checkpoint/references/ledger-format.md +1 -1
- package/content/skills/mugiwara-contract-first/SKILL.md +46 -1
- package/content/skills/mugiwara-execution/SKILL.md +37 -37
- package/content/skills/mugiwara-execution/references/dispatch.md +1 -1
- package/content/skills/mugiwara-execution/references/execution-phase-flows.md +18 -0
- package/content/skills/mugiwara-execution/references/resume-batching.md +2 -2
- package/content/skills/mugiwara-frontend/SKILL.md +44 -43
- package/content/skills/mugiwara-frontend/references/checklist.md +14 -0
- package/content/skills/mugiwara-gates/SKILL.md +23 -14
- package/content/skills/mugiwara-healing/SKILL.md +26 -25
- package/content/skills/mugiwara-lessons/SKILL.md +2 -2
- package/content/skills/mugiwara-orchestration/SKILL.md +11 -11
- package/content/skills/mugiwara-orchestration/references/check-ins.md +2 -2
- package/content/skills/mugiwara-orchestration/references/closure.md +17 -12
- package/content/skills/mugiwara-orchestration/references/control-commands.md +14 -0
- package/content/skills/mugiwara-orchestration/references/triage-escalation.md +11 -1
- package/content/skills/mugiwara-planning/SKILL.md +26 -29
- package/content/skills/mugiwara-planning/references/large-campaign-subplan.md +41 -0
- package/content/skills/mugiwara-planning/references/plan-template.md +24 -2
- package/content/skills/mugiwara-quality/SKILL.md +21 -12
- package/content/skills/mugiwara-resume/SKILL.md +8 -3
- package/content/skills/mugiwara-review/SKILL.md +19 -13
- package/content/skills/mugiwara-security/SKILL.md +47 -36
- package/content/skills/mugiwara-ship/SKILL.md +1 -1
- package/content/skills/mugiwara-ship/references/cleanup.md +17 -16
- package/content/skills/mugiwara-workflow/SKILL.md +11 -17
- package/content/skills/mugiwara-workflow/references/adaptive-budget-governor.md +5 -0
- package/content/skills/mugiwara-workflow/references/benchmark-governor.md +53 -0
- package/content/skills/mugiwara-workflow/references/cognitive-output-governor.md +5 -0
- package/content/skills/mugiwara-workflow/references/large-campaign-subplan.md +29 -0
- package/content/skills/mugiwara-workflow/references/scope-code-governor.md +14 -0
- package/content/skills/mugiwara-workflow/references/stop-slop-governor.md +14 -0
- package/content/skills/mugiwara-workflow/references/workspace-layout.md +42 -38
- package/dist/mugiwara.js +1642 -528
- package/gemini-extension.json +1 -1
- package/hooks/auto-savepoint.js +18 -10
- package/hooks/auto-savepoint.ts +23 -23
- package/hooks/engagement-marker.js +1 -1
- package/hooks/engagement-marker.ts +1 -1
- package/hooks/pipeline-guard.js +17 -13
- package/hooks/pipeline-guard.ts +24 -20
- package/hooks/session-start.js +13 -10
- package/hooks/session-start.ts +24 -19
- package/package.json +2 -2
- package/plugin.json +1 -1
- package/references/complexity.md +27 -4
- package/references/definition-of-done.md +1 -1
- package/references/multi-actor.md +20 -2
- package/references/posture-routing.md +31 -0
- package/references/prose-style.md +54 -0
- package/scripts/benchmark-governor.ts +516 -0
- package/scripts/benchmark-thresholds.json +47 -0
- package/scripts/check-doc-links.ts +46 -0
- package/scripts/conformance.ts +6 -16
- package/scripts/coverage-gate.ts +20 -6
- package/scripts/gate-selftest.ts +138 -7
- package/scripts/lane.sh +54 -8
- package/scripts/lib/lane-base.sh +4 -4
- package/scripts/lib/patterns.sh +5 -0
- package/scripts/policy-force.ts +22 -0
- package/scripts/retrieval-eval.ts +10 -4
- package/scripts/savepoint.sh +155 -58
- package/scripts/validate-content.ts +43 -11
- package/scripts/verify-install.ts +9 -7
- package/src/adaptive-budget.ts +178 -0
- package/src/args.ts +4 -3
- package/src/budget.ts +47 -0
- package/src/check-artifacts.ts +45 -0
- package/src/cli.ts +257 -108
- package/src/cognition.ts +234 -0
- package/src/config.ts +107 -0
- package/src/context.ts +72 -0
- package/src/continue.ts +29 -10
- package/src/cost.ts +186 -0
- package/src/evidence.ts +160 -0
- package/src/installer.ts +25 -34
- package/src/integrity.ts +158 -0
- package/src/investigation.ts +72 -0
- package/src/mission.ts +341 -94
- package/src/policy.ts +156 -0
- package/src/posture.ts +86 -0
- package/src/provenance.ts +116 -0
- package/src/reporting.ts +225 -0
- package/src/rollback.ts +95 -0
- package/src/routing.ts +69 -0
- package/src/run.ts +2 -2
- package/src/scope.ts +321 -0
- package/src/sign.ts +235 -0
- package/src/slop.ts +306 -0
- package/src/targets/claude.ts +2 -2
- package/src/work.ts +273 -0
- package/.opencode/commands/mugiwara-execute.md +0 -13
- package/.opencode/commands/mugiwara-heal.md +0 -13
- package/.opencode/commands/mugiwara-onboard.md +0 -14
- package/.opencode/commands/mugiwara-plan.md +0 -17
- package/.opencode/commands/mugiwara-ship.md +0 -13
- package/.opencode/commands/using-mugiwara.md +0 -20
- package/content/skills/mugiwara-agent-security/SKILL.md +0 -58
- package/content/skills/mugiwara-agent-security/references/checklist.md +0 -20
- package/content/skills/mugiwara-context-budget/SKILL.md +0 -66
- package/content/skills/mugiwara-context-budget/references/context-budget.md +0 -37
- package/content/skills/mugiwara-pr/SKILL.md +0 -69
- package/content/skills/mugiwara-pr/references/verdict-format.md +0 -31
- package/content/skills/mugiwara-sunset/SKILL.md +0 -82
- package/content/skills/using-mugiwara/SKILL.md +0 -51
- package/references/token-budget.md +0 -56
- package/scripts/evidence.sh +0 -81
- package/scripts/initiative.ts +0 -296
- package/scripts/mission-report.sh +0 -293
- package/src/onboard.ts +0 -207
package/src/slop.ts
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
// src/slop.ts
|
|
2
|
+
// Phase 6 Stop-Slop Governor — slop taxonomy, detection signals, progress
|
|
3
|
+
// measurement, work-to-cost anomaly, intervention rules + 6 category detectors
|
|
4
|
+
// (Native Cost Governor, plan §51 Phase 6, §20–§24, §21).
|
|
5
|
+
//
|
|
6
|
+
// Boundary: pure verdict functions over explicit inputs (unit-testable), plus a
|
|
7
|
+
// record helper that persists via the sanitized recordOptDecision (§41). No new
|
|
8
|
+
// config keys; savepoint.sh/lane-base.sh untouched. The crew acts — this module
|
|
9
|
+
// records.
|
|
10
|
+
|
|
11
|
+
import { recordOptDecision } from './cost.ts';
|
|
12
|
+
|
|
13
|
+
// ── Slop taxonomy (§21) ──
|
|
14
|
+
|
|
15
|
+
export type SlopKind =
|
|
16
|
+
| 'investigation'
|
|
17
|
+
| 'context'
|
|
18
|
+
| 'reasoning'
|
|
19
|
+
| 'output'
|
|
20
|
+
| 'code'
|
|
21
|
+
| 'retry'
|
|
22
|
+
| 'healing'
|
|
23
|
+
| 'scope';
|
|
24
|
+
|
|
25
|
+
export const SLOP_TAXONOMY: Record<SlopKind, string> = {
|
|
26
|
+
investigation: 'reading unrelated files / searching without narrowing / repeated exploration',
|
|
27
|
+
context: 'repeated reads / duplicate content / irrelevant files',
|
|
28
|
+
reasoning: 'speculative architecture / repeated reconsideration / hypothetical requirements',
|
|
29
|
+
output: 'verbose output / duplicate explanations without compression',
|
|
30
|
+
code: 'unnecessary abstraction / dependency / boilerplate without justification',
|
|
31
|
+
retry: 'same action with same evidence repeatedly failing',
|
|
32
|
+
healing: 'healing cycle with no fixes',
|
|
33
|
+
scope: 'files outside declared scope without acceptance expansion',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Classify a raw signal string into the §21 taxonomy via keyword match.
|
|
38
|
+
* Returns null when the signal does not map to any known kind.
|
|
39
|
+
*/
|
|
40
|
+
export function classifySlop(signal: string): SlopKind | null {
|
|
41
|
+
const s = signal.toLowerCase();
|
|
42
|
+
if (s.includes('same command') || s.includes('same action') || s.includes('repeated command') || s.includes('retry') || s.includes('same evidence'))
|
|
43
|
+
return 'retry';
|
|
44
|
+
if (s.includes('healing') || s.includes('heal') || s.includes('fixes_in_cycle') || s.includes('no fixes'))
|
|
45
|
+
return 'healing';
|
|
46
|
+
if (s.includes('repeated file') || s.includes('repeated read') || s.includes('duplicate') || s.includes('irrelevant file') || s.includes('re-read'))
|
|
47
|
+
return 'context';
|
|
48
|
+
if (s.includes('unrelated file') || s.includes('exploration') || s.includes('investigation') || s.includes('searching without'))
|
|
49
|
+
return 'investigation';
|
|
50
|
+
if (s.includes('scope') || s.includes('out-of-scope') || s.includes('out of scope') || s.includes('declared scope') || s.includes('unrelated refactor'))
|
|
51
|
+
return 'scope';
|
|
52
|
+
if (s.includes('loc') || s.includes('boilerplate') || s.includes('abstraction') || s.includes('dependency') || s.includes('code slop'))
|
|
53
|
+
return 'code';
|
|
54
|
+
if (s.includes('speculative') || s.includes('reconsideration') || s.includes('hypothetical') || s.includes('reasoning slop'))
|
|
55
|
+
return 'reasoning';
|
|
56
|
+
if (s.includes('verbose') || s.includes('duplicate explanation') || s.includes('output slop') || s.includes('compress'))
|
|
57
|
+
return 'output';
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ── Detection signals (§22) ──
|
|
62
|
+
|
|
63
|
+
export type SlopSignal = { kind: SlopKind; signal: string; count: number; threshold: number };
|
|
64
|
+
|
|
65
|
+
export function detectSlopSignal(input: {
|
|
66
|
+
kind: SlopKind;
|
|
67
|
+
count: number;
|
|
68
|
+
threshold: number;
|
|
69
|
+
evidence_delta?: number;
|
|
70
|
+
}): { slop: boolean; reason: string } {
|
|
71
|
+
const { kind, count, threshold, evidence_delta } = input;
|
|
72
|
+
const hasGain = evidence_delta !== undefined && evidence_delta !== 0;
|
|
73
|
+
const slop = count >= threshold && !hasGain;
|
|
74
|
+
const reason = slop
|
|
75
|
+
? `slop: ${kind} — count ${count} ≥ threshold ${threshold} with no evidence gain`
|
|
76
|
+
: `no slop: ${kind} — ${count < threshold ? `count ${count} < threshold ${threshold}` : `evidence gained (${evidence_delta})`}`;
|
|
77
|
+
return { slop, reason };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ── Progress measurement (§23) ──
|
|
81
|
+
|
|
82
|
+
export type ProgressSnapshot = {
|
|
83
|
+
tokens_used: number;
|
|
84
|
+
evidence_items: number;
|
|
85
|
+
criteria_mapped: number;
|
|
86
|
+
files_understood: number;
|
|
87
|
+
tests_fixed: number;
|
|
88
|
+
code_chars: number;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export function measureProgress(
|
|
92
|
+
before: ProgressSnapshot,
|
|
93
|
+
after: ProgressSnapshot,
|
|
94
|
+
): { progress: number; cost_delta: number; progress_per_cost: number; slop_signal: boolean; reason: string } {
|
|
95
|
+
const evidenceDelta = after.evidence_items - before.evidence_items;
|
|
96
|
+
const criteriaDelta = after.criteria_mapped - before.criteria_mapped;
|
|
97
|
+
const testsDelta = after.tests_fixed - before.tests_fixed;
|
|
98
|
+
const codeDelta = after.code_chars - before.code_chars;
|
|
99
|
+
const codeProgress = codeDelta > 0 ? 1 : 0;
|
|
100
|
+
const progress = evidenceDelta + criteriaDelta + testsDelta + codeProgress;
|
|
101
|
+
const cost_delta = after.tokens_used - before.tokens_used;
|
|
102
|
+
const progress_per_cost = cost_delta > 0 ? progress / cost_delta : 0;
|
|
103
|
+
const slop_signal = cost_delta > 0 && progress === 0;
|
|
104
|
+
const reason = slop_signal ? `slop — ${cost_delta} tokens with no progress` : `progress ${progress} over ${cost_delta} tokens`;
|
|
105
|
+
return { progress, cost_delta, progress_per_cost, slop_signal, reason };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ── Work-to-cost anomaly (§24) ──
|
|
109
|
+
|
|
110
|
+
export type AnomalyInput = { progress_per_cost: number; baseline_per_cost: number; drop_threshold?: number };
|
|
111
|
+
|
|
112
|
+
export function detectAnomaly(input: AnomalyInput): { anomaly: boolean; reason: string } {
|
|
113
|
+
const threshold = input.drop_threshold ?? 0.5;
|
|
114
|
+
if (input.baseline_per_cost <= 0) {
|
|
115
|
+
return { anomaly: false, reason: 'no anomaly — baseline 0 or above threshold' };
|
|
116
|
+
}
|
|
117
|
+
const anomaly = input.progress_per_cost < input.baseline_per_cost * threshold;
|
|
118
|
+
if (anomaly) {
|
|
119
|
+
const pct = Math.round((1 - input.progress_per_cost / input.baseline_per_cost) * 100);
|
|
120
|
+
return { anomaly: true, reason: `anomaly — ${pct}% drop below baseline` };
|
|
121
|
+
}
|
|
122
|
+
return { anomaly: false, reason: 'no anomaly — baseline 0 or above threshold' };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ── Intervention rules (§20) ──
|
|
126
|
+
|
|
127
|
+
export type Intervention = 'tolerate' | 'stop' | 'compress' | 'escalate';
|
|
128
|
+
export type InterventionInput = {
|
|
129
|
+
kind: SlopKind;
|
|
130
|
+
slop: boolean;
|
|
131
|
+
severity: 'harmless' | 'wasteful' | 'harmful';
|
|
132
|
+
progress_stalled: boolean;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export function decideIntervention(input: InterventionInput): { intervention: Intervention; reason: string } {
|
|
136
|
+
if (!input.slop) return { intervention: 'tolerate', reason: `tolerate — no slop for ${input.kind}` };
|
|
137
|
+
if (input.severity === 'harmful') return { intervention: 'escalate', reason: `escalate — ${input.kind} harmful slop` };
|
|
138
|
+
if (input.severity === 'wasteful') return { intervention: 'stop', reason: `stop — ${input.kind} wasteful slop` };
|
|
139
|
+
// harmless
|
|
140
|
+
if (input.progress_stalled) return { intervention: 'compress', reason: `compress — ${input.kind} harmless but stalled` };
|
|
141
|
+
return { intervention: 'tolerate', reason: `tolerate — ${input.kind} harmless slop` };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ── Retry slop (§21.6/§31) ──
|
|
145
|
+
|
|
146
|
+
export type RetryInput = {
|
|
147
|
+
action: string;
|
|
148
|
+
evidence_fingerprint: string;
|
|
149
|
+
outcome: 'fail' | 'pass';
|
|
150
|
+
history: { action: string; evidence_fingerprint: string; outcome: string }[];
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export function detectRetrySlop(input: RetryInput): { slop: boolean; reason: string; kind: SlopKind } {
|
|
154
|
+
const kind: SlopKind = 'retry';
|
|
155
|
+
if (input.outcome !== 'fail') return { slop: false, reason: 'no slop — outcome is pass', kind };
|
|
156
|
+
const found = input.history.some((h) => h.action === input.action && h.evidence_fingerprint === input.evidence_fingerprint && h.outcome === 'fail');
|
|
157
|
+
if (found) return { slop: true, reason: `slop: retry — same action ${input.action} with same evidence ${input.evidence_fingerprint} repeatedly failing`, kind };
|
|
158
|
+
return { slop: false, reason: 'no slop — no matching failed history', kind };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ── Healing slop (§21.7/§32) ──
|
|
162
|
+
|
|
163
|
+
export type HealingInput = { cycle: number; fixes_in_cycle: number; history_fixes: number[]; max_cycles?: number };
|
|
164
|
+
|
|
165
|
+
export function detectHealingSlop(input: HealingInput): { slop: boolean; reason: string; kind: SlopKind } {
|
|
166
|
+
const kind: SlopKind = 'healing';
|
|
167
|
+
const max = input.max_cycles ?? 3;
|
|
168
|
+
const hasZeroHistory = input.history_fixes.some((n) => n === 0);
|
|
169
|
+
if (input.fixes_in_cycle === 0 && hasZeroHistory) {
|
|
170
|
+
return { slop: true, reason: `slop: healing — no fixes in cycle ${input.cycle} with previous zero-fix cycle`, kind };
|
|
171
|
+
}
|
|
172
|
+
if (input.cycle >= max && input.fixes_in_cycle === 0) {
|
|
173
|
+
return { slop: true, reason: `slop: healing — cycle ${input.cycle} ≥ max ${max} with no fixes`, kind };
|
|
174
|
+
}
|
|
175
|
+
return { slop: false, reason: 'no slop — healing making progress', kind };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ── Scope slop (§21.8) ──
|
|
179
|
+
|
|
180
|
+
export type ScopeSlopInput = {
|
|
181
|
+
files_changed: string[];
|
|
182
|
+
declared_scope: string[];
|
|
183
|
+
acceptance_expanded: boolean;
|
|
184
|
+
unrelated_refactors: string[];
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
export function detectScopeSlop(input: ScopeSlopInput): { slop: boolean; reason: string; kind: SlopKind } {
|
|
188
|
+
const kind: SlopKind = 'scope';
|
|
189
|
+
const outOfScope = input.files_changed.filter((f) => !input.declared_scope.includes(f));
|
|
190
|
+
const hasScopeDrift = outOfScope.length > 0 || input.unrelated_refactors.length > 0;
|
|
191
|
+
if (hasScopeDrift && !input.acceptance_expanded) {
|
|
192
|
+
const names = [...outOfScope, ...input.unrelated_refactors].join(', ');
|
|
193
|
+
return { slop: true, reason: `slop: scope — out-of-scope ${names} without acceptance expansion`, kind };
|
|
194
|
+
}
|
|
195
|
+
return { slop: false, reason: 'no scope slop — within declared scope or acceptance expanded', kind };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// ── Context slop (§21.2/§12) ──
|
|
199
|
+
|
|
200
|
+
export type ContextSlopInput = {
|
|
201
|
+
repeated_reads: number;
|
|
202
|
+
repeated_read_threshold: number;
|
|
203
|
+
duplicate_chars: number;
|
|
204
|
+
irrelevant_files: string[];
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export function detectContextSlop(input: ContextSlopInput): { slop: boolean; reason: string; kind: SlopKind } {
|
|
208
|
+
const kind: SlopKind = 'context';
|
|
209
|
+
const signals: string[] = [];
|
|
210
|
+
if (input.repeated_reads >= input.repeated_read_threshold) signals.push(`repeated reads ${input.repeated_reads} ≥ ${input.repeated_read_threshold}`);
|
|
211
|
+
if (input.duplicate_chars > 0) signals.push(`duplicate chars ${input.duplicate_chars}`);
|
|
212
|
+
if (input.irrelevant_files.length > 0) signals.push(`irrelevant files ${input.irrelevant_files.join(', ')}`);
|
|
213
|
+
if (signals.length > 0) return { slop: true, reason: `slop: context — ${signals.join('; ')}`, kind };
|
|
214
|
+
return { slop: false, reason: 'no context slop', kind };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ── Investigation slop (§21.1/§13) ──
|
|
218
|
+
|
|
219
|
+
export type InvestigationSlopInput = {
|
|
220
|
+
unrelated_files_opened: number;
|
|
221
|
+
max_unrelated_files: number;
|
|
222
|
+
repeated_reads: number;
|
|
223
|
+
repeated_read_threshold: number;
|
|
224
|
+
exploration_passes: number;
|
|
225
|
+
max_passes: number;
|
|
226
|
+
acceptance_mapped: boolean;
|
|
227
|
+
has_concrete_reason: boolean;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
export function detectInvestigationSlop(input: InvestigationSlopInput): { slop: boolean; reason: string; kind: SlopKind } {
|
|
231
|
+
const kind: SlopKind = 'investigation';
|
|
232
|
+
if (input.has_concrete_reason) return { slop: false, reason: 'no investigation slop — concrete reason present', kind };
|
|
233
|
+
const breaches: string[] = [];
|
|
234
|
+
if (input.unrelated_files_opened > input.max_unrelated_files) breaches.push(`unrelated files ${input.unrelated_files_opened} > ${input.max_unrelated_files}`);
|
|
235
|
+
if (input.repeated_reads >= input.repeated_read_threshold) breaches.push(`repeated reads ${input.repeated_reads} ≥ ${input.repeated_read_threshold}`);
|
|
236
|
+
if (input.exploration_passes >= input.max_passes) breaches.push(`passes ${input.exploration_passes} ≥ ${input.max_passes}`);
|
|
237
|
+
if (breaches.length > 0) return { slop: true, reason: `slop: investigation — ${breaches.join('; ')}`, kind };
|
|
238
|
+
return { slop: false, reason: 'no investigation slop', kind };
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ── Code slop (§21.5/§15) ──
|
|
242
|
+
|
|
243
|
+
export type CodeSlopInput = {
|
|
244
|
+
new_abstractions: number;
|
|
245
|
+
new_dependencies: number;
|
|
246
|
+
loc_added: number;
|
|
247
|
+
acceptance_expanded: boolean;
|
|
248
|
+
justification_provided: boolean;
|
|
249
|
+
boilerplate_chars: number;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
export function detectCodeSlop(input: CodeSlopInput): { slop: boolean; reason: string; kind: SlopKind } {
|
|
253
|
+
const kind: SlopKind = 'code';
|
|
254
|
+
if (input.acceptance_expanded || input.justification_provided) {
|
|
255
|
+
return { slop: false, reason: 'no code slop — acceptance expanded or justified', kind };
|
|
256
|
+
}
|
|
257
|
+
const signals: string[] = [];
|
|
258
|
+
if (input.new_abstractions > 0) signals.push(`abstractions ${input.new_abstractions}`);
|
|
259
|
+
if (input.new_dependencies > 0) signals.push(`dependencies ${input.new_dependencies}`);
|
|
260
|
+
if (input.boilerplate_chars > 0) signals.push(`boilerplate ${input.boilerplate_chars} chars`);
|
|
261
|
+
if (input.loc_added > 100) signals.push(`loc ${input.loc_added}`);
|
|
262
|
+
if (signals.length > 0) return { slop: true, reason: `slop: code — ${signals.join('; ')} without acceptance or justification`, kind };
|
|
263
|
+
return { slop: false, reason: 'no code slop', kind };
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// ── Decision trail (§41) ──
|
|
267
|
+
|
|
268
|
+
export function recordSlopDecision(
|
|
269
|
+
missionDir: string,
|
|
270
|
+
d: { decision: string; reason: string; evidence?: string; kind?: SlopKind },
|
|
271
|
+
): void {
|
|
272
|
+
const prefix = d.kind ? `[${d.kind}] ` : '';
|
|
273
|
+
recordOptDecision(missionDir, {
|
|
274
|
+
actor: 'slop-governor',
|
|
275
|
+
decision: `${prefix}${d.decision}`,
|
|
276
|
+
reason: d.reason,
|
|
277
|
+
evidence: d.evidence,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ── Live wiring (§3.3) ──
|
|
282
|
+
// Runs the existing detectors over state already available at ledger-build time
|
|
283
|
+
// (state.json heal cycle, context-registry repeated reads). One call site feeds
|
|
284
|
+
// the ledger's slopMetrics.interventions so it stops reading 0. Per-crew
|
|
285
|
+
// attribution: healing → Brook (Flow 8), context → all.
|
|
286
|
+
export type LiveSlopResult = {
|
|
287
|
+
interventions: number;
|
|
288
|
+
perRole: Record<string, number>;
|
|
289
|
+
rows: { role: string; kind: SlopKind; reason: string }[];
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
export function computeLiveSlop(input: {
|
|
293
|
+
heal_cycle: number;
|
|
294
|
+
repeated_reads: number;
|
|
295
|
+
repeated_read_threshold?: number;
|
|
296
|
+
max_heal_cycles?: number;
|
|
297
|
+
}): LiveSlopResult {
|
|
298
|
+
const rows: { role: string; kind: SlopKind; reason: string }[] = [];
|
|
299
|
+
const thr = input.repeated_read_threshold ?? 3;
|
|
300
|
+
const heal = detectHealingSlop({ cycle: input.heal_cycle, fixes_in_cycle: 0, history_fixes: [], max_cycles: input.max_heal_cycles ?? 3 });
|
|
301
|
+
if (heal.slop) rows.push({ role: 'Brook', kind: 'healing', reason: heal.reason });
|
|
302
|
+
if (input.repeated_reads >= thr) rows.push({ role: 'all', kind: 'context', reason: `repeated reads ${input.repeated_reads} ≥ ${thr}` });
|
|
303
|
+
const perRole: Record<string, number> = {};
|
|
304
|
+
for (const r of rows) perRole[r.role] = (perRole[r.role] ?? 0) + 1;
|
|
305
|
+
return { interventions: rows.length, perRole, rows };
|
|
306
|
+
}
|
package/src/targets/claude.ts
CHANGED
|
@@ -40,8 +40,8 @@ function copyScripts(dstDir: string): string[] {
|
|
|
40
40
|
if (!existsSync(src)) return;
|
|
41
41
|
for (const f of readdirSync(src)) {
|
|
42
42
|
// install.sh is the npx bootstrap, not a harness script — never shipped
|
|
43
|
-
// into a project.
|
|
44
|
-
if (
|
|
43
|
+
// into a project.
|
|
44
|
+
if (!f.endsWith('.sh') || f === 'install.sh') continue;
|
|
45
45
|
const to = join(dst, f);
|
|
46
46
|
mkdirSync(dst, { recursive: true });
|
|
47
47
|
copyFileSync(join(src, f), to);
|
package/src/work.ts
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
// src/work.ts
|
|
2
|
+
// Phase 3 Work Governor — verdict engine + decision trail
|
|
3
|
+
// (Native Cost Governor initiative, plan §51 Phase 3, spec §7/§8/§9/§19/§30/§41).
|
|
4
|
+
//
|
|
5
|
+
// Turns the Phase-2 signals into auditable skip/avoid/delegate/complete
|
|
6
|
+
// verdicts. Honest boundary (same as Phase 2 for investigation.ts): this
|
|
7
|
+
// module PRODUCES and RECORDS verdicts; the LLM crew (workflow skill, T4) is
|
|
8
|
+
// the only thing that acts on them. The module makes the decision structured
|
|
9
|
+
// and auditable — it does not pretend a TS function can force the model.
|
|
10
|
+
//
|
|
11
|
+
// Every verdict is a pure function of explicit inputs (unit-testable, parity
|
|
12
|
+
// locked by fixtures) and every skip/avoid/delegate/complete decision lands in
|
|
13
|
+
// the trail via recordWorkDecision → recordOptDecision (§41, S2 sanitizer).
|
|
14
|
+
import { delegateAt, laneBaseForLane, recordOptDecision } from './cost.ts';
|
|
15
|
+
|
|
16
|
+
// ── Stage classification (§7/§34) ───────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
export type StageClass = 'required' | 'conditional' | 'optional';
|
|
19
|
+
|
|
20
|
+
export type StageClassifyInput = {
|
|
21
|
+
stage: string;
|
|
22
|
+
requirement_kind: 'explicit' | 'exploratory' | 'ambiguous';
|
|
23
|
+
uncertainty_high: boolean;
|
|
24
|
+
provides_required_evidence: boolean;
|
|
25
|
+
protects_quality_security: boolean;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type StageClassifyVerdict = { stage: string; class: StageClass; reason: string };
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Classify a flow stage as required/conditional/optional. A stage that
|
|
32
|
+
* protects quality/security or provides required evidence is `required`
|
|
33
|
+
* (never skipped); a stage with high uncertainty or a non-explicit
|
|
34
|
+
* requirement is `conditional`; everything else is `optional`.
|
|
35
|
+
*/
|
|
36
|
+
export function classifyStage(input: StageClassifyInput): StageClassifyVerdict {
|
|
37
|
+
if (input.protects_quality_security) {
|
|
38
|
+
return { stage: input.stage, class: 'required', reason: 'protects quality/security — required' };
|
|
39
|
+
}
|
|
40
|
+
if (input.provides_required_evidence) {
|
|
41
|
+
return { stage: input.stage, class: 'required', reason: 'provides required evidence — required' };
|
|
42
|
+
}
|
|
43
|
+
if (input.uncertainty_high || input.requirement_kind !== 'explicit') {
|
|
44
|
+
return { stage: input.stage, class: 'conditional', reason: 'uncertain or non-explicit requirement — conditional' };
|
|
45
|
+
}
|
|
46
|
+
return { stage: input.stage, class: 'optional', reason: 'explicit, no protection/evidence need — optional' };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ── Evidence-backed stage skipping (§7/§13) ─────────────────────────────────
|
|
50
|
+
|
|
51
|
+
export type SkipInput = {
|
|
52
|
+
stage: string;
|
|
53
|
+
classification: StageClass;
|
|
54
|
+
evidence_present: boolean;
|
|
55
|
+
investigation_stopped: boolean;
|
|
56
|
+
context_over: boolean;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export type SkipVerdict = { stage: string; skip: boolean; reason: string; evidence?: string };
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Decide whether a classified stage may be skipped on evidence. `required`
|
|
63
|
+
* never skips (protects quality/security). `conditional` skips when evidence
|
|
64
|
+
* already answers or the investigation stopped; `optional` skips when
|
|
65
|
+
* evidence answers or the context is over budget. Every skip carries an
|
|
66
|
+
* explicit reason (§7 — never skipped silently).
|
|
67
|
+
*/
|
|
68
|
+
export function shouldSkipStage(input: SkipInput): SkipVerdict {
|
|
69
|
+
if (input.classification === 'required') {
|
|
70
|
+
return { stage: input.stage, skip: false, reason: 'required — protects quality/security' };
|
|
71
|
+
}
|
|
72
|
+
if (input.classification === 'conditional') {
|
|
73
|
+
if (input.evidence_present) {
|
|
74
|
+
return { stage: input.stage, skip: true, reason: 'evidence already answers', evidence: input.stage };
|
|
75
|
+
}
|
|
76
|
+
if (input.investigation_stopped) {
|
|
77
|
+
return { stage: input.stage, skip: true, reason: 'investigation stopped — no further value' };
|
|
78
|
+
}
|
|
79
|
+
return { stage: input.stage, skip: false, reason: 'conditional — no skip signal; run' };
|
|
80
|
+
}
|
|
81
|
+
// optional
|
|
82
|
+
if (input.evidence_present) {
|
|
83
|
+
return { stage: input.stage, skip: true, reason: 'evidence already answers', evidence: input.stage };
|
|
84
|
+
}
|
|
85
|
+
if (input.context_over) {
|
|
86
|
+
return { stage: input.stage, skip: true, reason: 'context over budget — tighten, do not expand' };
|
|
87
|
+
}
|
|
88
|
+
return { stage: input.stage, skip: false, reason: 'optional — no skip signal; run' };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ── Agent invocation control (§8) ───────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
export type InvocationInput = {
|
|
94
|
+
agent: string;
|
|
95
|
+
unique_responsibility: boolean;
|
|
96
|
+
evidence_answers: boolean;
|
|
97
|
+
stage_can_perform: boolean;
|
|
98
|
+
expected_value_gt_cost: boolean;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export type InvocationVerdict = { agent: string; invoke: boolean; reason: string };
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Decide whether an agent earns invocation. Invoke only when the agent has
|
|
105
|
+
* unique responsibility, evidence cannot answer, the stage cannot perform
|
|
106
|
+
* itself, and expected value exceeds cost. Never invoke merely because the
|
|
107
|
+
* agent exists in the crew. On refusal, name the first failing clause.
|
|
108
|
+
*/
|
|
109
|
+
export function evaluateInvocation(input: InvocationInput): InvocationVerdict {
|
|
110
|
+
if (!input.unique_responsibility) {
|
|
111
|
+
return { agent: input.agent, invoke: false, reason: 'no unique responsibility' };
|
|
112
|
+
}
|
|
113
|
+
if (input.evidence_answers) {
|
|
114
|
+
return { agent: input.agent, invoke: false, reason: 'evidence already answers' };
|
|
115
|
+
}
|
|
116
|
+
if (input.stage_can_perform) {
|
|
117
|
+
return { agent: input.agent, invoke: false, reason: 'stage can perform itself' };
|
|
118
|
+
}
|
|
119
|
+
if (!input.expected_value_gt_cost) {
|
|
120
|
+
return { agent: input.agent, invoke: false, reason: 'expected value not greater than cost' };
|
|
121
|
+
}
|
|
122
|
+
return { agent: input.agent, invoke: true, reason: 'unique responsibility, evidence cannot answer, value exceeds cost' };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ── Skill loading control (§9) ──────────────────────────────────────────────
|
|
126
|
+
|
|
127
|
+
export type SkillInput = {
|
|
128
|
+
skill: string;
|
|
129
|
+
required_by_task: boolean;
|
|
130
|
+
required_by_policy: boolean;
|
|
131
|
+
required_by_dependency: boolean;
|
|
132
|
+
failing_verification: boolean;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export type SkillVerdict = { skill: string; load: boolean; reason: string };
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Decide whether a skill earns loading — minimum sufficient set (§9): load
|
|
139
|
+
* only when required by the task, by policy, by a dependency, or by a failing
|
|
140
|
+
* verification. Else refuse with the standard reason.
|
|
141
|
+
*/
|
|
142
|
+
export function shouldLoadSkill(input: SkillInput): SkillVerdict {
|
|
143
|
+
if (input.required_by_task) return { skill: input.skill, load: true, reason: 'required by task' };
|
|
144
|
+
if (input.required_by_policy) return { skill: input.skill, load: true, reason: 'required by policy' };
|
|
145
|
+
if (input.required_by_dependency) return { skill: input.skill, load: true, reason: 'required by dependency' };
|
|
146
|
+
if (input.failing_verification) return { skill: input.skill, load: true, reason: 'required by failing verification' };
|
|
147
|
+
return { skill: input.skill, load: false, reason: 'not required by task/policy/dependency/verification' };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ── Delegation optimization (§30, consumes delegateAt + laneBaseForLane) ────
|
|
151
|
+
|
|
152
|
+
export type DelegationInput = {
|
|
153
|
+
lane: string;
|
|
154
|
+
budget: number;
|
|
155
|
+
tokens_used: number;
|
|
156
|
+
threshold_pct: number;
|
|
157
|
+
independent_tasks: number;
|
|
158
|
+
parallel_value: number;
|
|
159
|
+
estimated_overhead: number;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export type DelegationVerdict = {
|
|
163
|
+
delegate: boolean;
|
|
164
|
+
reason: string;
|
|
165
|
+
budget_at: number;
|
|
166
|
+
lane_base: number;
|
|
167
|
+
parallel_value: number;
|
|
168
|
+
overhead: number;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Decide whether delegation is worthwhile. Closes the Phase-2 Q1 remainder:
|
|
173
|
+
* budget ceiling = delegateAt(budget, threshold_pct); overhead floor = one
|
|
174
|
+
* delegate costs at least one agent's context load (laneBaseForLane). Delegate
|
|
175
|
+
* only when there are ≥2 independent tasks, parallel value beats the overhead
|
|
176
|
+
* floor, and usage is inside the delegation budget. Else refuse naming the
|
|
177
|
+
* failing clause.
|
|
178
|
+
*/
|
|
179
|
+
export function evaluateDelegation(input: DelegationInput): DelegationVerdict {
|
|
180
|
+
const budget_at = delegateAt(input.budget, input.threshold_pct);
|
|
181
|
+
const lane_base = laneBaseForLane(input.lane);
|
|
182
|
+
const overhead = Math.max(input.estimated_overhead, lane_base);
|
|
183
|
+
if (input.independent_tasks < 2) {
|
|
184
|
+
return {
|
|
185
|
+
delegate: false,
|
|
186
|
+
reason: 'not enough independent tasks (needs >= 2)',
|
|
187
|
+
budget_at,
|
|
188
|
+
lane_base,
|
|
189
|
+
parallel_value: input.parallel_value,
|
|
190
|
+
overhead,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
if (input.parallel_value <= overhead) {
|
|
194
|
+
return {
|
|
195
|
+
delegate: false,
|
|
196
|
+
reason: 'parallel value not greater than overhead',
|
|
197
|
+
budget_at,
|
|
198
|
+
lane_base,
|
|
199
|
+
parallel_value: input.parallel_value,
|
|
200
|
+
overhead,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
if (input.tokens_used > budget_at) {
|
|
204
|
+
return {
|
|
205
|
+
delegate: false,
|
|
206
|
+
reason: 'over delegation budget',
|
|
207
|
+
budget_at,
|
|
208
|
+
lane_base,
|
|
209
|
+
parallel_value: input.parallel_value,
|
|
210
|
+
overhead,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
delegate: true,
|
|
215
|
+
reason: 'parallel value exceeds overhead and within budget',
|
|
216
|
+
budget_at,
|
|
217
|
+
lane_base,
|
|
218
|
+
parallel_value: input.parallel_value,
|
|
219
|
+
overhead,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ── Completion detection (§19) ──────────────────────────────────────────────
|
|
224
|
+
|
|
225
|
+
export type CompletionInput = {
|
|
226
|
+
acceptance_satisfied: boolean;
|
|
227
|
+
implementation_complete: boolean;
|
|
228
|
+
tests_complete: boolean;
|
|
229
|
+
quality_gates_complete: boolean;
|
|
230
|
+
evidence_collected: boolean;
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
export type CompletionVerdict = { complete: boolean; missing: string[]; reason: string };
|
|
234
|
+
|
|
235
|
+
const COMPLETION_FIELDS: Array<keyof CompletionInput> = [
|
|
236
|
+
'acceptance_satisfied',
|
|
237
|
+
'implementation_complete',
|
|
238
|
+
'tests_complete',
|
|
239
|
+
'quality_gates_complete',
|
|
240
|
+
'evidence_collected',
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* A mission is complete only when all five §19 conditions hold. `missing`
|
|
245
|
+
* lists every condition still open; `reason` is `ready for closure` or the
|
|
246
|
+
* comma-joined missing list.
|
|
247
|
+
*/
|
|
248
|
+
export function completionCheck(input: CompletionInput): CompletionVerdict {
|
|
249
|
+
const missing = COMPLETION_FIELDS.filter((f) => !input[f]);
|
|
250
|
+
if (missing.length === 0) {
|
|
251
|
+
return { complete: true, missing: [], reason: 'ready for closure' };
|
|
252
|
+
}
|
|
253
|
+
return { complete: false, missing, reason: `missing: ${missing.join(', ')}` };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// ── Decision trail (§41) ────────────────────────────────────────────────────
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Record any skip/avoid/delegate/complete verdict as an optimization decision
|
|
260
|
+
* with the `work-governor` actor. Thin wrapper over the sanitized
|
|
261
|
+
* recordOptDecision (S2 — newline/CR stripped, no markdown injection).
|
|
262
|
+
*/
|
|
263
|
+
export function recordWorkDecision(
|
|
264
|
+
missionDir: string,
|
|
265
|
+
d: { decision: string; reason: string; evidence?: string },
|
|
266
|
+
): void {
|
|
267
|
+
recordOptDecision(missionDir, {
|
|
268
|
+
actor: 'work-governor',
|
|
269
|
+
decision: d.decision,
|
|
270
|
+
reason: d.reason,
|
|
271
|
+
...(d.evidence ? { evidence: d.evidence } : {}),
|
|
272
|
+
});
|
|
273
|
+
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Execute an approved mugiwara plan as Zoro (execution stage)
|
|
3
|
-
---
|
|
4
|
-
Execute the approved plan as Zoro, inline in the main conversation:
|
|
5
|
-
|
|
6
|
-
1. **Entry protocol first** — read the mission state (`.mugiwara/state/<mission>/[member].json`). No active mission → run Flow 0 triage before anything else. Foreign mission → stop, report owner. Base drift → stop, ask. Non-git → degrade to standard, say so once.
|
|
7
|
-
2. Load the skill: `mugiwara-execution`.
|
|
8
|
-
3. Read the existing plan from `.mugiwara/plans/` — that file is the bridge, never re-plan.
|
|
9
|
-
4. Open a todo list, run tasks sequentially inline; dispatch [PARALLEL] batches to worker subagents only.
|
|
10
|
-
5. Commit per logical task and verify every acceptance criterion with evidence in `.mugiwara/results/`.
|
|
11
|
-
6. **Return the result to Luffy — do not choose the next wave.**
|
|
12
|
-
|
|
13
|
-
See skills/mugiwara-execution for the wave-structured protocol.
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Heal earlier-wave failures as Brook (healing stage, after review/security findings)
|
|
3
|
-
---
|
|
4
|
-
Heal failures as Brook, inline in the main conversation:
|
|
5
|
-
|
|
6
|
-
1. **Entry protocol first** — read the mission state (`.mugiwara/state/<mission>/[member].json`). No active mission → run Flow 0 triage before anything else. Foreign mission → stop, report owner. Base drift → stop, ask. Non-git → degrade to standard, say so once. Read `heal_halt` (savepoint computes it as `heal_cycle ≥ heal_max_cycles`, config default 3) — when `true`, STOP and escalate to the user.
|
|
7
|
-
2. Load the skill: `mugiwara-healing`.
|
|
8
|
-
3. Read the `.mugiwara/issues` ledger first — stop-the-line triage per failure, never fix blind.
|
|
9
|
-
4. Prove-it before fixing: reproduce or verify the failure from `.mugiwara/results/` evidence.
|
|
10
|
-
5. Apply minimal root-cause fixes, update the ledger with evidence.
|
|
11
|
-
6. **Return the result to Luffy — do not choose the next wave.**
|
|
12
|
-
|
|
13
|
-
See skills/mugiwara-healing for the triage protocol.
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Run the Mugiwara onboarding wizard — zero-LLM terminal wizard via `mugiwara onboard`, writes .mugiwara/config.
|
|
3
|
-
---
|
|
4
|
-
Mugiwara onboard: $ARGUMENTS
|
|
5
|
-
|
|
6
|
-
Run the onboarding wizard. One path only — the zero-LLM terminal wizard:
|
|
7
|
-
|
|
8
|
-
1. Tell the user to run `mugiwara onboard` in their terminal (or `bunx @ionivetech/mugiwara onboard`).
|
|
9
|
-
2. Do NOT ask the questions yourself. Do NOT write .mugiwara/config. The wizard is a plain
|
|
10
|
-
script — no LLM, no network, works on every platform.
|
|
11
|
-
3. After the user finishes, verify `.mugiwara/config` exists and summarize the values.
|
|
12
|
-
|
|
13
|
-
The wizard never writes .mugiwara/onboard.json. All 14 crew agents are always active —
|
|
14
|
-
no agent-selection step.
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Plan a mugiwara mission as Nami (planning stage)
|
|
3
|
-
---
|
|
4
|
-
Plan the mission as Nami, inline in the main conversation:
|
|
5
|
-
|
|
6
|
-
1. **Entry protocol first** — read the mission state (`.mugiwara/state/<mission>/[member].json`). No active mission → run Flow 0 triage before anything else. Foreign mission → stop, report owner. Base drift → stop, ask. Non-git → degrade to standard, say so once.
|
|
7
|
-
2. Load the skill: `mugiwara-planning`.
|
|
8
|
-
3. Classify mission size, interview first, scan full context, write the scaled Quick/Standard/Full plan.
|
|
9
|
-
4. Embody the Nami crew role inline — never Task-dispatch.
|
|
10
|
-
5. Persist the plan to `.mugiwara/plans/`; later stages read it from there as the bridge.
|
|
11
|
-
6. **Return the plan to Luffy — do not choose the next wave.**
|
|
12
|
-
|
|
13
|
-
Spec input: read `.mugiwara/spec/YYYY-MM-DD-<mission>.md`. If it is empty or
|
|
14
|
-
missing, write the spec bridge from the user's request first (goal, acceptance
|
|
15
|
-
criteria, constraints) before planning — never plan from an empty spec.
|
|
16
|
-
|
|
17
|
-
See skills/mugiwara-planning for the full template and wave structure.
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Close the mission as Luffy (closure + ship stage, at mission end)
|
|
3
|
-
---
|
|
4
|
-
Close the mission as Luffy, inline in the main conversation:
|
|
5
|
-
|
|
6
|
-
1. **Entry protocol first** — read the mission state (`.mugiwara/state/<mission>/[member].json`). No active mission → run Flow 0 triage before anything else. Foreign mission → stop, report owner. Base drift → stop, ask. Non-git → degrade to standard, say so once.
|
|
7
|
-
2. Load the skills: `mugiwara-orchestration` + `mugiwara-ship`.
|
|
8
|
-
3. Run the ship gate: pre-launch checklist, feature flags, staged rollout, mandatory rollback plan — binary GO/NO-GO with evidence.
|
|
9
|
-
4. Bridge on `.mugiwara/plans/` (promise) vs `.mugiwara/results/` (evidence) for the Definition-of-Done verdict.
|
|
10
|
-
5. Close the mission: lessons ledger update, then the terminal step — save-point commit, push the branch, write the PR verdict, hand to the user.
|
|
11
|
-
6. **The crew never creates a PR, never merges, never deploys — hand the branch + verdict to the user.**
|
|
12
|
-
|
|
13
|
-
See skills/mugiwara-ship for the gate and skills/mugiwara-orchestration for closure.
|