orchestrator-workflow 0.41.0 → 0.43.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/CHANGELOG.md +135 -0
- package/INSTALL-AGENT.md +6 -1
- package/README.md +132 -645
- package/assets/agents/task-slicer.md +11 -1
- package/assets/codex-models.json +5 -0
- package/assets/skill/SKILL.md +3 -2
- package/assets/skill/references/bundle-gate-in-ci.md +60 -11
- package/assets/skill/references/contracts.md +15 -1
- package/assets/skill/references/evidence-and-probes.md +52 -8
- package/assets/skill/references/review-and-recovery.md +5 -0
- package/dist/cli.js +12 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/init.d.ts +11 -3
- package/dist/init.js +56 -13
- package/dist/routing.d.ts +28 -62
- package/dist/routing.js +86 -17
- package/docs/architecture.md +44 -0
- package/docs/harnesses.md +38 -0
- package/docs/install-reference.md +95 -0
- package/docs/model-routing-reference.md +252 -0
- package/docs/operator-install.md +113 -0
- package/docs/role-profile-reference.md +48 -0
- package/docs/run-contracts.md +36 -0
- package/docs/validate-review-report.md +57 -0
- package/docs/verification-sets.md +53 -0
- package/package.json +3 -2
package/dist/routing.d.ts
CHANGED
|
@@ -4,11 +4,13 @@ export interface ModelSelection {
|
|
|
4
4
|
model: string;
|
|
5
5
|
effort: Tier;
|
|
6
6
|
}
|
|
7
|
+
export type CodexModelAlias = "small" | "balanced" | "strong";
|
|
7
8
|
/**
|
|
8
9
|
* A sparse harness-specific model-routing patch. Later layers supplied to
|
|
9
10
|
* mergeRouting replace a selection leaf while preserving unrelated entries.
|
|
10
11
|
*/
|
|
11
12
|
export type HarnessRouting = Partial<Record<Harness, Partial<Record<Role, Partial<Record<Tier, ModelSelection>>>>>>;
|
|
13
|
+
export declare function parseCodexModels(value: unknown): Partial<Record<CodexModelAlias, string>>;
|
|
12
14
|
/**
|
|
13
15
|
* Parses one strict, sparse routing layer. It deliberately never drops
|
|
14
16
|
* unrecognised data: a typo in a harness, role, tier, or selection is an
|
|
@@ -17,80 +19,44 @@ export type HarnessRouting = Partial<Record<Harness, Partial<Record<Role, Partia
|
|
|
17
19
|
export declare function parseRouting(value: unknown): HarnessRouting;
|
|
18
20
|
/** Deeply merges sparse routing layers without mutating any input layer. */
|
|
19
21
|
export declare function mergeRouting(...layers: (HarnessRouting | undefined)[]): HarnessRouting;
|
|
20
|
-
declare const
|
|
22
|
+
declare const CODEX_DEFAULT_ALIASES: {
|
|
21
23
|
explorer: {
|
|
22
|
-
low:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
};
|
|
26
|
-
medium: {
|
|
27
|
-
model: string;
|
|
28
|
-
effort: "medium";
|
|
29
|
-
};
|
|
30
|
-
high: {
|
|
31
|
-
model: string;
|
|
32
|
-
effort: "high";
|
|
33
|
-
};
|
|
24
|
+
low: "small";
|
|
25
|
+
medium: "balanced";
|
|
26
|
+
high: "balanced";
|
|
34
27
|
};
|
|
35
28
|
"task-slicer": {
|
|
36
|
-
low:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
};
|
|
40
|
-
medium: {
|
|
41
|
-
model: string;
|
|
42
|
-
effort: "medium";
|
|
43
|
-
};
|
|
44
|
-
high: {
|
|
45
|
-
model: string;
|
|
46
|
-
effort: "high";
|
|
47
|
-
};
|
|
29
|
+
low: "balanced";
|
|
30
|
+
medium: "balanced";
|
|
31
|
+
high: "balanced";
|
|
48
32
|
};
|
|
49
33
|
implementer: {
|
|
50
|
-
low:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
medium: {
|
|
55
|
-
model: string;
|
|
56
|
-
effort: "medium";
|
|
57
|
-
};
|
|
58
|
-
high: {
|
|
59
|
-
model: string;
|
|
60
|
-
effort: "high";
|
|
61
|
-
};
|
|
62
|
-
xhigh: {
|
|
63
|
-
model: string;
|
|
64
|
-
effort: "xhigh";
|
|
65
|
-
};
|
|
34
|
+
low: "small";
|
|
35
|
+
medium: "balanced";
|
|
36
|
+
high: "balanced";
|
|
37
|
+
xhigh: "strong";
|
|
66
38
|
};
|
|
67
39
|
reviewer: {
|
|
68
|
-
medium:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
};
|
|
72
|
-
high: {
|
|
73
|
-
model: string;
|
|
74
|
-
effort: "high";
|
|
75
|
-
};
|
|
76
|
-
xhigh: {
|
|
77
|
-
model: string;
|
|
78
|
-
effort: "xhigh";
|
|
79
|
-
};
|
|
40
|
+
medium: "balanced";
|
|
41
|
+
high: "strong";
|
|
42
|
+
xhigh: "strong";
|
|
80
43
|
};
|
|
81
44
|
advisor: {
|
|
82
|
-
high:
|
|
83
|
-
|
|
84
|
-
effort: "high";
|
|
85
|
-
};
|
|
86
|
-
xhigh: {
|
|
87
|
-
model: string;
|
|
88
|
-
effort: "xhigh";
|
|
89
|
-
};
|
|
45
|
+
high: "strong";
|
|
46
|
+
xhigh: "strong";
|
|
90
47
|
};
|
|
91
48
|
};
|
|
49
|
+
export declare function codexModelsRoutingPatch(value: unknown): HarnessRouting;
|
|
50
|
+
type CodexDefaultRoleRouting<AliasRouting extends Partial<Record<Tier, CodexModelAlias>>> = {
|
|
51
|
+
[TierName in keyof AliasRouting]: TierName extends Tier ? {
|
|
52
|
+
model: string;
|
|
53
|
+
effort: TierName;
|
|
54
|
+
} : never;
|
|
55
|
+
};
|
|
92
56
|
export type CodexDefaultRouting = HarnessRouting & {
|
|
93
|
-
codex:
|
|
57
|
+
codex: {
|
|
58
|
+
[RoleName in Role]: CodexDefaultRoleRouting<(typeof CODEX_DEFAULT_ALIASES)[RoleName]>;
|
|
59
|
+
};
|
|
94
60
|
};
|
|
95
61
|
/** Returns a fresh complete Codex routing layer, including each default tier. */
|
|
96
62
|
export declare function defaultCodexRouting(): CodexDefaultRouting;
|
package/dist/routing.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { HARNESSES } from "./detect.js";
|
|
2
|
+
import { readAsset } from "./assets.js";
|
|
2
3
|
import { ROLE_TIERS, ROLES } from "./models.js";
|
|
4
|
+
const CODEX_MODEL_ALIASES = [
|
|
5
|
+
"small",
|
|
6
|
+
"balanced",
|
|
7
|
+
"strong",
|
|
8
|
+
];
|
|
3
9
|
const TIERS = ["low", "medium", "high", "xhigh"];
|
|
4
10
|
const DANGEROUS_KEYS = new Set(["__proto__", "prototype", "constructor"]);
|
|
5
11
|
const CLAUDE_ALIASES = new Set(["sonnet", "opus", "haiku"]);
|
|
@@ -58,6 +64,50 @@ function assertModelId(model, harness, location) {
|
|
|
58
64
|
}
|
|
59
65
|
return model;
|
|
60
66
|
}
|
|
67
|
+
function assertConcreteCodexModelId(model, location) {
|
|
68
|
+
const value = assertModelId(model, "codex", location);
|
|
69
|
+
if (CODEX_MODEL_ALIASES.includes(value)) {
|
|
70
|
+
throw new Error(`${location}.model must not use an internal Codex alias`);
|
|
71
|
+
}
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
function loadBundledCodexModels() {
|
|
75
|
+
let value;
|
|
76
|
+
try {
|
|
77
|
+
value = JSON.parse(readAsset("codex-models.json"));
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
81
|
+
throw new Error(`Could not read bundled Codex model aliases: ${reason}`);
|
|
82
|
+
}
|
|
83
|
+
if (!isRecord(value)) {
|
|
84
|
+
throw new Error("Bundled Codex model aliases must be an object");
|
|
85
|
+
}
|
|
86
|
+
assertSafeKeys(value, "bundled Codex model aliases");
|
|
87
|
+
const result = {};
|
|
88
|
+
for (const alias of CODEX_MODEL_ALIASES) {
|
|
89
|
+
if (!(alias in value)) {
|
|
90
|
+
throw new Error(`Bundled Codex model aliases must contain "${alias}"`);
|
|
91
|
+
}
|
|
92
|
+
result[alias] = assertConcreteCodexModelId(value[alias], `bundled Codex model alias "${alias}"`);
|
|
93
|
+
}
|
|
94
|
+
for (const key of Object.keys(value)) {
|
|
95
|
+
assertKnownKey(key, CODEX_MODEL_ALIASES, "bundled Codex model alias");
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
export function parseCodexModels(value) {
|
|
100
|
+
if (!isRecord(value)) {
|
|
101
|
+
throw new Error("Codex model aliases must be an object");
|
|
102
|
+
}
|
|
103
|
+
assertSafeKeys(value, "Codex model aliases");
|
|
104
|
+
const result = {};
|
|
105
|
+
for (const [alias, model] of Object.entries(value)) {
|
|
106
|
+
assertKnownKey(alias, CODEX_MODEL_ALIASES, "Codex model alias");
|
|
107
|
+
result[alias] = assertConcreteCodexModelId(model, `Codex model alias "${alias}"`);
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
61
111
|
function parseSelection(value, harness, location) {
|
|
62
112
|
if (!isRecord(value)) {
|
|
63
113
|
throw new Error(`${location} must be a selection object`);
|
|
@@ -144,36 +194,55 @@ export function mergeRouting(...layers) {
|
|
|
144
194
|
}
|
|
145
195
|
return result;
|
|
146
196
|
}
|
|
147
|
-
const
|
|
197
|
+
const CODEX_DEFAULT_ALIASES = {
|
|
148
198
|
explorer: {
|
|
149
|
-
low:
|
|
150
|
-
medium:
|
|
151
|
-
high:
|
|
199
|
+
low: "small",
|
|
200
|
+
medium: "balanced",
|
|
201
|
+
high: "balanced",
|
|
152
202
|
},
|
|
153
203
|
"task-slicer": {
|
|
154
|
-
low:
|
|
155
|
-
medium:
|
|
156
|
-
high:
|
|
204
|
+
low: "balanced",
|
|
205
|
+
medium: "balanced",
|
|
206
|
+
high: "balanced",
|
|
157
207
|
},
|
|
158
208
|
implementer: {
|
|
159
|
-
low:
|
|
160
|
-
medium:
|
|
161
|
-
high:
|
|
162
|
-
xhigh:
|
|
209
|
+
low: "small",
|
|
210
|
+
medium: "balanced",
|
|
211
|
+
high: "balanced",
|
|
212
|
+
xhigh: "strong",
|
|
163
213
|
},
|
|
164
214
|
reviewer: {
|
|
165
|
-
medium:
|
|
166
|
-
high:
|
|
167
|
-
xhigh:
|
|
215
|
+
medium: "balanced",
|
|
216
|
+
high: "strong",
|
|
217
|
+
xhigh: "strong",
|
|
168
218
|
},
|
|
169
219
|
advisor: {
|
|
170
|
-
high:
|
|
171
|
-
xhigh:
|
|
220
|
+
high: "strong",
|
|
221
|
+
xhigh: "strong",
|
|
172
222
|
},
|
|
173
223
|
};
|
|
224
|
+
function codexRoutingForAliases(models) {
|
|
225
|
+
const routing = { codex: {} };
|
|
226
|
+
for (const role of ROLES) {
|
|
227
|
+
for (const tier of ROLE_TIERS[role]) {
|
|
228
|
+
const alias = CODEX_DEFAULT_ALIASES[role][tier];
|
|
229
|
+
if (alias === undefined)
|
|
230
|
+
continue;
|
|
231
|
+
const model = models[alias];
|
|
232
|
+
if (model === undefined)
|
|
233
|
+
continue;
|
|
234
|
+
routing.codex[role] ??= {};
|
|
235
|
+
routing.codex[role][tier] = { model, effort: tier };
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return routing;
|
|
239
|
+
}
|
|
240
|
+
export function codexModelsRoutingPatch(value) {
|
|
241
|
+
return codexRoutingForAliases(parseCodexModels(value));
|
|
242
|
+
}
|
|
174
243
|
/** Returns a fresh complete Codex routing layer, including each default tier. */
|
|
175
244
|
export function defaultCodexRouting() {
|
|
176
|
-
return
|
|
245
|
+
return codexRoutingForAliases(loadBundledCodexModels());
|
|
177
246
|
}
|
|
178
247
|
function normalizeCodexCatalog(catalog) {
|
|
179
248
|
const modelsValue = Array.isArray(catalog)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Architecture: why this shape
|
|
2
|
+
|
|
3
|
+
The orchestrator/subagent loop `orchestrator-workflow` installs, and the
|
|
4
|
+
reasoning behind it. See the [package README](../README.md) for installation
|
|
5
|
+
and day-to-day usage.
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
Operator
|
|
9
|
+
goal | ^ handoff: what changed, how verified,
|
|
10
|
+
v | what remains open
|
|
11
|
+
explorer --> Orchestrator . . . . . .ai/runs/<date>-<slug>/
|
|
12
|
+
optional, session model 00-goal 04-implementation-summary
|
|
13
|
+
read-only plans, validates slices, 01-plan 05-review-findings
|
|
14
|
+
terrain map decides acceptance 02-tasks 06-handoff
|
|
15
|
+
| 03-decisions
|
|
16
|
+
narrow | ^ structured (state lives in files,
|
|
17
|
+
contracts v | YAML evidence not in chat history)
|
|
18
|
+
+-------------+-------------+
|
|
19
|
+
| | |
|
|
20
|
+
task-slicer implementer reviewer
|
|
21
|
+
sonnet sonnet opus
|
|
22
|
+
small, one narrow skeptical, severity-rated
|
|
23
|
+
testable task, plus findings, no rewrites
|
|
24
|
+
slices tests
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Two effects fall out of this shape:
|
|
28
|
+
|
|
29
|
+
- **Token efficiency.** The orchestrator's context stays small: subagents
|
|
30
|
+
receive narrow task contracts instead of the whole conversation, return
|
|
31
|
+
structured YAML evidence instead of transcripts, and durable state lives
|
|
32
|
+
in run files that survive context compaction. The cheap models do the
|
|
33
|
+
volume work; the strongest model is spent only on orchestration decisions
|
|
34
|
+
and the skeptical review. The ceremony scales to the task: a trivial change
|
|
35
|
+
is done directly, the full flow is for non-trivial work, and a read-only
|
|
36
|
+
explorer maps the terrain first only when the solution is unclear. When
|
|
37
|
+
available, the explorer prefers each of a repo's configured knowledge
|
|
38
|
+
bundles (`knowledge` in `.ai/workflow/manifest.json`; default `docs/okf/`)
|
|
39
|
+
or a connected semantic code-search tool over hand-mapping terrain with
|
|
40
|
+
grep.
|
|
41
|
+
- **Quality through structure.** Writing and reviewing are separated by
|
|
42
|
+
role and model, task slices are validated before any implementation
|
|
43
|
+
starts, acceptance is decided on evidence (tests executed, findings
|
|
44
|
+
addressed), and every run leaves an auditable trail in `.ai/runs/`.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Harnesses: installed files and read-only posture
|
|
2
|
+
|
|
3
|
+
See the [package README](../README.md) for install commands and the rest of
|
|
4
|
+
the CLI surface.
|
|
5
|
+
|
|
6
|
+
Each installed skill includes the compact `SKILL.md` entrypoint and every
|
|
7
|
+
regular Markdown file from its adjacent `references/` directory. The entrypoint
|
|
8
|
+
routes run-state/harness, contracts, evidence/probes, and review/recovery work
|
|
9
|
+
to those files; references are part of the installed skill, not optional docs.
|
|
10
|
+
|
|
11
|
+
| Harness | Files | Notes |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| Claude Code | `.claude/skills/orchestrator-workflow/{SKILL.md,references/*.md}`, `.claude/agents/{explorer,task-slicer,implementer,reviewer,advisor}.md`, `CLAUDE.md` | Claude Code reads `CLAUDE.md`, not `AGENTS.md`; the installer adds an additive `@AGENTS.md` import. Subagent models go into the `model:` frontmatter; the read-only explorer, reviewer, and advisor also get `disallowedTools: Edit, Write, NotebookEdit`. |
|
|
14
|
+
| OpenAI Codex | `.agents/skills/orchestrator-workflow/{SKILL.md,references/*.md}`, `.codex/agents/{explorer,task-slicer,implementer,reviewer,advisor}.toml` | Codex reads `AGENTS.md` natively. Native custom-agent files carry the canonical role instructions plus `model` and `model_reasoning_effort`. Explorer and advisor request a read-only sandbox; reviewer inherits the caller's sandbox so it can run temporary/build checks, while its prompt prohibits source edits. |
|
|
15
|
+
| opencode | `.opencode/skills/orchestrator-workflow/{SKILL.md,references/*.md}`, `.opencode/agents/{explorer,task-slicer,implementer,reviewer,advisor}.md` | opencode reads `AGENTS.md` natively. Subagents get `mode: subagent`; the read-only explorer, reviewer, and advisor also get `permission: edit: deny`. Model resolution is described in [Model routing reference](model-routing-reference.md). |
|
|
16
|
+
|
|
17
|
+
**Read-only posture, honestly stated.** Claude Code disables file-mutation
|
|
18
|
+
tools for explorer, reviewer, and advisor; opencode denies edits for those
|
|
19
|
+
roles. Codex requests a read-only sandbox for explorer and advisor. Its
|
|
20
|
+
reviewer inherits the caller's sandbox so temporary/build checks remain
|
|
21
|
+
possible, while its prompt prohibits source edits. In inherited or otherwise
|
|
22
|
+
write-enabled sandboxes, shell-level mutation (`git checkout`,
|
|
23
|
+
`git restore`, `git clean`, `git stash`, `git reset`, `sed -i`, redirecting
|
|
24
|
+
output into a file, which the reviewer may do only inside its write boundary below) is guarded by instruction only: the agent prompts forbid
|
|
25
|
+
it explicitly, but the role definition itself does not prevent it. A native
|
|
26
|
+
read-only sandbox can block those writes. This residual has bitten in practice (a
|
|
27
|
+
reviewer ran `git checkout` and discarded uncommitted work), which is why the
|
|
28
|
+
prompts now name the forbidden commands instead of just saying "read-only".
|
|
29
|
+
The reviewer's own write boundary is narrower than "read-only": it may write
|
|
30
|
+
to its own scratchpad (a scratch copy or replay of the repository) and to
|
|
31
|
+
the run directory's `evidence/`, and nowhere else. It never writes into the
|
|
32
|
+
reviewed tree, its index, its refs, or its object store: no `git fetch`, no
|
|
33
|
+
`git merge-tree --write-tree`, no `git update-ref`, no `git gc`, on top of
|
|
34
|
+
the working-tree and index mutations already forbidden above. A write a
|
|
35
|
+
declared check or the probe runner's own isolation leaves behind is expected
|
|
36
|
+
wherever that tool places it, not an exception to this rule.
|
|
37
|
+
Marker- or verdict-style enforcement of the Bash residual (sandboxing,
|
|
38
|
+
PreToolUse hooks) is harness territory and out of this kit's scope.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Install reference
|
|
2
|
+
|
|
3
|
+
Details behind the install commands in the [package README](../README.md):
|
|
4
|
+
what the agent-led installer's conflict check does, the exact rules for
|
|
5
|
+
`--harness none` (templates-only mode) on a re-run, the optional
|
|
6
|
+
`knowledge` manifest field for a repository whose bundle is not at the
|
|
7
|
+
default location, and the file-ownership rules a re-run follows.
|
|
8
|
+
|
|
9
|
+
## Agent-led installation: bundle and conflict handling
|
|
10
|
+
|
|
11
|
+
The compact skill entrypoint and its routed references form one installed
|
|
12
|
+
bundle. On a reinstall, the installer checks the core and every required
|
|
13
|
+
reference for local conflicts before activating a new core; it leaves the
|
|
14
|
+
current coherent bundle intact unless an explicitly authorized `--force` run
|
|
15
|
+
replaces the affected files.
|
|
16
|
+
|
|
17
|
+
## Templates-only mode (`--harness none`)
|
|
18
|
+
|
|
19
|
+
`--harness none` (the literal word `none`, on its own) installs only
|
|
20
|
+
`.ai/workflow/**` and `.ai/runs/.gitkeep`: no `AGENTS.md`, no `CLAUDE.md`, no
|
|
21
|
+
harness-specific directory, and a manifest recording `harnesses: []`. Use it
|
|
22
|
+
for a repo that wants the run-state templates and the workflow itself, but no
|
|
23
|
+
per-harness subagent files yet (e.g. no harness has been chosen, or the files
|
|
24
|
+
were dropped by hand). `none` combined with a real harness name
|
|
25
|
+
(`--harness none,claude`) is rejected as ambiguous rather than silently
|
|
26
|
+
picking one. A plain **non-interactive** re-run (no `--harness` flag) after a
|
|
27
|
+
templates-only install stays templates-only, for `init` and `apply` alike,
|
|
28
|
+
even when `apply`'s own operator-defaults name a harness or the target has
|
|
29
|
+
harness files on disk from something else; add a harness back with an
|
|
30
|
+
explicit `--harness <list>` on a later run, the same explicit-flag-wins rule
|
|
31
|
+
`--profile`/`--models`/`--tiers` use, applied to the no-harness case. An
|
|
32
|
+
**interactive** re-run is different: it still prompts, with nothing forced
|
|
33
|
+
pre-selected, instead of silently skipping straight back to templates-only
|
|
34
|
+
without asking; deselect every checkbox to stay templates-only. `init` and
|
|
35
|
+
`apply` both pre-check nothing at all on this prompt, and both still
|
|
36
|
+
annotate what is detected on disk with a " (detected)" label; select a
|
|
37
|
+
harness to install it.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx orchestrator-workflow init --harness none --yes
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## The `knowledge` manifest field
|
|
44
|
+
|
|
45
|
+
`manifest.json` may also carry a `knowledge` list of `{ path, repoRoot }`
|
|
46
|
+
entries, for a repo whose knowledge bundle is not at the default location (a
|
|
47
|
+
workspace-level bundle with sources in a sub-repo, a bundle elsewhere, or
|
|
48
|
+
several bundles). `path` is the bundle directory and `repoRoot` (default
|
|
49
|
+
`"."`) the root of the repository the bundle's sources live in. Each is a
|
|
50
|
+
relative path resolved against the worktree top level on its own (`path` is
|
|
51
|
+
not nested under `repoRoot`), so a workspace bundle for a sub-repo's sources
|
|
52
|
+
reads `{ "path": "kb/app", "repoRoot": "app" }`. Entries are stored
|
|
53
|
+
normalised (`./kb/app/` becomes `kb/app`); an empty or absolute path
|
|
54
|
+
(POSIX, or a Windows form such as `C:/x`), any other path starting with a
|
|
55
|
+
Windows drive letter (the drive-relative `C:x` or `C:..`), a `path` of `.`, a
|
|
56
|
+
path escaping the worktree top level, and any path containing a backslash are
|
|
57
|
+
invalid (use `/` as the separator on every platform). The absolute, drive and
|
|
58
|
+
escape rules apply both as written and to the normalised value that is stored,
|
|
59
|
+
so `./C:x` and `docs/../C:/x` are invalid too. The CLI has no flag for the
|
|
60
|
+
field: edit it in the manifest by hand, and every re-install preserves its
|
|
61
|
+
valid entries (the programmatic `runInit` option `knowledge` writes it and
|
|
62
|
+
refuses an invalid entry). A hand-edited invalid entry is ignored on read
|
|
63
|
+
and reported by `doctor`; a re-install that rewrites the manifest removes it
|
|
64
|
+
from disk and prints a note naming its index and reason. The field carries
|
|
65
|
+
no check argv; the concrete bundle-check command still lives in the
|
|
66
|
+
repository-bound verification set (see the package README's
|
|
67
|
+
"Verification sets" section), so there is one source of argv truth. When
|
|
68
|
+
`knowledge` in `.ai/workflow/manifest.json` is absent or an empty list, the
|
|
69
|
+
default `docs/okf/` applies, today's behaviour. `doctor` prints a
|
|
70
|
+
`knowledge:` detail line (the `knowledgeWarnings` key in `--json`) for a
|
|
71
|
+
configured `path` or `repoRoot` that is not a directory, for each ignored
|
|
72
|
+
invalid
|
|
73
|
+
entry, and when a non-empty list omits an existing default bundle directory.
|
|
74
|
+
These warnings never change the status or the exit code.
|
|
75
|
+
|
|
76
|
+
## Ownership and re-runs
|
|
77
|
+
|
|
78
|
+
`init` is idempotent: a second run changes nothing. `apply` installs
|
|
79
|
+
through that same `runInit` path and is subject to the same
|
|
80
|
+
conflict/`--force`/ownership rules; on the repository side it changes
|
|
81
|
+
nothing either, but it refreshes this target's entry in the operator
|
|
82
|
+
manifest on every run. The rules:
|
|
83
|
+
|
|
84
|
+
- `AGENTS.md` and `CLAUDE.md` belong to you. The installer only appends its
|
|
85
|
+
fenced section or the import line, and on re-run replaces only the content
|
|
86
|
+
between its own markers. A broken or duplicated marker fence is reported as
|
|
87
|
+
a conflict and left alone.
|
|
88
|
+
- Templates, skills, and subagent definitions are kit-owned. The manifest
|
|
89
|
+
records a hash of each file as installed, so a re-run after a kit upgrade
|
|
90
|
+
updates files you never touched and reports files you edited as conflicts
|
|
91
|
+
instead of overwriting them; `--force` overwrites those too.
|
|
92
|
+
- `.ai/workflow/manifest.json` is the kit's state file. It records the applied
|
|
93
|
+
version, harnesses, role profile, models, the `--tiers` flag, the optional
|
|
94
|
+
kit-version pin, and file hashes, and is rewritten whenever that state
|
|
95
|
+
changes; do not edit it by hand.
|