harness-everything 0.30.5 → 0.30.6
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/CHANGELOG.md +23 -0
- package/ci/fable-mode-test.js +112 -51
- package/ci/mechanism-2t-workspace-identity.test.js +3 -1
- package/ci/mechanism-2z-claude-plugin-manifest.test.js +12 -0
- package/ci/router-workflow-plan.test.js +92 -7
- package/docs/platform-capabilities.md +8 -0
- package/docs/workflows/fable-mode.md +10 -9
- package/evals/fable-mode/tasks/negative-tier2-no-model.yaml +3 -3
- package/evals/fable-mode/tasks/positive-haiku-mode.yaml +1 -1
- package/evals/fable-mode/tasks/positive-opus-mode.yaml +1 -1
- package/evals/fable-mode/tasks/positive-sonnet-mode.yaml +1 -1
- package/evals/fable-mode/tasks/positive-trigger.yaml +1 -1
- package/fable-mode/SKILL.md +18 -12
- package/fable-mode/agents/fable-orchestrator.md +7 -6
- package/fable-mode/agents/fable-verifier.md +1 -1
- package/fable-mode/agents/fable-worker-haiku.md +5 -4
- package/fable-mode/agents/fable-worker-sonnet.md +5 -4
- package/fable-mode/behavior-profile-matrix.json +36 -0
- package/fable-mode/execution-guardrails/SKILL.md +3 -6
- package/fable-mode/execution-guardrails/references/guardrail-rules.md +8 -9
- package/fable-mode/fable-haiku/SKILL.md +7 -5
- package/fable-mode/fable-haiku/references/routing-notes.md +2 -1
- package/fable-mode/fable-opus/SKILL.md +8 -6
- package/fable-mode/fable-sonnet/SKILL.md +8 -6
- package/fable-mode/model-matrix.json +7 -30
- package/fable-mode/references/model-matrix.md +35 -30
- package/fable-mode/references/profile-lookup.md +19 -0
- package/fable-mode/runtime-model-floor-matrix.json +47 -0
- package/fable-mode/scripts/model-selector.js +106 -60
- package/fable-mode/scripts/workflow-plan-consumer.js +1 -1
- package/harness-everything/SKILL.md +1 -1
- package/harness-everything/references/router-workflow-plan.md +2 -2
- package/harness-everything/schemas/router-task-shape.schema.json +3 -2
- package/harness-everything/schemas/router-workflow-plan.schema.json +6 -5
- package/harness-everything/scripts/router-contract-core.js +19 -12
- package/harness-everything/scripts/tier-router.js +100 -12
- package/opencode-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
- package/plugins/harness-everything/plugin.json +1 -1
- package/plugins/harness-everything/skills/fable-mode/SKILL.md +18 -12
- package/plugins/harness-everything/skills/fable-mode/agents/fable-orchestrator.md +7 -6
- package/plugins/harness-everything/skills/fable-mode/agents/fable-verifier.md +1 -1
- package/plugins/harness-everything/skills/fable-mode/agents/fable-worker-haiku.md +5 -4
- package/plugins/harness-everything/skills/fable-mode/agents/fable-worker-sonnet.md +5 -4
- package/plugins/harness-everything/skills/fable-mode/behavior-profile-matrix.json +36 -0
- package/plugins/harness-everything/skills/fable-mode/execution-guardrails/SKILL.md +3 -6
- package/plugins/harness-everything/skills/fable-mode/execution-guardrails/references/guardrail-rules.md +8 -9
- package/plugins/harness-everything/skills/fable-mode/fable-haiku/SKILL.md +7 -5
- package/plugins/harness-everything/skills/fable-mode/fable-haiku/references/routing-notes.md +2 -1
- package/plugins/harness-everything/skills/fable-mode/fable-opus/SKILL.md +8 -6
- package/plugins/harness-everything/skills/fable-mode/fable-sonnet/SKILL.md +8 -6
- package/plugins/harness-everything/skills/fable-mode/model-matrix.json +7 -30
- package/plugins/harness-everything/skills/fable-mode/references/model-matrix.md +35 -30
- package/plugins/harness-everything/skills/fable-mode/references/profile-lookup.md +19 -0
- package/plugins/harness-everything/skills/fable-mode/runtime-model-floor-matrix.json +47 -0
- package/plugins/harness-everything/skills/fable-mode/scripts/model-selector.js +106 -60
- package/plugins/harness-everything/skills/fable-mode/scripts/workflow-plan-consumer.js +1 -1
- package/plugins/harness-everything/skills/harness-everything/SKILL.md +1 -1
- package/plugins/harness-everything/skills/harness-everything/references/router-workflow-plan.md +2 -2
- package/plugins/harness-everything/skills/harness-everything/schemas/router-task-shape.schema.json +3 -2
- package/plugins/harness-everything/skills/harness-everything/schemas/router-workflow-plan.schema.json +6 -5
- package/plugins/harness-everything/skills/harness-everything/scripts/router-contract-core.js +19 -12
- package/plugins/harness-everything/skills/harness-everything/scripts/tier-router.js +100 -12
- package/sbom.cdx.json +7 -7
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"name": "harness-everything",
|
|
11
11
|
"source": "./",
|
|
12
12
|
"description": "Harness OS: an orchestrated agent operating system — tier routing, circuit breaker guardrails, verification gates, WAL session memory, and self-evolving workspace rules.",
|
|
13
|
-
"version": "0.30.
|
|
13
|
+
"version": "0.30.6",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "Miya Daniel"
|
|
16
16
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "harness-everything",
|
|
3
3
|
"description": "Harness OS: an orchestrated agent operating system — tier routing, circuit breaker guardrails, verification gates, WAL session memory, and self-evolving workspace rules.",
|
|
4
|
-
"version": "0.30.
|
|
4
|
+
"version": "0.30.6",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Miya Daniel"
|
|
7
7
|
},
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.30.6](https://github.com/dyphn1/Harness-everything/compare/v0.30.5...v0.30.6) (2026-10-06)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
* **fable-mode:** align Claude nested skill contract ([aadfe34](https://github.com/dyphn1/Harness-everything/commit/aadfe349e6f9a6ce9623f9b408ad8c6d9958208e))
|
|
10
|
+
* **fable-mode:** compress guardrail reference contract ([302efcd](https://github.com/dyphn1/Harness-everything/commit/302efcd0433c75be10619dbad7aa2b925b57400f))
|
|
11
|
+
* **fable-mode:** preserve unknown audit states and raw aliases ([2716be9](https://github.com/dyphn1/Harness-everything/commit/2716be9feb3e6b986c0f5da884ed4a686b95791b))
|
|
12
|
+
* **fable-mode:** remove residual model-gated routing ([32fee42](https://github.com/dyphn1/Harness-everything/commit/32fee423e9af7416172bf146cb876f72d61e331e))
|
|
13
|
+
* **fable-mode:** stay within skill token budget ([d934d36](https://github.com/dyphn1/Harness-everything/commit/d934d36cef17d5e0b30dfffd888cdab5d7c9a747))
|
|
14
|
+
* **fable:** accept curly-quoted lookups and restore execution deep dive ([08517e4](https://github.com/dyphn1/Harness-everything/commit/08517e4469bab46042358df136446e2495144a7f)), closes [#290](https://github.com/dyphn1/Harness-everything/issues/290)
|
|
15
|
+
* **fable:** dispatch profile lookups before loading stage references ([58ce883](https://github.com/dyphn1/Harness-everything/commit/58ce8834d3fa0ab288f9106f26758d4945ca49b6)), closes [#290](https://github.com/dyphn1/Harness-everything/issues/290)
|
|
16
|
+
* **router:** preserve Fable profile alias across normalization ([50e84da](https://github.com/dyphn1/Harness-everything/commit/50e84da3f14216800e4c757996663debfb7a8f7a))
|
|
17
|
+
* **router:** scope fable lookup negations to their own list ([032b52b](https://github.com/dyphn1/Harness-everything/commit/032b52bba809237c4b891e44fc7ee7b082262ddb)), closes [#290](https://github.com/dyphn1/Harness-everything/issues/290)
|
|
18
|
+
* **router:** select bounded Fable profile lookups before staged topology ([0d6fdac](https://github.com/dyphn1/Harness-everything/commit/0d6fdac675a9225f9425fcb699444992032371a3)), closes [#290](https://github.com/dyphn1/Harness-everything/issues/290)
|
|
19
|
+
|
|
20
|
+
## [Unreleased]
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Select a bounded Fable profile lookup before loading staged workflow references; preserve execution topology and required obligations (#290).
|
|
25
|
+
- Validate entire Fable lookup clauses so same-clause execution keeps its obligations, while canonical JSON field lists remain bounded lookups (#294).
|
|
26
|
+
- Scope lookup negations to their own noun list so an un-negated action after a negation keeps execution routing (#294).
|
|
27
|
+
|
|
5
28
|
## [0.30.5](https://github.com/dyphn1/Harness-everything/compare/v0.30.4...v0.30.5) (2026-10-06)
|
|
6
29
|
|
|
7
30
|
### Bug Fixes
|
package/ci/fable-mode-test.js
CHANGED
|
@@ -5,6 +5,7 @@ const fs = require('fs');
|
|
|
5
5
|
const os = require('os');
|
|
6
6
|
const { spawnSync } = require('child_process');
|
|
7
7
|
const path = require('path');
|
|
8
|
+
const { evaluateRuntimeFloor } = require('../fable-mode/scripts/model-selector.js');
|
|
8
9
|
|
|
9
10
|
const root = path.resolve(__dirname, '..');
|
|
10
11
|
const selector = path.join(root, 'fable-mode', 'scripts', 'model-selector.js');
|
|
@@ -13,19 +14,17 @@ const auditDir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-fable-mode-'));
|
|
|
13
14
|
const auditFile = path.join(auditDir, 'audit.jsonl');
|
|
14
15
|
|
|
15
16
|
function runNode(file, args) {
|
|
16
|
-
return spawnSync(process.execPath, [file, ...args], {
|
|
17
|
-
cwd: root,
|
|
18
|
-
encoding: 'utf8'
|
|
19
|
-
});
|
|
17
|
+
return spawnSync(process.execPath, [file, ...args], { cwd: root, encoding: 'utf8' });
|
|
20
18
|
}
|
|
21
19
|
|
|
22
20
|
function selectorArgs(overrides = {}) {
|
|
23
21
|
const input = {
|
|
24
22
|
requested: 'opus',
|
|
25
|
-
available: 'opus,sonnet,haiku',
|
|
26
23
|
'available-agents': 'fable-orchestrator,fable-worker-sonnet,fable-worker-haiku',
|
|
27
24
|
fallback: 'stop',
|
|
28
|
-
|
|
25
|
+
host: 'codex',
|
|
26
|
+
'runtime-model': 'gpt-6.1-sol',
|
|
27
|
+
'runtime-effort': 'xhigh',
|
|
29
28
|
'audit-file': auditFile,
|
|
30
29
|
'stage-brief': 'Choose the architecture',
|
|
31
30
|
'pass-condition': 'ADR exists and names the decision',
|
|
@@ -33,104 +32,166 @@ function selectorArgs(overrides = {}) {
|
|
|
33
32
|
'verifier-result': 'pending',
|
|
34
33
|
...overrides
|
|
35
34
|
};
|
|
36
|
-
return Object.entries(input).flatMap(([key, value]) => [
|
|
35
|
+
return Object.entries(input).flatMap(([key, value]) => ['--' + key, String(value)]);
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
function readRecord(result) {
|
|
40
|
-
assert.ok(result.stdout.trim(),
|
|
39
|
+
assert.ok(result.stdout.trim(), 'selector produced no JSON: ' + result.stderr);
|
|
41
40
|
return JSON.parse(result.stdout);
|
|
42
41
|
}
|
|
43
42
|
|
|
44
|
-
console.log('=== Fable
|
|
43
|
+
console.log('=== Fable behavior profile + runtime floor contract tests ===');
|
|
44
|
+
|
|
45
|
+
const publicDescription = 'Stage large tasks through plans, named fable agents, failable checks, and skeptical review; fable on opus|sonnet|haiku selects a behavior profile, not a runtime model.';
|
|
46
|
+
const fableSkillText = fs.readFileSync(path.join(root, 'fable-mode', 'SKILL.md'), 'utf8');
|
|
47
|
+
assert.ok(fableSkillText.includes('description: "' + publicDescription + '"'));
|
|
48
|
+
|
|
49
|
+
for (const task of ['positive-opus-mode.yaml', 'positive-sonnet-mode.yaml', 'positive-haiku-mode.yaml', 'positive-trigger.yaml']) {
|
|
50
|
+
const source = fs.readFileSync(path.join(root, 'evals', 'fable-mode', 'tasks', task), 'utf8');
|
|
51
|
+
assert.ok(source.includes('description: "' + publicDescription + '"'), task + ' must keep the exact public fable-mode description');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const behavior = JSON.parse(fs.readFileSync(path.join(root, 'fable-mode', 'behavior-profile-matrix.json'), 'utf8'));
|
|
55
|
+
assert.strictEqual(behavior.profiles.orchestrator.legacyAlias, 'opus');
|
|
56
|
+
assert.ok(behavior.profiles.reasoning.aliases.includes('sonnect'));
|
|
57
|
+
|
|
58
|
+
const floors = JSON.parse(fs.readFileSync(path.join(root, 'fable-mode', 'runtime-model-floor-matrix.json'), 'utf8'));
|
|
59
|
+
assert.strictEqual(floors.hosts.claude.orchestrator.minVersion, '5.5');
|
|
60
|
+
assert.strictEqual(floors.hosts.claude.orchestrator.minEffort, 'medium');
|
|
61
|
+
assert.strictEqual(floors.hosts.claude.reasoning.minVersion, '5.5');
|
|
62
|
+
assert.strictEqual(floors.hosts.claude.mechanical.minVersion, '5.5');
|
|
63
|
+
assert.strictEqual(floors.hosts.codex.orchestrator.minGeneration, 6);
|
|
64
|
+
assert.strictEqual(floors.hosts.codex.orchestrator.minEffort, 'xhigh');
|
|
65
|
+
assert.strictEqual(floors.hosts.codex.reasoning.minEffort, 'medium');
|
|
66
|
+
assert.strictEqual(floors.hosts.codex.mechanical.family, 'luna');
|
|
67
|
+
assert.strictEqual(floors.hosts.codex.mechanical.minEffort, 'xhigh');
|
|
68
|
+
|
|
69
|
+
for (const profile of ['fable-opus', 'fable-sonnet', 'fable-haiku']) {
|
|
70
|
+
const source = fs.readFileSync(path.join(root, 'fable-mode', profile, 'SKILL.md'), 'utf8');
|
|
71
|
+
assert.match(source, /Reference profile, not a standalone plugin skill/);
|
|
72
|
+
}
|
|
73
|
+
for (const agent of ['fable-orchestrator.md', 'fable-worker-sonnet.md', 'fable-worker-haiku.md', 'fable-verifier.md']) {
|
|
74
|
+
const source = fs.readFileSync(path.join(root, 'fable-mode', 'agents', agent), 'utf8');
|
|
75
|
+
assert.match(source, /^model: inherit$/m, agent + ' must not pin a branded runtime model');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const guardrailSource = fs.readFileSync(path.join(root, 'fable-mode', 'execution-guardrails', 'SKILL.md'), 'utf8');
|
|
79
|
+
assert.match(guardrailSource, /reference-only, not an always-on carrier/);
|
|
80
|
+
assert.doesNotMatch(guardrailSource, /These rules are always-on/);
|
|
45
81
|
|
|
46
82
|
const selected = runNode(selector, selectorArgs());
|
|
47
83
|
assert.strictEqual(selected.status, 0, selected.stderr);
|
|
48
84
|
const selectedRecord = readRecord(selected);
|
|
49
85
|
assert.strictEqual(selectedRecord.status, 'selected');
|
|
50
|
-
assert.strictEqual(selectedRecord.
|
|
51
|
-
assert.strictEqual(selectedRecord.
|
|
52
|
-
assert.strictEqual(selectedRecord.
|
|
86
|
+
assert.strictEqual(selectedRecord.requestedProfile, 'orchestrator');
|
|
87
|
+
assert.strictEqual(selectedRecord.effectiveProfile, 'orchestrator');
|
|
88
|
+
assert.strictEqual(selectedRecord.profileAlias, 'opus');
|
|
53
89
|
assert.strictEqual(selectedRecord.agent, 'fable-orchestrator');
|
|
90
|
+
assert.strictEqual(selectedRecord.runtimeFloorStatus, 'meets-recommended');
|
|
54
91
|
|
|
55
|
-
const sonnect = runNode(selector, selectorArgs({
|
|
92
|
+
const sonnect = runNode(selector, selectorArgs({
|
|
93
|
+
requested: 'sonnect',
|
|
94
|
+
host: 'claude',
|
|
95
|
+
'runtime-model': 'claude-sonnet-5.5',
|
|
96
|
+
'runtime-effort': 'medium'
|
|
97
|
+
}));
|
|
56
98
|
assert.strictEqual(sonnect.status, 0, sonnect.stderr);
|
|
57
99
|
const sonnectRecord = readRecord(sonnect);
|
|
58
|
-
assert.strictEqual(sonnectRecord.
|
|
59
|
-
assert.strictEqual(sonnectRecord.
|
|
100
|
+
assert.strictEqual(sonnectRecord.requestedProfile, 'reasoning');
|
|
101
|
+
assert.strictEqual(sonnectRecord.profileAlias, 'sonnect');
|
|
102
|
+
assert.strictEqual(sonnectRecord.runtimeFloorStatus, 'meets-recommended');
|
|
60
103
|
|
|
61
|
-
const
|
|
104
|
+
const belowFloor = runNode(selector, selectorArgs({
|
|
62
105
|
requested: 'opus',
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
'
|
|
106
|
+
host: 'codex',
|
|
107
|
+
'runtime-model': 'gpt-6-sol',
|
|
108
|
+
'runtime-effort': 'medium'
|
|
109
|
+
}));
|
|
110
|
+
assert.strictEqual(belowFloor.status, 0, belowFloor.stderr);
|
|
111
|
+
const belowFloorRecord = readRecord(belowFloor);
|
|
112
|
+
assert.strictEqual(belowFloorRecord.status, 'selected');
|
|
113
|
+
assert.strictEqual(belowFloorRecord.effectiveProfile, 'orchestrator');
|
|
114
|
+
assert.strictEqual(belowFloorRecord.runtimeFloorStatus, 'below-recommended');
|
|
115
|
+
assert.strictEqual(belowFloorRecord.escalationRequired, false);
|
|
116
|
+
|
|
117
|
+
const unknownFamily = evaluateRuntimeFloor('reasoning', {
|
|
118
|
+
host: 'codex',
|
|
119
|
+
runtimeModel: 'vendor-private-model',
|
|
120
|
+
runtimeEffort: 'xhigh'
|
|
121
|
+
});
|
|
122
|
+
assert.strictEqual(unknownFamily.status, 'unknown');
|
|
123
|
+
assert.match(unknownFamily.reason, /not comparable/);
|
|
124
|
+
|
|
125
|
+
const unknownEffort = evaluateRuntimeFloor('reasoning', {
|
|
126
|
+
host: 'codex',
|
|
127
|
+
runtimeModel: 'gpt-6.1-sol',
|
|
128
|
+
runtimeEffort: 'custom-effort'
|
|
129
|
+
});
|
|
130
|
+
assert.strictEqual(unknownEffort.status, 'unknown');
|
|
131
|
+
assert.match(unknownEffort.reason, /not comparable/);
|
|
132
|
+
|
|
133
|
+
const inline = runNode(selector, selectorArgs({
|
|
134
|
+
requested: 'sonnet',
|
|
135
|
+
'available-agents': 'fable-worker-haiku',
|
|
136
|
+
fallback: 'inline'
|
|
66
137
|
}));
|
|
67
138
|
assert.strictEqual(inline.status, 0, inline.stderr);
|
|
68
139
|
const inlineRecord = readRecord(inline);
|
|
69
140
|
assert.strictEqual(inlineRecord.status, 'fallback');
|
|
70
|
-
assert.strictEqual(inlineRecord.
|
|
71
|
-
assert.match(inlineRecord.fallbackReason, /
|
|
72
|
-
assert.strictEqual(inlineRecord.escalationRequired, false);
|
|
141
|
+
assert.strictEqual(inlineRecord.effectiveProfile, 'reasoning');
|
|
142
|
+
assert.match(inlineRecord.fallbackReason, /execute the same reasoning behavior profile inline/);
|
|
73
143
|
|
|
74
|
-
const blocked = runNode(selector, selectorArgs({
|
|
144
|
+
const blocked = runNode(selector, selectorArgs({
|
|
145
|
+
requested: 'sonnet',
|
|
146
|
+
'available-agents': 'fable-worker-haiku',
|
|
147
|
+
fallback: 'stop'
|
|
148
|
+
}));
|
|
75
149
|
assert.strictEqual(blocked.status, 2);
|
|
76
150
|
const blockedRecord = readRecord(blocked);
|
|
77
151
|
assert.strictEqual(blockedRecord.status, 'blocked');
|
|
78
|
-
assert.strictEqual(blockedRecord.
|
|
152
|
+
assert.strictEqual(blockedRecord.effectiveProfile, null);
|
|
79
153
|
assert.strictEqual(blockedRecord.escalationRequired, true);
|
|
80
154
|
assert.match(blockedRecord.fallbackReason, /inline fallback was not authorized/);
|
|
81
155
|
|
|
82
|
-
const missingAgent = runNode(selector, selectorArgs({
|
|
83
|
-
requested: 'sonnet',
|
|
84
|
-
available: 'sonnet',
|
|
85
|
-
'available-agents': 'fable-worker-haiku',
|
|
86
|
-
fallback: 'inline',
|
|
87
|
-
'host-model': 'opus'
|
|
88
|
-
}));
|
|
89
|
-
assert.strictEqual(missingAgent.status, 0, missingAgent.stderr);
|
|
90
|
-
const missingAgentRecord = readRecord(missingAgent);
|
|
91
|
-
assert.strictEqual(missingAgentRecord.status, 'fallback');
|
|
92
|
-
assert.strictEqual(missingAgentRecord.effectiveModel, 'opus');
|
|
93
|
-
assert.match(missingAgentRecord.fallbackReason, /fable-worker-sonnet is not in availableAgents/);
|
|
94
|
-
|
|
95
156
|
const missingField = runNode(selector, selectorArgs({ 'pass-condition': '' }));
|
|
96
157
|
assert.strictEqual(missingField.status, 2);
|
|
97
158
|
assert.match(missingField.stderr, /passCondition is required/);
|
|
98
159
|
|
|
99
160
|
const explicitRoute = runNode(router, ['fable on sonnect for architecture synthesis']);
|
|
100
161
|
assert.strictEqual(explicitRoute.status, 0);
|
|
101
|
-
assert.match(explicitRoute.stdout, /REQUESTED FABLE
|
|
102
|
-
assert.match(explicitRoute.stdout,
|
|
162
|
+
assert.match(explicitRoute.stdout, /REQUESTED FABLE PROFILE: sonnect/);
|
|
163
|
+
assert.match(explicitRoute.stdout, /=> ROUTE: fable-mode\/SKILL\.md/);
|
|
164
|
+
assert.doesNotMatch(explicitRoute.stdout, /REQUESTED FABLE MODEL MODE/);
|
|
165
|
+
assert.doesNotMatch(explicitRoute.stdout, /=> ROUTE: fable-mode\/fable-sonnet\/SKILL\.md/);
|
|
103
166
|
|
|
104
167
|
const ordinaryTier2 = runNode(router, ['Fix this checkout bug and add a regression test.']);
|
|
105
168
|
assert.strictEqual(ordinaryTier2.status, 0);
|
|
106
169
|
assert.match(ordinaryTier2.stdout, /RECOMMENDED TIER: Tier 2/);
|
|
107
|
-
assert.doesNotMatch(ordinaryTier2.stdout, /REQUESTED FABLE
|
|
108
|
-
assert.doesNotMatch(ordinaryTier2.stdout, /fable-opus\/SKILL\.md/);
|
|
170
|
+
assert.doesNotMatch(ordinaryTier2.stdout, /REQUESTED FABLE PROFILE/);
|
|
109
171
|
|
|
110
172
|
const warningBatchContract = '**Warning batching.** Collect minor concerns and list them together in the next natural report or handoff; their count alone MUST NOT stop, pause, or return the worker/stage. An independently material, confirmed concern may stop the current stage and be surfaced immediately.';
|
|
111
173
|
for (const rel of [
|
|
112
174
|
'fable-mode/agents/fable-worker-haiku.md',
|
|
113
175
|
'fable-mode/agents/fable-worker-sonnet.md',
|
|
114
176
|
'fable-mode/agents/fable-orchestrator.md',
|
|
115
|
-
'fable-mode/execution-guardrails/SKILL.md'
|
|
177
|
+
'fable-mode/execution-guardrails/SKILL.md'
|
|
116
178
|
]) {
|
|
117
179
|
const prompt = fs.readFileSync(path.join(root, rel), 'utf8').replace(/\s+/g, ' ');
|
|
118
|
-
assert.ok(prompt.includes(warningBatchContract),
|
|
119
|
-
assert.doesNotMatch(
|
|
120
|
-
prompt,
|
|
121
|
-
/minor concerns.{0,200}stop and surface all at once before continuing/i,
|
|
122
|
-
`${rel} must not introduce a warning-count stop condition`
|
|
123
|
-
);
|
|
180
|
+
assert.ok(prompt.includes(warningBatchContract), rel + ' must keep minor-concern batching reporting-only');
|
|
124
181
|
}
|
|
125
182
|
|
|
126
183
|
const auditLines = fs.readFileSync(auditFile, 'utf8').trim().split(/\r?\n/).filter(Boolean);
|
|
127
184
|
assert.strictEqual(auditLines.length, 5);
|
|
128
185
|
for (const line of auditLines) {
|
|
129
186
|
const record = JSON.parse(line);
|
|
130
|
-
for (const field of [
|
|
131
|
-
|
|
187
|
+
for (const field of [
|
|
188
|
+
'requestedProfile', 'effectiveProfile', 'profileAlias', 'runtimeModel', 'runtimeEffort',
|
|
189
|
+
'recommendedRuntimeFloor', 'runtimeFloorStatus', 'runtimeFloorReason', 'fallbackReason',
|
|
190
|
+
'stageBrief', 'passCondition', 'verificationCommand', 'verifierResult'
|
|
191
|
+
]) {
|
|
192
|
+
assert.ok(Object.prototype.hasOwnProperty.call(record, field), 'audit missing ' + field);
|
|
132
193
|
}
|
|
133
194
|
}
|
|
134
195
|
fs.rmSync(auditDir, { recursive: true, force: true });
|
|
135
196
|
|
|
136
|
-
console.log('PASS:
|
|
197
|
+
console.log('PASS: profiles are behavior contracts; runtime floors are advisory; agent fallback remains explicit');
|
|
@@ -131,7 +131,9 @@ check('hooks can resolve state from a bound session after cwd changes', result.s
|
|
|
131
131
|
const installed = path.join(fixture, 'installed', 'fable-mode', 'scripts');
|
|
132
132
|
fs.mkdirSync(installed, { recursive: true });
|
|
133
133
|
fs.copyFileSync(path.join(root, 'fable-mode', 'scripts', 'model-selector.js'), path.join(installed, 'model-selector.js'));
|
|
134
|
-
|
|
134
|
+
for (const matrix of ['behavior-profile-matrix.json', 'runtime-model-floor-matrix.json']) {
|
|
135
|
+
fs.copyFileSync(path.join(root, 'fable-mode', matrix), path.join(installed, '..', matrix));
|
|
136
|
+
}
|
|
135
137
|
const fable = path.join(installed, 'model-selector.js');
|
|
136
138
|
const fableArgs = ['--requested', 'haiku', '--available', 'haiku', '--available-agents', 'fable-worker-haiku', '--stage-brief', 'identity', '--pass-condition', 'audit', '--verification-command', 'node test', '--verifier-result', 'pass', '--session-id', 'issue-42-fable-session'];
|
|
137
139
|
result = spawnSync(process.execPath, [fable, ...fableArgs], { cwd: outer, env: baseEnv, encoding: 'utf8' });
|
|
@@ -81,6 +81,18 @@ if (manifestHooks !== undefined) {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
assert.ok(Array.isArray(manifest.skills) && manifest.skills.length > 0, 'Claude plugin must declare packaged skills');
|
|
84
|
+
assert.ok(manifest.skills.includes('./fable-mode'), 'Claude plugin must expose fable-mode as the public Fable entrypoint');
|
|
85
|
+
for (const nestedRef of [
|
|
86
|
+
'./fable-mode/fable-opus',
|
|
87
|
+
'./fable-mode/fable-sonnet',
|
|
88
|
+
'./fable-mode/fable-haiku',
|
|
89
|
+
'./fable-mode/execution-guardrails',
|
|
90
|
+
]) {
|
|
91
|
+
assert.ok(
|
|
92
|
+
!manifest.skills.includes(nestedRef),
|
|
93
|
+
`${nestedRef} is a nested reference contract, not an independently routable Claude skill`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
84
96
|
for (const skillRef of manifest.skills) {
|
|
85
97
|
const skillDir = resolvePluginPath(skillRef, `skill ${skillRef}`);
|
|
86
98
|
assert.ok(fs.statSync(skillDir).isDirectory(), `skill path must be a directory: ${skillRef}`);
|
|
@@ -202,10 +202,95 @@ if (validContract(fableTypo, 'fable keyword trivial edit')) {
|
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
const explicitFable = runTier('fable on opus audit the entire repository architecture');
|
|
205
|
-
if (validContract(explicitFable, 'explicit Fable
|
|
205
|
+
if (validContract(explicitFable, 'explicit Fable profile')) {
|
|
206
206
|
check(explicitFable.contract.workflowPlan.strategy === 'fable-staged', 'explicit Fable request selects Fable topology');
|
|
207
|
-
check(explicitFable.contract.workflowPlan.
|
|
208
|
-
check(explicitFable.
|
|
207
|
+
check(explicitFable.contract.workflowPlan.profileSelection.requested === 'orchestrator', 'legacy opus alias normalizes to orchestrator profile');
|
|
208
|
+
check(explicitFable.contract.workflowPlan.profileSelection.alias === 'opus', 'legacy alias remains auditable');
|
|
209
|
+
check(explicitFable.result.stdout.includes('REQUESTED FABLE PROFILE: opus'), 'explicit Fable profile remains visible');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const explicitSonnect = runTier('fable on sonnect for architecture synthesis');
|
|
213
|
+
if (validContract(explicitSonnect, 'explicit Fable sonnect alias')) {
|
|
214
|
+
check(explicitSonnect.contract.workflowPlan.profileSelection.requested === 'reasoning', 'sonnect normalizes to reasoning profile');
|
|
215
|
+
check(explicitSonnect.contract.workflowPlan.profileSelection.alias === 'sonnect', 'raw sonnect alias remains auditable end-to-end');
|
|
216
|
+
check(explicitSonnect.result.stdout.includes('REQUESTED FABLE PROFILE: sonnect'), 'router output preserves raw sonnect alias');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// #290: mentioning a profile in a bounded lookup must not launch orchestration.
|
|
220
|
+
for (const prompt of [
|
|
221
|
+
"Explain what 'fable on sonnect' means; return only a small JSON selection record.",
|
|
222
|
+
"Resolve fable on haiku into a profile JSON record; no orchestration or delegation.",
|
|
223
|
+
"解釋 fable on opus 的意思,只回傳 JSON。",
|
|
224
|
+
"Explain what 'run fable on sonnect' means; return only JSON.",
|
|
225
|
+
'Explain fable on sonnet; return JSON with requestedProfile, effectiveProfile.',
|
|
226
|
+
"Explain what 'fable on sonnect' means; return only a small JSON selection record with requestedProfile, effectiveProfile, profileAlias, assignedRole, runtimeModel, runtimeEffort. No orchestration or delegation.",
|
|
227
|
+
'Explain fable on haiku; output JSON with `requestedProfile`, `runtimeModel` and `runtimeEffort`.',
|
|
228
|
+
'解釋 fable on opus 的意思,只回傳 JSON,包含 requestedProfile、effectiveProfile、runtimeEffort。',
|
|
229
|
+
"Explain what 'use fable on opus' means; no execution or model switching.",
|
|
230
|
+
'Explain fable on sonnet; return JSON; no stages, delegation or execution.',
|
|
231
|
+
'請說明 fable on sonnet 的意思,並只回傳含 requestedProfile 的 JSON。',
|
|
232
|
+
'Explain fable on sonnet, please return JSON.',
|
|
233
|
+
'Explain fable on sonnet and please return only JSON.',
|
|
234
|
+
'請說明 fable on sonnet,請只回傳 JSON。',
|
|
235
|
+
'Explain what “run fable on sonnect” means; return only JSON.',
|
|
236
|
+
'Explain what ‘use fable on opus’ means.',
|
|
237
|
+
'Explain fable on sonnet; no model switching.',
|
|
238
|
+
"Explain fable on sonnet; don't switch model or delegate.",
|
|
239
|
+
'Explain fable on sonnet; no stages and no delegation.',
|
|
240
|
+
'解釋 fable on sonnet,不要委派或切換模型。',
|
|
241
|
+
]) {
|
|
242
|
+
const lookup = runTier(prompt);
|
|
243
|
+
const repeat = runTier(prompt);
|
|
244
|
+
if (validContract(lookup, 'bounded Fable lookup')) {
|
|
245
|
+
check(lookup.contract.classification.tier === 'tier1', 'lookup remains a bounded Tier 1 operation');
|
|
246
|
+
check(lookup.contract.workflowPlan.strategy === 'direct-single', 'lookup selects direct-single before loading references');
|
|
247
|
+
check(lookup.contract.workflowPlan.parallelism.allowed === false, 'lookup does not delegate');
|
|
248
|
+
check(lookup.result.stdout.includes('references/profile-lookup.md'), 'lookup selects only compact reference');
|
|
249
|
+
check(!lookup.result.stdout.includes('RECOMMENDED KNOWLEDGE GUIDES'), 'lookup omits unrelated keyword guides');
|
|
250
|
+
check(!lookup.result.stdout.includes('with fable-mode/scripts/model-selector.js'), 'lookup does not send agent to selector implementation');
|
|
251
|
+
check(JSON.stringify(lookup.contract) === JSON.stringify(repeat.contract), 'lookup contract is deterministic');
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
for (const prompt of [
|
|
255
|
+
'Use fable on sonnect to implement a multi-stage architecture migration.',
|
|
256
|
+
'Explain fable on opus and then implement a repository-wide migration.',
|
|
257
|
+
'Explain how to run fable-staged across all modules.',
|
|
258
|
+
'Explain fable on sonnet then run it to analyze security.',
|
|
259
|
+
'Explain fable on sonnet and analyze the authentication design.',
|
|
260
|
+
'Explain fable on sonnet; then send the findings to Slack.',
|
|
261
|
+
'Explain fable on sonnet and update README.',
|
|
262
|
+
'Explain fable on haiku, add a regression test.',
|
|
263
|
+
'Explain fable on opus and commit the documentation change.',
|
|
264
|
+
'說明 fable on sonnet 並更新 README。',
|
|
265
|
+
'解釋 fable on haiku,新增回歸測試。',
|
|
266
|
+
'解析 fable on opus 並刪除過期文件。',
|
|
267
|
+
'Explain fable on sonnet before updating README.',
|
|
268
|
+
'Explain fable on sonnet; return JSON after updating README.',
|
|
269
|
+
"Explain fable on sonnet before updating README.md to change 'Instalation' to 'Installation'.",
|
|
270
|
+
'解釋 fable on sonnet 後更新 README。',
|
|
271
|
+
'Explain fable on sonnet; no delegation before deleting stale files.',
|
|
272
|
+
'Explain fable on sonnet; return JSON with requestedProfile, update README.',
|
|
273
|
+
'Explain fable on sonnet; output JSON with requestedProfile and then publish the result.',
|
|
274
|
+
'Explain fable on sonnet; return JSON after restarting the server.',
|
|
275
|
+
'Explain fable on sonnet; no execution except updating README.',
|
|
276
|
+
'Explain fable on sonnet; provide a profile result while running the tests.',
|
|
277
|
+
'Explain fable on sonnet; return JSON with unknownField.',
|
|
278
|
+
'Explain fable on sonnet; some unknown continuation.',
|
|
279
|
+
// A negation scopes only its own noun list; affirmative actions after it execute.
|
|
280
|
+
'Explain fable on sonnet; no delegation, do execution.',
|
|
281
|
+
'Explain fable on sonnet; no delegation, switch model.',
|
|
282
|
+
'Explain fable on sonnet; no delegation and stage execution.',
|
|
283
|
+
'Explain fable on sonnet; without orchestration do execution.',
|
|
284
|
+
'Explain fable on sonnet; no delegation or switch model.',
|
|
285
|
+
'解釋 fable on sonnet,不要委派,執行。',
|
|
286
|
+
'解釋 fable on sonnet,不要委派,切換模型。',
|
|
287
|
+
]) {
|
|
288
|
+
const execution = runTier(prompt);
|
|
289
|
+
if (validContract(execution, 'Fable execution boundary')) {
|
|
290
|
+
check(execution.contract.workflowPlan.strategy === 'fable-staged', 'execution/macro scope preserves staged topology');
|
|
291
|
+
check(!execution.contract.workflowPlan.reasonCodes.includes('fable-profile-lookup'), 'mixed execution never records the bounded lookup reason');
|
|
292
|
+
check(execution.contract.workflowPlan.requiredInvariants.includes('isolated-worktree-before-mutation'), 'execution retains isolation obligation');
|
|
293
|
+
}
|
|
209
294
|
}
|
|
210
295
|
|
|
211
296
|
const explicitOverride = runTier('Use iterative-single to audit the entire repository architecture.');
|
|
@@ -250,10 +335,10 @@ if (validContract(noWorkspaceState, 'workspace state block')) {
|
|
|
250
335
|
const unavailableModel = runTier('fable on opus audit the entire repository architecture', {
|
|
251
336
|
context: { hostCapabilities: { modelAvailability: 'unavailable', subagents: 'available' } },
|
|
252
337
|
});
|
|
253
|
-
if (validContract(unavailableModel, 'model capability
|
|
254
|
-
check(unavailableModel.contract.workflowPlan.
|
|
255
|
-
check(unavailableModel.contract.workflowPlan.fallback.disposition
|
|
256
|
-
check(unavailableModel.contract.workflowPlan.fallback.reasonCodes.includes('requested-model-capability-unavailable'), 'model
|
|
338
|
+
if (validContract(unavailableModel, 'runtime model capability advisory')) {
|
|
339
|
+
check(unavailableModel.contract.workflowPlan.profileSelection.requested === 'orchestrator', 'opus remains a behavior-profile alias');
|
|
340
|
+
check(unavailableModel.contract.workflowPlan.fallback.disposition !== 'blocked', 'runtime model availability does not block Fable profile selection');
|
|
341
|
+
check(!unavailableModel.contract.workflowPlan.fallback.reasonCodes.includes('requested-model-capability-unavailable'), 'router no longer treats a branded model as a Fable requirement');
|
|
257
342
|
}
|
|
258
343
|
|
|
259
344
|
const hookUnavailable = runTier('Drop the prod database table.', {
|
|
@@ -38,6 +38,14 @@ This is a **repository/agent contract**, not an automatic upgrade to any platfor
|
|
|
38
38
|
|
|
39
39
|
The full ten-dimension entries and official source URLs are in [platform-compatibility.json](platform-compatibility.json). “Supported” in the standalone-skills column refers to the host’s documented skill surface plus the repository’s verified path contract; it does not mean that a live Harness session was run on every platform.
|
|
40
40
|
|
|
41
|
+
### Claude Code Fable entrypoint boundary
|
|
42
|
+
|
|
43
|
+
The Claude plugin registers `./fable-mode` as the public Fable skill. The nested `fable-opus`, `fable-sonnet`, `fable-haiku`, and `execution-guardrails` directories are reference contracts inside that skill tree; they are not independently registered or host-routable Claude skills. The legacy prompts `fable on opus`, `fable on sonnet`/`sonnect`, and `fable on haiku` select Fable behavior profiles (orchestrator/reasoning/mechanical), not branded runtime models. `model-selector.js` records the profile and separately evaluates the host-specific advisory runtime floor; a below-floor or unknown runtime does not block Fable by itself.
|
|
44
|
+
|
|
45
|
+
The router distinguishes bounded profile explanations from Fable execution. Supported lookup prompts select `direct-single` and `references/profile-lookup.md`; the public skill dispatches before loading stage references. Entire explanation, format and negative-constraint clauses are checked against a bounded lookup vocabulary; comma/and-separated canonical output fields remain lookup data. Unknown continuations, same-clause actions (including `before`/`after`), mixed execution or macro scope retain execution routing and required invariants. This is a deterministic routing and packaged instruction contract, not a host-enforced reference-read limit or a measured token-cost guarantee.
|
|
46
|
+
|
|
47
|
+
The nested execution-guardrails file is also not an always-on carrier. Fable agents that need those rules carry them inline; any non-Fable surface must load, copy, or inject the rules through a carrier the host actually executes before claiming that they apply there.
|
|
48
|
+
|
|
41
49
|
## Installer target contract
|
|
42
50
|
|
|
43
51
|
The general installer’s target paths are tested independently from host discovery. This prevents a successful file copy from being reported as proof that an agent will load the file.
|
|
@@ -36,18 +36,19 @@ stateDiagram-v2
|
|
|
36
36
|
Recorded --> [*]
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
The stage record preserves
|
|
39
|
+
The stage record preserves requested/effective behavior profile, profile alias, runtime model/effort when known, runtime-floor status, fallback reason, stage brief, artifact, pass condition, verification command, and verifier result.
|
|
40
40
|
|
|
41
|
-
## 3.
|
|
41
|
+
## 3. Behavior Profile and Runtime Recommendation
|
|
42
42
|
|
|
43
|
-
Explicit
|
|
43
|
+
Explicit `haiku`/`sonnet`/`sonnect`/`opus` requests are behavior-profile aliases resolved through `model-selector.js`; they do not pin the host runtime model. Host-specific model floors are advisory and visible.
|
|
44
44
|
|
|
45
45
|
```mermaid
|
|
46
46
|
flowchart LR
|
|
47
|
-
Requested[Requested
|
|
48
|
-
Selector
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
Requested[Requested profile / legacy alias] --> Selector[model-selector.js]
|
|
48
|
+
Selector --> Role[Named Fable role]
|
|
49
|
+
Role --> Runtime[Host runtime + advisory model floor]
|
|
50
|
+
Runtime -->|Meets / below / unknown| Execute[Execute same behavior profile]
|
|
51
|
+
Role -->|Named agent unavailable| Fallback[Inline or stop fallback]
|
|
51
52
|
Named --> Stage[Bounded stage brief]
|
|
52
53
|
Fallback --> Stage
|
|
53
54
|
Stage --> Verify[Named stage check]
|
|
@@ -56,7 +57,7 @@ flowchart LR
|
|
|
56
57
|
Cold --> Record
|
|
57
58
|
```
|
|
58
59
|
|
|
59
|
-
The
|
|
60
|
+
The role split is explicit: `opus` aliases the orchestrator profile, `sonnet` aliases reasoning, and `haiku` aliases mechanical work. These names describe Fable behavior; actual Claude/Codex model choice is a separate host concern. Workers do not spawn workers.
|
|
60
61
|
|
|
61
62
|
## 4. Scope and Context Discipline
|
|
62
63
|
|
|
@@ -89,4 +90,4 @@ At most two full replans are allowed before unresolved blockers are escalated ra
|
|
|
89
90
|
|
|
90
91
|
Fable completion means the planned stages have produced their artifacts, their checks have passed, and high-risk outputs have received skeptical review where required. It does not mean every possible companion skill was invoked.
|
|
91
92
|
|
|
92
|
-
The canonical executable and policy details live in `fable-mode/SKILL.md`, `fable-mode/model-matrix.json`, `fable-mode/scripts/model-selector.js`, and `fable-mode/references/model-matrix.md`.
|
|
93
|
+
The canonical executable and policy details live in `fable-mode/SKILL.md`, `fable-mode/behavior-profile-matrix.json`, `fable-mode/runtime-model-floor-matrix.json`, `fable-mode/scripts/model-selector.js`, and `fable-mode/references/model-matrix.md`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
id: negative-fable-model-005
|
|
2
|
-
name: Ordinary Tier 2 work does not select a fable
|
|
3
|
-
description: A normal Tier 2 bugfix must not route to
|
|
2
|
+
name: Ordinary Tier 2 work does not select a fable profile
|
|
3
|
+
description: A normal Tier 2 bugfix must not route to an explicit Fable behavior profile.
|
|
4
4
|
tags:
|
|
5
5
|
- negative-trigger
|
|
6
6
|
- tier-2
|
|
@@ -10,7 +10,7 @@ expected:
|
|
|
10
10
|
should_trigger: false
|
|
11
11
|
graders:
|
|
12
12
|
- type: text
|
|
13
|
-
name: no-
|
|
13
|
+
name: no-explicit-profile-route
|
|
14
14
|
config:
|
|
15
15
|
contains:
|
|
16
16
|
- "fable-opus"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
id: positive-fable-haiku-002
|
|
2
2
|
name: Explicit Haiku mode routes mechanical work
|
|
3
|
-
description: "Stage large
|
|
3
|
+
description: "Stage large tasks through plans, named fable agents, failable checks, and skeptical review; fable on opus|sonnet|haiku selects a behavior profile, not a runtime model."
|
|
4
4
|
tags:
|
|
5
5
|
- positive-trigger
|
|
6
6
|
- fable-haiku
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
id: positive-fable-opus-004
|
|
2
2
|
name: Explicit Opus mode routes macro orchestration
|
|
3
|
-
description: "Stage large
|
|
3
|
+
description: "Stage large tasks through plans, named fable agents, failable checks, and skeptical review; fable on opus|sonnet|haiku selects a behavior profile, not a runtime model."
|
|
4
4
|
tags:
|
|
5
5
|
- positive-trigger
|
|
6
6
|
- fable-opus
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
id: positive-fable-sonnet-003
|
|
2
2
|
name: Explicit Sonnet mode routes reasoning work
|
|
3
|
-
description: "Stage large
|
|
3
|
+
description: "Stage large tasks through plans, named fable agents, failable checks, and skeptical review; fable on opus|sonnet|haiku selects a behavior profile, not a runtime model."
|
|
4
4
|
tags:
|
|
5
5
|
- positive-trigger
|
|
6
6
|
- fable-sonnet
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
id: positive-fable-mode-001
|
|
2
2
|
name: On-scope prompt triggers fable-mode
|
|
3
|
-
description: "Stage large
|
|
3
|
+
description: "Stage large tasks through plans, named fable agents, failable checks, and skeptical review; fable on opus|sonnet|haiku selects a behavior profile, not a runtime model."
|
|
4
4
|
tags:
|
|
5
5
|
- positive-trigger
|
|
6
6
|
inputs:
|
package/fable-mode/SKILL.md
CHANGED
|
@@ -1,39 +1,45 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fable-mode
|
|
3
|
-
description: "Stage large
|
|
3
|
+
description: "Stage large tasks through plans, named fable agents, failable checks, and skeptical review; fable on opus|sonnet|haiku selects a behavior profile, not a runtime model."
|
|
4
4
|
license: Apache-2.0
|
|
5
5
|
metadata:
|
|
6
6
|
author: Miya Daniel
|
|
7
|
-
version: 0.30.
|
|
7
|
+
version: 0.30.6
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
# Fable Mode
|
|
10
|
+
# Fable Mode
|
|
11
11
|
|
|
12
12
|
## Skill Contract
|
|
13
13
|
|
|
14
14
|
| Component | Specification |
|
|
15
15
|
| :--- | :--- |
|
|
16
|
-
| **Trigger / Input** |
|
|
17
|
-
| **Expected Output** |
|
|
18
|
-
| **State Mutations** |
|
|
19
|
-
| **Enforcement Gate** | `<this-skill-dir>/scripts/model-selector.js`, stage contracts, and `<skills-repo-root>/harness-everything/scripts/verify-gate.js`. |
|
|
16
|
+
| **Trigger / Input** | Profile lookup or Tier 3 execution. |
|
|
17
|
+
| **Expected Output** | Profile record or verified stages. |
|
|
18
|
+
| **State Mutations** | Execution only: stage checklist and audit records. |
|
|
19
|
+
| **Enforcement Gate** | Execution: `<this-skill-dir>/scripts/model-selector.js`, stage contracts, and `<skills-repo-root>/harness-everything/scripts/verify-gate.js`. |
|
|
20
20
|
|
|
21
21
|
## USE FOR:
|
|
22
22
|
- Large multi-file, multi-source, or multi-session work
|
|
23
|
-
-
|
|
23
|
+
- Fable profile explanations or explicit Fable execution requests
|
|
24
24
|
- Work needing named delegation and cold verification
|
|
25
25
|
|
|
26
26
|
## DO NOT USE FOR:
|
|
27
27
|
- One obvious single-pass edit
|
|
28
28
|
- Ordinary Tier 2 implementation or bugfix work
|
|
29
29
|
|
|
30
|
+
## Select Operation First
|
|
31
|
+
|
|
32
|
+
For explanation/profile-only lookup, read only `<this-skill-dir>/references/profile-lookup.md` and answer. No stage state, delegation, or selector source reads. Quoted aliases do not start Fable. Mixed execution retains its topology.
|
|
33
|
+
|
|
34
|
+
Execution follows the workflow below.
|
|
35
|
+
|
|
30
36
|
## Workflow
|
|
31
37
|
|
|
32
38
|
1. Discover the runtime and lock the authorized file scope before edits.
|
|
33
39
|
2. Write a numbered stage map with one artifact and pass condition per stage; allow at most two full replans.
|
|
34
|
-
3. Resolve the requested
|
|
35
|
-
4. Delegate by
|
|
36
|
-
5.
|
|
37
|
-
6.
|
|
40
|
+
3. Resolve the requested behavior profile with `model-selector.js`; `opus`, `sonnet`/`sonnect`, and `haiku` are compatibility aliases, not model bindings.
|
|
41
|
+
4. Delegate by profile: orchestrator coordinates, reasoning handles bounded judgment, mechanical handles low-ambiguity work, and workers never spawn workers.
|
|
42
|
+
5. Treat the host runtime-model floor as advisory; record its status without blocking Fable solely for model choice.
|
|
43
|
+
6. Run each stage check, cold-review high-stakes artifacts, and audit profile/runtime/fallback fields.
|
|
38
44
|
|
|
39
45
|
Deep dive: <this-skill-dir>/references/model-matrix.md
|