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
19 changes: 16 additions & 3 deletions docs-lab/reference/schemas/spec-driven/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,17 +361,22 @@ Before writing tasks, check design.md for Open Questions. If any of them
would change what gets built, resolve them with the user first - do not
bake an unstated assumption into the task list.

**IMPORTANT: Follow the template below exactly.** The apply phase parses
**IMPORTANT: Follow the template below for tracked tasks.** The apply phase parses
checkbox format to track progress. A box holding only `x` counts as done,
upper or lower case and with any spacing, so `- [ x]` is done too. Every
other marker, including `- [~]`, `- [-]` and an empty `- []`, reads as
unfinished. A line with no checkbox is not tracked at all.

Guidelines:
- Group related tasks under ## numbered headings
- Each task MUST be a checkbox: `- [ ] X.Y Task description`
- Group related tracked tasks under ## numbered headings
- Each tracked task MUST be a checkbox: `- [ ] X.Y Task description`
- Tasks should be small enough to complete in one session
- Order tasks by dependency (what must be done first?)
- Track implementation and verification work that can be completed before
archive. If the requested workflow includes archive or work that requires
this change to be archived, preserve those steps as plain bullets in an
optional `## Workflow follow-up` section at the end of tasks.md. These
bullets are reference information outside tracked task progress.
- Each task MUST state how to verify completion (a test, command,
observable behavior, or delivered artifact). Put the verification in
that task's checkbox description. Use a separate verification task only
Expand Down Expand Up @@ -401,6 +406,14 @@ Example:
- [ ] 2.3 Document the export API in docs/export.md and verify the documented command runs as written
```

When applicable, append workflow follow-up as plain bullets, for example:
```
## Workflow follow-up

- Archive the change after the project's review requirements are satisfied.
- Verify the archived result.
```

Reference specs for what needs to be built, design for how to build it.
````

Expand Down
19 changes: 16 additions & 3 deletions schemas/spec-driven/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -195,17 +195,22 @@ artifacts:
would change what gets built, resolve them with the user first - do not
bake an unstated assumption into the task list.

**IMPORTANT: Follow the template below exactly.** The apply phase parses
**IMPORTANT: Follow the template below for tracked tasks.** The apply phase parses
checkbox format to track progress. A box holding only `x` counts as done,
upper or lower case and with any spacing, so `- [ x]` is done too. Every
other marker, including `- [~]`, `- [-]` and an empty `- []`, reads as
unfinished. A line with no checkbox is not tracked at all.

Guidelines:
- Group related tasks under ## numbered headings
- Each task MUST be a checkbox: `- [ ] X.Y Task description`
- Group related tracked tasks under ## numbered headings
- Each tracked task MUST be a checkbox: `- [ ] X.Y Task description`
- Tasks should be small enough to complete in one session
- Order tasks by dependency (what must be done first?)
- Track implementation and verification work that can be completed before
archive. If the requested workflow includes archive or work that requires
this change to be archived, preserve those steps as plain bullets in an
optional `## Workflow follow-up` section at the end of tasks.md. These
bullets are reference information outside tracked task progress.
- Each task MUST state how to verify completion (a test, command,
observable behavior, or delivered artifact). Put the verification in
that task's checkbox description. Use a separate verification task only
Expand Down Expand Up @@ -235,6 +240,14 @@ artifacts:
- [ ] 2.3 Document the export API in docs/export.md and verify the documented command runs as written
```

When applicable, append workflow follow-up as plain bullets, for example:
```
## Workflow follow-up

- Archive the change after the project's review requirements are satisfied.
- Verify the archived result.
```

Reference specs for what needs to be built, design for how to build it.
requires:
- specs
Expand Down
7 changes: 4 additions & 3 deletions skills/openspec-apply-change/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ In both branches, never create the root as a side effect: do not run `openspec i
- If `state: "blocked"`: show the message and pause implementation.
- If `missingArtifacts` is non-empty: suggest using `/openspec-continue-change` to create them.
- Otherwise, follow the CLI instruction to create or repair the schema-configured tracking file from existing planning artifacts. Do not assume another artifact is ready or start implementation while blocked.
- If `state: "all_done"`: congratulate, suggest archive
- If `state: "all_done"`: report that all tracked tasks are complete and suggest review or verification as appropriate before archiving
- Otherwise: proceed to implementation

Treat `context` as a required prompt-level input. Read and consider it, and
Expand Down Expand Up @@ -124,7 +124,7 @@ In both branches, never create the root as a side effect: do not run `openspec i
Display:
- Tasks completed this session
- Overall progress: "N/M tasks complete"
- If all done: suggest archive
- If all done: report that tracked tasks are complete and suggest review or verification as appropriate before archiving
- If paused: explain why and wait for guidance

**Output During Implementation**
Expand Down Expand Up @@ -155,7 +155,8 @@ Working on task 4/7: <task description>
- [x] Task 2
...

All tasks complete! You can archive this change with `/openspec-archive-change`.
All tracked tasks are complete. Review or verify the change as appropriate
before archiving. You can archive this change with `/openspec-archive-change`.
```

