Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions core/templates/onboarding-harness.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
## AI-DLC Structure

- **Skill**: `{{HARNESS_DIR}}/skills/aidlc/` — Orchestrator (`SKILL.md`), stage protocol, and the stage files across the phase directories (the enabled set depends on the composed plugins: see the compiled `{{HARNESS_DIR}}/tools/data/stage-graph.json` or run `{{INVOKE}} --doctor`)
- **Document skill** (user-invocable): `{{HARNESS_DIR}}/skills/aidlc-knowledge/`, typed as `{{INVOKE}}-knowledge`; the framework CLI also exposes `{{INVOKE}} knowledge <verb>`. Also standalone — outside the lifecycle graph — but classified `read-write`, unlike the read-only session skills below: it changes the document catalog and emits document audit events. It never advances the workflow stage pointer and never approves a gate. See "Document knowledge" under "Where things live" in the project's root `AGENTS.md` (Claude Code and Copilot readers find it under "Shared AI-DLC onboarding" in this file).
- **Session skills** (read-only, user-invocable): `{{HARNESS_DIR}}/skills/aidlc-session-cost/`, `{{HARNESS_DIR}}/skills/aidlc-replay/`, `{{HARNESS_DIR}}/skills/aidlc-outcomes-pack/` — typed as `{{INVOKE}}-session-cost`, `{{INVOKE}}-replay`, `{{INVOKE}}-outcomes-pack`. Each pulls every count from `{{INVOKE}} engine runtime summary --json` (no LLM-side counting). Classified `read-only`: they never advance the workflow stage pointer and never emit audit events. `aidlc-session-cost` and `aidlc-replay` print to the terminal only; `aidlc-outcomes-pack` is the only one that writes a file (`OUTCOMES.md`).
- **Stage-runner skills** (user-invocable): `{{HARNESS_DIR}}/skills/aidlc-<stage>/` — one per runnable core stage, typed as `{{INVOKE}}-<stage>` (e.g. `{{INVOKE}}-domain-design`, `{{INVOKE}}-code-generation`); plugin-owned stages use their bare plugin-prefixed command name. Each runs that single stage in isolation via the engine's `--single` mode (`aidlc-orchestrate next --stage <slug> --single`) and **never advances your main workflow's `Current Stage`** — `next --single` records only the synthetic start boundary and `report --single` closes that same attempt. They are opt-in packaging: the same stage is reachable via `{{INVOKE}} --stage <slug> --single` without a runner. The runner set is generated from the compiled stage graph by `{{INVOKE}} engine gen runners` and kept in sync by its `check` drift guard, so adding a stage file and regenerating adds its runner. The three bootstrap **initialization** stages ship no per-stage runner (they have no standalone meaning); the whole initialization phase is packaged as `{{INVOKE}}-init`, which creates the first workflow record and its starting state in one step. (This is opt-in packaging: describing what to build normally sets up the first piece of work by itself — no separate initialization command is needed.)
- **Document skill** (user-invocable): `{{HARNESS_DIR}}/skills/aidlc-knowledge/`, typed as `{{SKILL_INVOKE}}-knowledge`; the framework CLI also exposes `{{INVOKE}} engine knowledge <verb>`. Also standalone — outside the lifecycle graph — but classified `read-write`, unlike the read-only session skills below: it changes the document catalog and emits document audit events. It never advances the workflow stage pointer and never approves a gate. See "Document knowledge" under "Where things live" in the project's root `AGENTS.md` (Claude Code and Copilot readers find it under "Shared AI-DLC onboarding" in this file).
- **Session skills** (read-only, user-invocable): `{{HARNESS_DIR}}/skills/aidlc-session-cost/`, `{{HARNESS_DIR}}/skills/aidlc-replay/`, `{{HARNESS_DIR}}/skills/aidlc-outcomes-pack/` — typed as `{{SKILL_INVOKE}}-session-cost`, `{{SKILL_INVOKE}}-replay`, `{{SKILL_INVOKE}}-outcomes-pack`. Each pulls every count from `{{INVOKE}} engine runtime summary --json` (no LLM-side counting). Classified `read-only`: they never advance the workflow stage pointer and never emit audit events. `aidlc-session-cost` and `aidlc-replay` print to the terminal only; `aidlc-outcomes-pack` is the only one that writes a file (`OUTCOMES.md`).
- **Stage-runner skills** (user-invocable): `{{HARNESS_DIR}}/skills/aidlc-<stage>/` — one per runnable core stage, typed as `{{SKILL_INVOKE}}-<stage>` (e.g. `{{SKILL_INVOKE}}-domain-design`, `{{SKILL_INVOKE}}-code-generation`); plugin-owned stages use their bare plugin-prefixed command name. Each runs that single stage in isolation via the engine's `--single` mode (`aidlc-orchestrate next --stage <slug> --single`) and **never advances your main workflow's `Current Stage`** — `next --single` records only the synthetic start boundary and `report --single` closes that same attempt. They are opt-in packaging: the same stage is reachable via `{{SKILL_INVOKE}} --stage <slug> --single` without a runner. The runner set is generated from the compiled stage graph by `{{INVOKE}} engine gen runners` and kept in sync by its `check` drift guard, so adding a stage file and regenerating adds its runner. The three bootstrap **initialization** stages ship no per-stage runner (they have no standalone meaning); the whole initialization phase is packaged as `{{SKILL_INVOKE}}-init`, which creates the first workflow record and its starting state in one step. (This is opt-in packaging: describing what to build normally sets up the first piece of work by itself — no separate initialization command is needed.)
- **Agents**: `{{HARNESS_DIR}}/agents/` — the base framework ships 14 agents: 11 domain-expert personas (product, design, delivery, architect, aws-platform, compliance, devsecops, developer, quality, pipeline-deploy, operations), 2 review-only agents (product-lead, architecture-reviewer), and the adaptive-workflows composer. A plugin install may add more; the enabled set is discovered from the files present under that directory. {{SLOT:agents_note}}
- **Sensors**: `{{HARNESS_DIR}}/sensors/`: automatic checks that run on matching writes or once per existing deliverable at the approval gate. Gate-fired sensors may be advisory or blocking; blocking failures require an explicit audited override before the gate opens. Ships with framework defaults (`aidlc-claim-sources.md`, `aidlc-required-sections.md`, `aidlc-upstream-coverage.md`, `aidlc-traceability.md`, `aidlc-linter.md`, `aidlc-type-check.md`); forks may add custom `aidlc-<id>.md` manifests. Stages declare which sensors fire via the frontmatter `sensors: [<id>]` list — a pull import resolved at compile time.
- **Knowledge**: `{{HARNESS_DIR}}/knowledge/` — Methodology reference. Per-agent under `aidlc-<agent>-agent/` subfolders; `aidlc-shared/` holds cross-agent material. Ships with framework.
Expand Down
3 changes: 3 additions & 0 deletions harness/copilot/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ const manifest: HarnessManifest = {
"sha256:55b31ba55f6e7ebc47fe76a00039e2ec16e020503fb63791cbd8665438ff32ac",
// The pre-Guards shipped variant (the onboarding gained its Guards section).
"sha256:7a3a19981ba7a3c447b54eb0d0b1e96f8c9931687595967103cb5dfbb3c2b309",
// The pre-skill-prefix shipped variant (#1341: user-typed skill
// names rendered the shell invocation instead of the skill command).
"sha256:622ebad60ee4fed6a2a9811e7378ccbff6b76d651aaee00fd079b02471d8cf06",
],
},
},
Expand Down
31 changes: 30 additions & 1 deletion tests/unit/t151-onboarding-skeleton.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,34 @@ describe("t151 neutral and native onboarding", () => {
]);
});

