harness-everything 0.15.0 → 0.16.1
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 +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/AGENTS.md +2 -2
- package/CHANGELOG.md +23 -0
- package/README.md +7 -7
- package/VERIFICATION.md +3 -3
- package/bin/cli.js +17 -0
- package/ci/invariant-routing.test.js +58 -158
- package/ci/mechanism-2a-rule-of-3.test.js +73 -138
- package/ci/mechanism-2ac-atomic-commit-check.test.js +2 -2
- package/ci/mechanism-2af-worktree-isolation.test.js +38 -196
- package/ci/mechanism-2ah-workflow-lifecycle.test.js +20 -831
- package/ci/mechanism-2ai-workspace-fingerprint-batch.test.js +3 -4
- package/ci/mechanism-2al-codex-hooks-compat.test.js +286 -0
- package/ci/mechanism-2b-boundary-guard.test.js +6 -16
- package/ci/mechanism-2e-scope-guard.test.js +8 -24
- package/ci/mechanism-2f-stop-gate.test.js +21 -75
- package/ci/mechanism-2n-opencode-plugin.test.js +13 -28
- package/ci/openai-plugin-package.test.js +8 -8
- package/ci/openai-plugin-runtime.test.js +2 -2
- package/ci/router-workflow-plan.test.js +6 -6
- package/ci/self-evolve-loop.test.js +4 -1
- package/ci/workflow-execution-contract.test.js +51 -129
- package/ci/workflow-plan-consumers-edge.test.js +1 -1
- package/ci/workflow-plan-consumers.test.js +6 -6
- package/docs/architecture.md +21 -21
- package/docs/enforcement-locks.md +41 -102
- package/docs/mechanism-first-skill-mesh.md +2 -2
- package/docs/philosophy.md +2 -2
- package/docs/platform-capabilities.md +19 -3
- package/docs/platform-compatibility.json +4 -4
- package/docs/routing.md +14 -14
- package/docs/workflow-runtime.md +80 -110
- package/evals/harness-everything/tasks/positive-tier1.yaml +1 -1
- package/evals/harness-everything/tasks/positive-tier2.yaml +1 -1
- package/evals/harness-everything/tasks/positive-tier3.yaml +1 -1
- package/evals/using-git-worktrees/tasks/positive-trigger.yaml +1 -1
- package/fable-mode/SKILL.md +1 -1
- package/fable-mode/execution-guardrails/SKILL.md +1 -1
- package/fable-mode/fable-haiku/SKILL.md +1 -1
- package/fable-mode/fable-opus/SKILL.md +1 -1
- package/fable-mode/fable-sonnet/SKILL.md +1 -1
- package/fable-mode/scripts/workflow-plan-consumer.js +4 -3
- package/harness-everything/SKILL.md +11 -11
- package/harness-everything/references/triage-and-tiers.md +11 -11
- package/harness-everything/scripts/kernel-router-core.js +5 -5
- package/harness-everything/scripts/kernel-router.js +15 -17
- package/harness-everything/scripts/router-contract-core.js +1 -1
- package/hooks/hooks.json +10 -23
- package/hooks/scripts/atomic-commit-check.js +1 -1
- package/hooks/scripts/boundary-guard.js +4 -4
- package/hooks/scripts/contract-test.js +8 -11
- package/hooks/scripts/depth-guard.js +2 -2
- package/hooks/scripts/lib/workflow-runtime.js +24 -402
- package/hooks/scripts/rule-of-3-tracker.js +28 -31
- package/hooks/scripts/rule-of-3.js +4 -28
- package/hooks/scripts/state-persist.js +36 -136
- package/hooks/scripts/stop-gate.js +15 -48
- package/hooks/scripts/subagent-scope-guard.js +8 -8
- package/hooks/scripts/workflow-disposition.js +2 -10
- package/hooks/scripts/workflow-gate.js +33 -84
- package/hooks/scripts/workflow-mutation-denied.js +3 -15
- package/hooks/scripts/workflow-stop-gate.js +23 -38
- package/opencode-plugin/README.md +9 -10
- package/opencode-plugin/index.mjs +14 -30
- package/opencode-plugin/plugin.json +1 -1
- package/package.json +4 -2
- package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
- package/plugins/harness-everything/hooks/hooks.json +3 -3
- package/plugins/harness-everything/hooks/scripts/atomic-commit-check.js +1 -1
- package/plugins/harness-everything/hooks/scripts/boundary-guard.js +4 -4
- package/plugins/harness-everything/hooks/scripts/contract-test.js +8 -11
- package/plugins/harness-everything/hooks/scripts/depth-guard.js +2 -2
- package/plugins/harness-everything/hooks/scripts/lib/workflow-runtime.js +24 -402
- package/plugins/harness-everything/hooks/scripts/rule-of-3-tracker.js +28 -31
- package/plugins/harness-everything/hooks/scripts/rule-of-3.js +4 -28
- package/plugins/harness-everything/hooks/scripts/state-persist.js +36 -136
- package/plugins/harness-everything/hooks/scripts/stop-gate.js +15 -48
- package/plugins/harness-everything/hooks/scripts/subagent-scope-guard.js +8 -8
- package/plugins/harness-everything/hooks/scripts/workflow-disposition.js +2 -10
- package/plugins/harness-everything/hooks/scripts/workflow-gate.js +33 -84
- package/plugins/harness-everything/hooks/scripts/workflow-mutation-denied.js +3 -15
- package/plugins/harness-everything/hooks/scripts/workflow-stop-gate.js +23 -38
- package/plugins/harness-everything/plugin.json +1 -1
- package/plugins/harness-everything/scripts/lib/advisory-text.js +16 -29
- package/plugins/harness-everything/skills/fable-mode/SKILL.md +1 -1
- package/plugins/harness-everything/skills/fable-mode/execution-guardrails/SKILL.md +1 -1
- package/plugins/harness-everything/skills/fable-mode/fable-haiku/SKILL.md +1 -1
- package/plugins/harness-everything/skills/fable-mode/fable-opus/SKILL.md +1 -1
- package/plugins/harness-everything/skills/fable-mode/fable-sonnet/SKILL.md +1 -1
- package/plugins/harness-everything/skills/fable-mode/scripts/workflow-plan-consumer.js +4 -3
- package/plugins/harness-everything/skills/harness-everything/SKILL.md +11 -11
- package/plugins/harness-everything/skills/harness-everything/references/triage-and-tiers.md +11 -11
- package/plugins/harness-everything/skills/harness-everything/scripts/kernel-router-core.js +5 -5
- package/plugins/harness-everything/skills/harness-everything/scripts/kernel-router.js +15 -17
- package/plugins/harness-everything/skills/harness-everything/scripts/router-contract-core.js +1 -1
- package/plugins/harness-everything/skills/using-git-worktrees/SKILL.md +5 -5
- package/scripts/codex-hooks-compat.js +521 -0
- package/scripts/lib/advisory-text.js +16 -29
- package/using-git-worktrees/SKILL.md +5 -5
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Harness uses tiers to estimate scope and select the smallest sufficient execution topology. A tier is **not** a fixed TODO/TDD/Fable pipeline. Once the router selects an applicable topology, however, that topology becomes the run's execution contract.
|
|
4
4
|
|
|
5
|
-
> Architecture rule: **
|
|
5
|
+
> Architecture rule: **Guidance-first workflow; flexible reasoning/implementation; only Rule-of-3 reflection and explicit permission boundaries may block.**
|
|
6
6
|
|
|
7
7
|
## 0. When Harness Routing Applies
|
|
8
8
|
|
|
@@ -43,7 +43,7 @@ The kernel protects lifecycle obligations without micromanaging model reasoning.
|
|
|
43
43
|
2. **Verify before claim** — completion requires objective evidence appropriate to the change.
|
|
44
44
|
3. **Re-plan on repetition** — after three same-signature failures, stop micro-retrying and use a fresh diagnosis / `zoom-out`.
|
|
45
45
|
4. **Evaluate before omission** — when the router suggests a skill, read its complete `SKILL.md` entry/basic flow before deciding applicability.
|
|
46
|
-
5. **
|
|
46
|
+
5. **Review selected workflow** — use the topology as planning guidance and keep any skipped step evidence-based.
|
|
47
47
|
|
|
48
48
|
The model remains free to choose tools, implementation technique, decomposition details, and reasoning inside the workflow.
|
|
49
49
|
|
|
@@ -54,7 +54,7 @@ The model remains free to choose tools, implementation technique, decomposition
|
|
|
54
54
|
- Every router-suggested skill when its evaluated flow is objectively not applicable.
|
|
55
55
|
- Every optional deep-dive/reference linked from a skill.
|
|
56
56
|
|
|
57
|
-
A suggested skill may resolve as `use`, `not-applicable`, or `unresolved/unavailable`. `not-applicable` needs a flow-grounded reason; a metadata-only or confidence-only judgement is insufficient. The selected **topology** is
|
|
57
|
+
A suggested skill may resolve as `use`, `not-applicable`, or `unresolved/unavailable`. `not-applicable` needs a flow-grounded reason; a metadata-only or confidence-only judgement is insufficient. The selected **topology** is planning guidance. Escape/replan metadata may still record why a suggested path was not followed, but it is not a lock.
|
|
58
58
|
|
|
59
59
|
## 2. Routing Mechanism
|
|
60
60
|
|
|
@@ -73,7 +73,7 @@ npx github:dyphn1/Harness-everything next "<brief prompt summary>"
|
|
|
73
73
|
- compact **Harness Routing Checkpoint**,
|
|
74
74
|
- required invariants,
|
|
75
75
|
- suggested skills whose applicability must be evaluated,
|
|
76
|
-
- **Workflow
|
|
76
|
+
- **Workflow Guidance** for the selected topology.
|
|
77
77
|
|
|
78
78
|
If `UserPromptSubmit` already ran the kernel this turn, reuse that output. Do not infer a silent Tier 1/direct path from missing or degraded routing.
|
|
79
79
|
|
|
@@ -90,12 +90,12 @@ A name, description, router summary, tier label, or generic "routine/common task
|
|
|
90
90
|
|
|
91
91
|
### Workflow escape contract
|
|
92
92
|
|
|
93
|
-
Escape is
|
|
93
|
+
Escape is audit metadata for a bounded guidance deviation. Use it only when the selected topology genuinely cannot represent part of the task. The permitted reason codes are:
|
|
94
94
|
|
|
95
95
|
- `workflow-uncovered-scope` — the selected topology cannot represent a bounded part of the task;
|
|
96
96
|
- `host-capability-unavailable` — the host lacks a capability required to execute the selected topology.
|
|
97
97
|
|
|
98
|
-
Every escape must name a declared stage in the correlated run and record the reason code, uncovered scope, and evidence explaining the coverage/capability gap.
|
|
98
|
+
Every escape must name a declared stage in the correlated run and record the reason code, uncovered scope, and evidence explaining the coverage/capability gap. Host capability loss and missing isolation should remain visible as warnings/evidence, without creating a persistent execution lock.
|
|
99
99
|
|
|
100
100
|
## 3. Tier Guidance
|
|
101
101
|
|
|
@@ -117,7 +117,7 @@ When an evaluated skill is applicable, follow its workflow rather than reading i
|
|
|
117
117
|
|
|
118
118
|
Typical shape: repository-wide/architectural work, large ambiguous requirements, cross-source synthesis, or bounded delegation.
|
|
119
119
|
|
|
120
|
-
The router may select `fable-staged`, `fable-parallel`, or `fable-multi-agent-workspace`. A selected Fable topology is
|
|
120
|
+
The router may select `fable-staged`, `fable-parallel`, or `fable-multi-agent-workspace`. A selected Fable topology is structured planning guidance: use its stages/dependencies/evidence when helpful, but do not convert missing lifecycle evidence into a persistent workflow lock.
|
|
121
121
|
|
|
122
122
|
Tier 3 does **not** automatically mean multi-agent; the router still chooses the smallest sufficient topology.
|
|
123
123
|
|
|
@@ -140,11 +140,11 @@ This describes a reasoning policy. The workflow contract governs lifecycle oblig
|
|
|
140
140
|
|
|
141
141
|
| Host mode | Expected behavior |
|
|
142
142
|
|---|---|
|
|
143
|
-
| Lifecycle hooks available | Kernel
|
|
144
|
-
| Advisory instructions only | Agent
|
|
143
|
+
| Lifecycle hooks available | Kernel records selected workflow guidance. PreToolUse/Stop hooks emit reminders; Rule-of-3 and permission gates are the intentional blocking exceptions. |
|
|
144
|
+
| Advisory instructions only | Agent receives the same routing/workflow guidance without lifecycle observations. |
|
|
145
145
|
| Manual use | Invoke `harness-everything` / `harness next`, then execute the selected topology explicitly. |
|
|
146
146
|
|
|
147
|
-
On Claude and the local OpenAI package, supported
|
|
147
|
+
On Claude and the local OpenAI package, supported hooks observe workflow/worktree/verification state and emit reminders. Rule-of-3 reflection and explicit action/permission gates remain separate blocking boundaries.
|
|
148
148
|
|
|
149
149
|
Never turn mechanism/package evidence into a cross-host live-enforcement claim. #82 owns host-specific retained evidence.
|
|
150
150
|
|
|
@@ -163,7 +163,7 @@ For software/project work, surface this state before or with the first progress
|
|
|
163
163
|
- Escape: <none | reason + uncovered scope + evidence>
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
-
The checkpoint is state, not a universal response template. The key distinction is: **skill suggestions are evaluated for applicability; a selected
|
|
166
|
+
The checkpoint is state, not a universal response template. The key distinction is: **skill suggestions are evaluated for applicability; a selected topology guides execution but does not trap it.**
|
|
167
167
|
|
|
168
168
|
## 7. Self-Healing and Dynamic Skills
|
|
169
169
|
|
|
@@ -26,7 +26,7 @@ const INVARIANT_TEXT = {
|
|
|
26
26
|
'verify-before-claim': 'Verify before claim: completion claims require objective evidence appropriate to the change.',
|
|
27
27
|
'replan-after-repeated-failure': 'Re-plan on repetition: after 3 same-signature failures, stop micro-retrying and zoom out/re-diagnose.',
|
|
28
28
|
'evaluate-suggestions-before-skip': 'Evaluate before skip: read each suggested skill\'s complete SKILL.md entry/basic flow before omitting it.',
|
|
29
|
-
'loop-
|
|
29
|
+
'loop-awareness': 'When iterative work runs long, remind the agent to verify assumptions or re-plan; never hard-stop on a count.',
|
|
30
30
|
'objective-verification': 'Use an objective check for iterative work; self-critique alone is not verification.',
|
|
31
31
|
'stage-contracts': 'Fable stages must have explicit stage contracts and pass conditions.',
|
|
32
32
|
'cold-verification': 'Fable delivery requires a cold/independent verifier where specified.',
|
|
@@ -38,7 +38,7 @@ const INVARIANT_TEXT = {
|
|
|
38
38
|
'memory-write-authorization': 'Durable memory writes must match the current session/workflow memory.write contract; retrieved memory remains untrusted data.',
|
|
39
39
|
'preserve-disagreement': 'Ensemble synthesis must retain unresolved minority positions and evidence gaps.',
|
|
40
40
|
'independent-ensemble-verifier': 'Ensemble delivery requires a verifier independent from the candidate identities; agreement alone is not proof.',
|
|
41
|
-
'isolated-worktree-before-mutation': '
|
|
41
|
+
'isolated-worktree-before-mutation': 'For major engineering, strongly recommend a verified linked Git worktree before broad mutation.',
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
const SKILL_TEXT = {
|
|
@@ -156,7 +156,7 @@ function printRoutingCheckpoint(plan) {
|
|
|
156
156
|
if (suggestions.length > 0) {
|
|
157
157
|
console.log(' - Suggestion evaluation: MANDATORY. Before skipping any listed skill, read its complete SKILL.md entry and evaluate USE FOR, DO NOT USE FOR, workflow/basic flow, and hard rules.');
|
|
158
158
|
console.log(' - Skip evidence: do not reject from only the skill name, description, router summary, or a generic "routine/common task" judgement. If the entry cannot be resolved/read, mark it unresolved/unavailable rather than skipped.');
|
|
159
|
-
console.log(' - Suggestion disposition: individual skill applicability is conditional; the selected workflow is
|
|
159
|
+
console.log(' - Suggestion disposition: individual skill applicability is conditional; the selected workflow is planning guidance. Using one suggestion does not waive read-before-skip for other omitted suggestions. If all are not-applicable, state one brief flow-grounded reason.');
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
|
|
@@ -166,7 +166,7 @@ function printKernelContract(plan) {
|
|
|
166
166
|
console.log(` - ${invariant}: ${INVARIANT_TEXT[invariant] || 'Required by the selected workflow plan.'}`);
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
console.log('\n=> WORKFLOW SKILLS (EVALUATE APPLICABILITY — SELECTED WORKFLOW IS
|
|
169
|
+
console.log('\n=> WORKFLOW SKILLS (EVALUATE APPLICABILITY — SELECTED WORKFLOW IS GUIDANCE):');
|
|
170
170
|
if (Array.isArray(plan.suggestedSkills) && plan.suggestedSkills.length > 0) {
|
|
171
171
|
const emitted = new Set();
|
|
172
172
|
for (const skill of plan.suggestedSkills) {
|
|
@@ -204,7 +204,7 @@ function printKernelContract(plan) {
|
|
|
204
204
|
console.log('\n=> ROUTING DEGRADATION: Structured routing is degraded. Keep the strategy deferred unless independent evidence supports a route; do not silently downgrade to Tier 1/direct execution.');
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
console.log('\n=> ORCHESTRATION POLICY:
|
|
207
|
+
console.log('\n=> ORCHESTRATION POLICY: Selected topology is planning guidance. Evaluate the suggested workflow and preserve objective evidence, but lifecycle hooks remind rather than hard-block. User/host permission boundaries and the Rule-of-3 zoom-out remain separate safety rails.');
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
function route(prompt, stdinPayload) {
|
|
@@ -58,9 +58,8 @@ function persistWorkflow(plan, payload, prompt) {
|
|
|
58
58
|
// Steering/status prompts cannot drop an unresolved execution contract.
|
|
59
59
|
// Stronger new work is retained as a pending route until explicit replan.
|
|
60
60
|
if (runtime.isMajorWorkflow(plan) && !runtime.isMajorWorkflow(context.workflow)) {
|
|
61
|
-
context.workflow.state = 'blocked';
|
|
62
61
|
context.workflow.pendingPlan = plan;
|
|
63
|
-
context.workflow.
|
|
62
|
+
context.workflow.planningWarning = 'stronger-route-suggested';
|
|
64
63
|
}
|
|
65
64
|
context.workflow.lastPromptHash = crypto.createHash('sha256').update(prompt).digest('hex').slice(0, 24);
|
|
66
65
|
const memoryCapability = issueMemoryCapability(context.workflow);
|
|
@@ -84,14 +83,15 @@ function persistWorkflow(plan, payload, prompt) {
|
|
|
84
83
|
verification: plan.verification,
|
|
85
84
|
mutationIsolation: plan.mutationIsolation || { required: false },
|
|
86
85
|
workflowPlan: plan,
|
|
87
|
-
state:
|
|
86
|
+
state: selected ? 'pending' : 'deferred',
|
|
87
|
+
planningWarnings: plan.fallback?.disposition === 'none' ? [] : [...(plan.fallback?.reasonCodes || [])],
|
|
88
88
|
runId: null,
|
|
89
89
|
revision: 0,
|
|
90
90
|
escapes: [],
|
|
91
|
-
|
|
92
|
-
mode: '
|
|
93
|
-
escapePolicy: 'scoped-evidence-only',
|
|
91
|
+
guidance: {
|
|
92
|
+
mode: 'advisory-workflow',
|
|
94
93
|
reasoningPolicy: 'model-controls-how',
|
|
94
|
+
hardBoundaries: ['rule-of-3-reflection', 'user-host-permission'],
|
|
95
95
|
},
|
|
96
96
|
};
|
|
97
97
|
const memoryCapability = issueMemoryCapability(context.workflow);
|
|
@@ -133,15 +133,15 @@ function run(raw) {
|
|
|
133
133
|
core.printWorkflowPlan(plan);
|
|
134
134
|
core.printRoutingCheckpoint(plan);
|
|
135
135
|
core.printKernelContract(plan);
|
|
136
|
-
console.log('\n=> WORKFLOW
|
|
136
|
+
console.log('\n=> WORKFLOW GUIDANCE (ADVISORY WHEN SELECTED):');
|
|
137
137
|
console.log(' - State: ' + (persisted?.workflow.state || (plan.strategy ? 'unpersisted' : 'deferred')));
|
|
138
138
|
console.log(' - Selected workflow: ' + (plan.strategy || 'deferred'));
|
|
139
139
|
if (plan.strategySelection === 'selected') {
|
|
140
|
-
console.log(' -
|
|
141
|
-
console.log(' -
|
|
142
|
-
console.log(' -
|
|
143
|
-
console.log(' - Tier 3 / Fable
|
|
144
|
-
console.log(' - Escape
|
|
140
|
+
console.log(' - Use the selected workflow as planning guidance; reasoning and implementation remain flexible.');
|
|
141
|
+
console.log(' - Before claiming completion, review unresolved workflow evidence and objective verification.');
|
|
142
|
+
console.log(' - If you skip a suggested step, keep the reason explicit and evidence-based.');
|
|
143
|
+
console.log(' - Tier 3 / Fable changes are safer in a linked Git worktree; missing isolation is a strong reminder, not a Harness lock.');
|
|
144
|
+
console.log(' - Escape/replan metadata remains useful for audit, but it does not create a persistent execution lock.');
|
|
145
145
|
}
|
|
146
146
|
if (persisted?.workflow) {
|
|
147
147
|
const controller = path.join(persisted.hooksRoot, 'workflow-disposition.js');
|
|
@@ -152,12 +152,10 @@ function run(raw) {
|
|
|
152
152
|
console.log(' - Enter/replan: node "' + controller + '" start --session-id "' + persisted.sessionId + '"');
|
|
153
153
|
console.log(' - Escape one declared stage: node "' + controller + '" escape --session-id "' + persisted.sessionId + '" --stage-id "<id>" --reason-code workflow-uncovered-scope --scope "<uncovered scope>" --evidence "<evidence>"');
|
|
154
154
|
} else {
|
|
155
|
-
console.log(' - Runtime state was not persisted;
|
|
155
|
+
console.log(' - Runtime state was not persisted; reminders may be less precise, but execution remains available.');
|
|
156
156
|
}
|
|
157
|
-
if (failure)
|
|
158
|
-
|
|
159
|
-
process.exitCode = 2;
|
|
160
|
-
} else if (result && result.status !== 0) process.exitCode = result.status || 1;
|
|
157
|
+
if (failure) console.error('[Workflow Reminder] routing state was not persisted: ' + failure.message);
|
|
158
|
+
if (result && result.status !== 0) console.error('[Workflow Reminder] router returned status ' + result.status + '; guidance is degraded, not blocking.');
|
|
161
159
|
}
|
|
162
160
|
|
|
163
161
|
if (typeof module !== 'undefined') module.exports = { isHostNotificationPrompt };
|
|
@@ -349,7 +349,7 @@ function planMetadataForStrategy(strategy) {
|
|
|
349
349
|
return {
|
|
350
350
|
...base,
|
|
351
351
|
patterns: ['router', 'react'],
|
|
352
|
-
requiredInvariants: [...base.requiredInvariants, 'loop-
|
|
352
|
+
requiredInvariants: [...base.requiredInvariants, 'loop-awareness', 'objective-verification'],
|
|
353
353
|
suggestedSkills: ['tdd', 'verification-loop'],
|
|
354
354
|
maxIterations: ITERATIVE_MAX_ITERATIONS,
|
|
355
355
|
parallelAllowed: false,
|
package/hooks/hooks.json
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/scripts/workflow-gate.js\""
|
|
35
35
|
}
|
|
36
36
|
],
|
|
37
|
-
"description": "
|
|
37
|
+
"description": "Emit advisory workflow/worktree reminders before mutation",
|
|
38
38
|
"id": "harness:pre:workflow-gate"
|
|
39
39
|
},
|
|
40
40
|
{
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"id": "harness:pre:action-gate"
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
|
-
"matcher": "Bash|PowerShell|Edit|Write",
|
|
52
|
+
"matcher": "Bash|PowerShell|Edit|Write|apply_patch",
|
|
53
53
|
"hooks": [
|
|
54
54
|
{
|
|
55
55
|
"type": "command",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/scripts/boundary-guard.js\""
|
|
68
68
|
}
|
|
69
69
|
],
|
|
70
|
-
"description": "
|
|
70
|
+
"description": "Warn about expensive broad searches and large file reads",
|
|
71
71
|
"id": "harness:pre:boundary-guard"
|
|
72
72
|
},
|
|
73
73
|
{
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/scripts/depth-guard.js\""
|
|
79
79
|
}
|
|
80
80
|
],
|
|
81
|
-
"description": "
|
|
81
|
+
"description": "Remind to inspect existing files before editing",
|
|
82
82
|
"id": "harness:pre:depth-guard"
|
|
83
83
|
},
|
|
84
84
|
{
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/scripts/workflow-stop-gate.js\""
|
|
134
134
|
}
|
|
135
135
|
],
|
|
136
|
-
"description": "
|
|
136
|
+
"description": "Remind when selected workflow evidence is incomplete",
|
|
137
137
|
"id": "harness:stop:workflow-completion-gate"
|
|
138
138
|
},
|
|
139
139
|
{
|
|
@@ -143,7 +143,7 @@
|
|
|
143
143
|
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/scripts/stop-gate.js\""
|
|
144
144
|
}
|
|
145
145
|
],
|
|
146
|
-
"description": "
|
|
146
|
+
"description": "Remind when edits have no observed successful verification",
|
|
147
147
|
"id": "harness:stop:stop-gate"
|
|
148
148
|
},
|
|
149
149
|
{
|
|
@@ -157,19 +157,6 @@
|
|
|
157
157
|
"id": "harness:stop:skill-telemetry"
|
|
158
158
|
}
|
|
159
159
|
],
|
|
160
|
-
"PermissionDenied": [
|
|
161
|
-
{
|
|
162
|
-
"matcher": "Bash|PowerShell",
|
|
163
|
-
"hooks": [
|
|
164
|
-
{
|
|
165
|
-
"type": "command",
|
|
166
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/scripts/workflow-mutation-denied.js\""
|
|
167
|
-
}
|
|
168
|
-
],
|
|
169
|
-
"description": "Release reserved mutation capacity when Claude auto mode denies a shell tool call",
|
|
170
|
-
"id": "harness:permission-denied:mutation-probe"
|
|
171
|
-
}
|
|
172
|
-
],
|
|
173
160
|
"PostToolUse": [
|
|
174
161
|
{
|
|
175
162
|
"matcher": "Bash|PowerShell|mcp__.*",
|
|
@@ -183,7 +170,7 @@
|
|
|
183
170
|
"id": "harness:post:action-gate-audit"
|
|
184
171
|
},
|
|
185
172
|
{
|
|
186
|
-
"matcher": "Bash|PowerShell",
|
|
173
|
+
"matcher": "Bash|PowerShell|apply_patch",
|
|
187
174
|
"hooks": [
|
|
188
175
|
{
|
|
189
176
|
"type": "command",
|
|
@@ -194,7 +181,7 @@
|
|
|
194
181
|
"id": "harness:post:rule-of-3-tracker"
|
|
195
182
|
},
|
|
196
183
|
{
|
|
197
|
-
"matcher": "Edit|Write|Bash|PowerShell",
|
|
184
|
+
"matcher": "Edit|Write|Bash|PowerShell|apply_patch",
|
|
198
185
|
"hooks": [
|
|
199
186
|
{
|
|
200
187
|
"type": "command",
|
|
@@ -262,7 +249,7 @@
|
|
|
262
249
|
"id": "harness:post-failure:action-gate-audit"
|
|
263
250
|
},
|
|
264
251
|
{
|
|
265
|
-
"matcher": "Bash|PowerShell",
|
|
252
|
+
"matcher": "Bash|PowerShell|apply_patch",
|
|
266
253
|
"hooks": [
|
|
267
254
|
{
|
|
268
255
|
"type": "command",
|
|
@@ -273,7 +260,7 @@
|
|
|
273
260
|
"id": "harness:post-failure:rule-of-3-tracker"
|
|
274
261
|
},
|
|
275
262
|
{
|
|
276
|
-
"matcher": "Bash|PowerShell",
|
|
263
|
+
"matcher": "Bash|PowerShell|apply_patch",
|
|
277
264
|
"hooks": [
|
|
278
265
|
{
|
|
279
266
|
"type": "command",
|
|
@@ -143,7 +143,7 @@ function main(payload) {
|
|
|
143
143
|
const changedFiles = statusRaw.split('\n').length;
|
|
144
144
|
console.error(`[Atomic Commit Check] ${state.editCount} edits since the last commit (${changedFiles} files currently changed).`);
|
|
145
145
|
console.error('If a logically complete chunk of work is done, commit it now before continuing - large uncommitted diffs are harder to review and harder to recover from.');
|
|
146
|
-
process.exit(
|
|
146
|
+
process.exit(0);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
process.exit(0);
|
|
@@ -25,10 +25,10 @@ process.stdin.on('end', () => {
|
|
|
25
25
|
if (filePath && !input.limit && fs.existsSync(filePath)) {
|
|
26
26
|
const stat = fs.statSync(filePath);
|
|
27
27
|
if (stat.isFile() && stat.size > MAX_BYTES_WITHOUT_LIMIT) {
|
|
28
|
-
console.error(`[Boundary
|
|
28
|
+
console.error(`[Boundary Reminder]: "${filePath}" is ${(stat.size / 1024).toFixed(0)}KB.`);
|
|
29
29
|
console.error(`Reading a file this large in one call risks context bloat and "lost in the middle" degradation.`);
|
|
30
30
|
console.error(`Re-issue the Read with an explicit "offset"/"limit" to pull a targeted slice, or use Grep to locate the relevant section first.`);
|
|
31
|
-
process.exit(
|
|
31
|
+
process.exit(0);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -41,10 +41,10 @@ process.stdin.on('end', () => {
|
|
|
41
41
|
return asPathSegment.test(searchPath) || asPathSegment.test(pattern);
|
|
42
42
|
});
|
|
43
43
|
if (hitsNoiseDir) {
|
|
44
|
-
console.error(`[Boundary
|
|
44
|
+
console.error(`[Boundary Reminder]: search targets a noise directory (${NOISE_DIRS.join(', ')}).`);
|
|
45
45
|
console.error(`These produce huge, low-signal result sets and rarely contain what you're actually looking for.`);
|
|
46
46
|
console.error(`Scope the search to source directories instead, or state explicitly why this directory must be searched.`);
|
|
47
|
-
process.exit(
|
|
47
|
+
process.exit(0);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -22,7 +22,7 @@ const {
|
|
|
22
22
|
listRunContracts,
|
|
23
23
|
getWorkerId,
|
|
24
24
|
} = require('./lib/fable-contracts');
|
|
25
|
-
const { loadWorkflow, matchingRun
|
|
25
|
+
const { loadWorkflow, matchingRun } = require('./lib/workflow-runtime');
|
|
26
26
|
const { createLearningOpportunity } = require('./lib/learning-opportunity');
|
|
27
27
|
|
|
28
28
|
function resultState(payload) {
|
|
@@ -119,7 +119,7 @@ process.stdin.on('end', () => {
|
|
|
119
119
|
if (resolution.ambiguous || !resolution.match) {
|
|
120
120
|
console.error(`[Contract Test] Ambiguous Fable check command matched ${runMatches.length} active run contract(s): ${command}`);
|
|
121
121
|
console.error('No contract was mutated. Correlate the worker/session to one run before accepting this check.');
|
|
122
|
-
process.exit(
|
|
122
|
+
process.exit(0);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
const entry = resolution.match;
|
|
@@ -127,14 +127,14 @@ process.stdin.on('end', () => {
|
|
|
127
127
|
const worker = getWorkerId(payload);
|
|
128
128
|
if (!worker || (entry.contract.workerId && worker !== entry.contract.workerId)) {
|
|
129
129
|
console.error('[Contract Test] Active workflow check lacks a matching observed worker identity.');
|
|
130
|
-
process.exit(
|
|
130
|
+
process.exit(0);
|
|
131
131
|
}
|
|
132
132
|
for (const id of entry.contract.dependsOn || []) {
|
|
133
133
|
const dependency = JSON.parse(fs.readFileSync(path.join(entry.runRoot, 'contracts', `${id}.json`), 'utf8'));
|
|
134
134
|
const escaped = workflowContext.workflow.escapes?.some(item => item.stageId === id && item.runId === entry.contract.runId);
|
|
135
135
|
if (dependency.status !== 'pass' && !escaped) {
|
|
136
136
|
console.error('[Contract Test] Dependency has not passed: ' + id);
|
|
137
|
-
process.exit(
|
|
137
|
+
process.exit(0);
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
}
|
|
@@ -164,12 +164,9 @@ process.stdin.on('end', () => {
|
|
|
164
164
|
}
|
|
165
165
|
console.log(`[Contract Test] ${contract.planId}/${contract.runId}/${contract.stageId}: ${contract.status.toUpperCase()} ${contract.checkCommand}`);
|
|
166
166
|
if (contract.status === 'fail') {
|
|
167
|
-
if (workflowContext.workflow?.workflowId) {
|
|
168
|
-
recordBudgetEvent(workflowContext, 'revision', { evidence: `${contract.stageId}:${contract.evidence || 'verification-failed'}` });
|
|
169
|
-
}
|
|
170
167
|
console.error(`Evidence: ${contract.evidence || '(no output captured)'}`);
|
|
171
|
-
console.error(`
|
|
172
|
-
process.exit(
|
|
168
|
+
console.error(`Review this failed stage before relying on its output. Artifact: ${contract.outputPath || '(no path recorded)'}`);
|
|
169
|
+
process.exit(0);
|
|
173
170
|
}
|
|
174
171
|
process.exit(0);
|
|
175
172
|
}
|
|
@@ -179,12 +176,12 @@ process.stdin.on('end', () => {
|
|
|
179
176
|
const legacy = resolveLegacyContract(stateRoot, command, payload);
|
|
180
177
|
if (legacy && legacy.ambiguous) {
|
|
181
178
|
console.error(`[Contract Test] Ambiguous legacy stage contracts matched: ${command}`);
|
|
182
|
-
process.exit(
|
|
179
|
+
process.exit(0);
|
|
183
180
|
}
|
|
184
181
|
if (legacy && legacy.failed) {
|
|
185
182
|
console.error(`[Contract Test] Legacy stage "${legacy.contract.stageId}" FAILED its named check: ${legacy.contract.checkCommand}`);
|
|
186
183
|
console.error(`Evidence: ${legacy.contract.evidence || '(no output captured)'}`);
|
|
187
|
-
process.exit(
|
|
184
|
+
process.exit(0);
|
|
188
185
|
}
|
|
189
186
|
process.exit(0);
|
|
190
187
|
} catch (_) {
|
|
@@ -52,10 +52,10 @@ process.stdin.on('end', () => {
|
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
if (!wasRead) {
|
|
55
|
-
console.error(`[Depth
|
|
55
|
+
console.error(`[Depth Reminder]: "${filePath}" already exists but hasn't been Read in this session.`);
|
|
56
56
|
console.error(`Write() overwrites the whole file - doing that blind risks destroying content you never looked at.`);
|
|
57
57
|
console.error(`Read the file first (even a quick pass), then retry the Write, or use Edit for a targeted change.`);
|
|
58
|
-
process.exit(
|
|
58
|
+
process.exit(0);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
process.exit(0);
|