**Output On Pause (Issue Encountered)**
Expand Down
2 changes: 1 addition & 1 deletion src/commands/workflow/instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ export async function generateApplyInstructions(
total > 0
) {
state = 'all_done';
instruction = 'All tasks are complete! This change is ready to be archived.\nConsider running tests and reviewing the changes before archiving.';
instruction = 'All tracked tasks are complete.\nReview or verify the change as appropriate before archiving.';
} else if (!tracksFile) {
// No tracking file configured in schema - ready to apply
state = 'ready';
Expand Down
7 changes: 4 additions & 3 deletions src/core/templates/workflows/apply-change.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ ${PROJECT_ROOT_GUARD}
- If \`state: "blocked"\`: show the message and pause implementation.
- If \`missingArtifacts\` is non-empty: ${BLOCKED_STATE_HANDOFF}
- Otherwise, follow the CLI instruction to create or repair the schema-configured tracking file from existing planning artifacts. Do not assume another artifact is ready or start implementation while blocked.
- If \`state: "all_done"\`: congratulate, suggest archive
- If \`state: "all_done"\`: report that all tracked tasks are complete and suggest review or verification as appropriate before archiving
- Otherwise: proceed to implementation

Treat \`context\` as a required prompt-level input. Read and consider it, and
Expand Down Expand Up @@ -143,7 +143,7 @@ ${PROJECT_ROOT_GUARD}
Display:
- Tasks completed this session
- Overall progress: "N/M tasks complete"
- If all done: suggest archive
- If all done: report that tracked tasks are complete and suggest review or verification as appropriate before archiving
- If paused: explain why and wait for guidance

**Output During Implementation**
Expand Down Expand Up @@ -174,7 +174,8 @@ Working on task 4/7: <task description>
- [x] Task 2
...

All tasks complete! ${ARCHIVE_HANDOFF}
All tracked tasks are complete. Review or verify the change as appropriate
before archiving. ${ARCHIVE_HANDOFF}
\`\`\`

**Output On Pause (Issue Encountered)**
Expand Down
16 changes: 15 additions & 1 deletion test/commands/artifact-workflow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1246,9 +1246,23 @@ operations:
});
expect(result.exitCode).toBe(0);
expect(result.stdout).toContain('complete ✓');
expect(result.stdout).toContain('ready to be archived');
expect(result.stdout).toContain('All tracked tasks are complete');
expect(result.stdout).toContain('as appropriate before archiving');
expect(result.stdout).not.toContain('ready to be archived');
expect(result.stdout).toContain('### Project Context (required instruction input)');
expect(result.stdout).toContain('### Operation Guidance (advisory)');

const jsonResult = await runCLI(
['instructions', 'apply', '--change', 'done-apply', '--json'],
{ cwd: tempDir }
);
expect(jsonResult.exitCode).toBe(0);
expect(jsonResult.stderr).toBe('');

const json = JSON.parse(jsonResult.stdout);
expect(json.state).toBe('all_done');
expect(json.progress).toEqual({ total: 2, complete: 2, remaining: 0 });
expect(json.instruction).toContain('All tracked tasks are complete');
});

it('uses spec-driven schema apply configuration', async () => {
Expand Down
23 changes: 23 additions & 0 deletions test/core/templates/propose.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { getCommandContents } from '../../../src/core/shared/skill-generation.js
import { MAX_CONTEXT_SIZE } from '../../../src/core/project-config.js';
import { resolveOptionalWorkflows } from '../../../src/core/templates/optional-workflow.js';
import { ALL_WORKFLOWS } from '../../../src/core/profiles.js';
import { parseTaskLines } from '../../../src/utils/task-progress.js';

// Templates carry optional-workflow conditionals; a body only means anything
// once resolved against a workflow set. Unless a test says otherwise, these are
Expand Down Expand Up @@ -117,6 +118,28 @@ describe('default proposal guidance', () => {
});

describe('default task guidance', () => {
it('keeps tracked tasks within the pre-archive workflow (#1790)', () => {
const tasks = defaultSchema.artifacts.find(artifact => artifact.id === 'tasks');
expect(tasks).toBeDefined();
expect(tasks!.instruction).toMatch(
/Track implementation and verification work that can be completed before\s+archive/
);
expect(tasks!.instruction).toMatch(
/preserve those steps as plain bullets in an\s+optional `## Workflow follow-up` section at the end of tasks.md/
);

const examples = [...tasks!.instruction.matchAll(/```\s*([\s\S]*?)```/g)];
expect(examples).toHaveLength(2);
const implementation = examples[0][1];
const followUp = examples[1][1];
expect(followUp).toContain('## Workflow follow-up');
expect(followUp).toContain('- Verify the archived result.');
expect(parseTaskLines(followUp)).toEqual([]);
expect(parseTaskLines(`${implementation}\n${followUp}`)).toEqual(
parseTaskLines(implementation)
);
});