test("user-typed skill names carry the harness's skill prefix, not the shell invocation", () => {
// `{{INVOKE}}` is a shell command (`bun <dir>/tools/aidlc.ts`, or `aidlc` on
// a native install). Gluing a skill suffix onto it renders a command that
// does not exist; the skill prefix each harness declares is what a person
// types. Any `{{INVOKE}}-<suffix>` is that mistake.
expect(HARNESS).not.toMatch(/\{\{INVOKE\}\}-/);

const skills = ["session-cost", "replay", "outcomes-pack", "knowledge", "init"];
for (const invoke of ["/aidlc", "$aidlc"]) {
const rendered = renderOnboarding(HARNESS, { invoke, slots: {} })
.replaceAll("{{HARNESS_DIR}}", ".foo")
.replaceAll("{{INVOKE}}", "bun .foo/tools/aidlc.ts");
for (const skill of skills) {
expect(rendered, `${invoke}-${skill}`).toContain(`${invoke}-${skill}`);
}
expect(rendered).not.toContain("aidlc.ts-");
}
});

test("runtime examples on {{INVOKE}} name commands the CLI routes", () => {
// `--stage <slug> --single` is an orchestrator-skill flag the CLI rejects
// as an unknown command, and `knowledge` is an engine noun, so neither is
// reachable as a top-level `{{INVOKE}}` command. The shipped forms are pinned
// per harness and channel in "every harness ships complete onboarding".
expect(HARNESS).not.toMatch(/\{\{INVOKE\}\} --stage /);
expect(HARNESS).not.toMatch(/\{\{INVOKE\}\} knowledge /);
});

test("a new harness gets complete onboarding without editing either skeleton", () => {
const fills: OnboardingFills = {
invoke: "@aidlc",
Expand Down Expand Up @@ -108,8 +136,9 @@ describe("t151 neutral and native onboarding", () => {
);
expect(setup, harness.name).not.toContain(`${fills.invoke} engine`);
expect(setup, harness.name).toContain(
`${native ? "aidlc" : `bun ${harness.manifest.harnessDir}/tools/aidlc.ts`} knowledge <verb>`,
`${native ? "aidlc" : `bun ${harness.manifest.harnessDir}/tools/aidlc.ts`} engine knowledge <verb>`,
);
expect(setup, harness.name).toContain(`\`${fills.invoke} --stage <slug> --single\``);
if (harness.manifest.onboarding?.harnessDst) {
expect(root, harness.name).toBe(NEUTRAL);
expect(setup, harness.name).not.toContain("## Where things live");
Expand Down
1 change: 1 addition & 0 deletions tests/unit/t243-install-mechanism.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5171,6 +5171,7 @@ describe("t243 projection channel", () => {
"sha256:55b31ba55f6e7ebc47fe76a00039e2ec16e020503fb63791cbd8665438ff32ac",
"sha256:7a3a19981ba7a3c447b54eb0d0b1e96f8c9931687595967103cb5dfbb3c2b309",
"sha256:622ebad60ee4fed6a2a9811e7378ccbff6b76d651aaee00fd079b02471d8cf06",
"sha256:a25a15052889fe6b5900f0fef5262cc50cb00bb436e52f1eb1abe62db35b2f50",
],
},
};
Expand Down
Loading