it('requires a concrete verification method in each task (#345)', () => {
const tasks = defaultSchema.artifacts.find(artifact => artifact.id === 'tasks');
expect(tasks).toBeDefined();
Expand Down
13 changes: 10 additions & 3 deletions test/core/templates/skill-templates-parity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,14 @@ const EXPECTED_FUNCTION_HASHES: Record<string, string> = {
getExploreSkillTemplate: 'c1fddb294758004936add586f5826694cb06175cff935b75fd3a8d92332332e6',
getNewChangeSkillTemplate: '0e5035b7b42198afc430206a1dbc9579096650ef0813d85e837d5a6cd0b98a85',
getContinueChangeSkillTemplate: 'c2c8a0ba7f8c8fc7b174793832cd50f7c404eb8e1f7d49c47000993d621633b6',
getApplyChangeSkillTemplate: 'a6a9aa080ba062045533b33a71ad9358d9d5fef1756616f3feac7dea64aba289',
getApplyChangeSkillTemplate: 'c4f02c29137e19b34bf1dc59146941b8c920214aa2cf3ce80ae7f1b982e976fc',
getFfChangeSkillTemplate: 'd091600476a815ba99f69b446bcd46af5bf73d1c2810215a0c6196937d019cf6',
getSyncSpecsSkillTemplate: 'bc80fe9b07eaa289e5eb8a3ce65eb7df722a16d864e37283c678220712e4f230',
getOnboardSkillTemplate: '84258a06c0ca88de708a23dd74e9a17efe11eff63a071b3864c781dcd5a0a4b7',
getOpsxExploreCommandTemplate: '5d11f8ecb4c457140a3e874a8bf7aa72674e922e698c208832b1f34d3c617719',
getOpsxNewCommandTemplate: '6d504fef1e0d4ced7c423f4cc9d9d2cee11b1a6224edf685e06a3f0757e0ebff',
getOpsxContinueCommandTemplate: '241c50f97d5d681412d456d6b982743c3a5babeb77017fc8099c418bcf0d92df',
getOpsxApplyCommandTemplate: '21ccc013710ffb9f3a93ede9f9fb7e3eecaac292fcb3f3be30e2562cae9c4127',
getOpsxApplyCommandTemplate: '9b733946aa7216b45d084bb5affd7071086db6f91282c3666731a17543825ff1',
getOpsxFfCommandTemplate: '743a7304c7efc84aa87f556154c034e1e0e561c276c51870a30ada58f33eb9af',
getArchiveChangeSkillTemplate: '04a029782fc4137971fad6f54cfda3685d7e0b835b06565f9a509b4878093099',
getBulkArchiveChangeSkillTemplate: '44dbd3c7a347e5f8339b2141393f2ac36017527cce251483fe70f2059c1e286e',
Expand All @@ -107,7 +107,7 @@ const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record<string, string> = {
'openspec-explore': '7d80caf9cd25a2565ba190b1297f1631c7f2c2db5e614597b4284abc0118ea70',
'openspec-new-change': '27e09d43785953827efc9a98bb9d6cf06db48fe6abe7e1c049409fe5b5061323',
'openspec-continue-change': '1f92fad53022270e96f8ea34de75f7c12c08225edd5a9e8f4e864b63b5ef79c5',
'openspec-apply-change': '4bcd8c1dc3d0d86a2e4c605fc60d6ee54e0e0433f248c1d602c12927935e6963',
'openspec-apply-change': '991a1d4687f1c8c7147d8c3b68cf14e9c515c6c53bb026356dac3b80e909b827',
'openspec-ff-change': 'a7ab656d46f04d45dff0c8888df4a126a2e62288b7336f7445bce4d1715055f5',
'openspec-sync-specs': '3909936a236a21a9a6d5bf495f90b396b3b68fc9220d7b2c1894668653beb2e4',
'openspec-archive-change': '5f0d131a885dcdcd9ba2172ea9a42bc6748125e24b8c4eecb7c86f1a4aea83af',
Expand Down Expand Up @@ -1267,6 +1267,13 @@ describe('apply skill/command shared instruction core', () => {
expect(getApplyChangeSkillTemplate().instructions).toBe(core);
expect(getOpsxApplyCommandTemplate().content).toBe(core);
});

it('keeps task completion distinct from archive readiness (#1790)', () => {
const core = getApplyInstructions();
expect(core).toContain('All tracked tasks are complete');
expect(core).toMatch(/Review or verify the change as appropriate\s+before archiving/);
expect(core).not.toContain('All tasks complete! You can archive');
});
});

describe('workflow guidance matches the packaged templates (#1138)', () => {
Expand Down
Loading