@phuthuycoding/kanban-flow 0.3.0
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/LICENSE +21 -0
- package/README.md +173 -0
- package/dist/cli/args.js +219 -0
- package/dist/cli/commands/approve.js +44 -0
- package/dist/cli/commands/archive.js +245 -0
- package/dist/cli/commands/artifacts.js +100 -0
- package/dist/cli/commands/autoconfig.js +180 -0
- package/dist/cli/commands/cancel.js +129 -0
- package/dist/cli/commands/contexts.js +101 -0
- package/dist/cli/commands/doctor.js +35 -0
- package/dist/cli/commands/harness.js +60 -0
- package/dist/cli/commands/helpers.js +22 -0
- package/dist/cli/commands/init.js +119 -0
- package/dist/cli/commands/inspect.js +141 -0
- package/dist/cli/commands/new.js +80 -0
- package/dist/cli/commands/rules.js +69 -0
- package/dist/cli/commands/run.js +156 -0
- package/dist/cli/commands/stage.js +186 -0
- package/dist/cli/result.js +1 -0
- package/dist/dashboard/dashboard-view.js +238 -0
- package/dist/dashboard/dashboard.js +206 -0
- package/dist/harness/chain.js +41 -0
- package/dist/harness/config.js +168 -0
- package/dist/harness/prompt.js +105 -0
- package/dist/harness/run.js +245 -0
- package/dist/harness/session.js +78 -0
- package/dist/harness/supervise.js +65 -0
- package/dist/index.js +123 -0
- package/dist/integrations/agents.js +67 -0
- package/dist/integrations/hooks.js +59 -0
- package/dist/integrations/install.js +193 -0
- package/dist/project/bootstrap.js +358 -0
- package/dist/project/config.js +111 -0
- package/dist/project/contexts.js +98 -0
- package/dist/project/doctor.js +163 -0
- package/dist/shared/frontmatter.js +54 -0
- package/dist/shared/paths.js +78 -0
- package/dist/shared/time.js +5 -0
- package/dist/workflow/direction.js +56 -0
- package/dist/workflow/features.js +198 -0
- package/dist/workflow/findings.js +3 -0
- package/dist/workflow/schema.js +148 -0
- package/dist/workflow/secrets.js +52 -0
- package/dist/workflow/status.js +188 -0
- package/dist/workflow/validate-approval.js +25 -0
- package/dist/workflow/validate-artifacts.js +89 -0
- package/dist/workflow/validate-cancel.js +14 -0
- package/dist/workflow/validate-reports.js +121 -0
- package/dist/workflow/validate-traceability.js +91 -0
- package/dist/workflow/validate.js +73 -0
- package/docs/workflow/README.md +67 -0
- package/docs/workflow/artifacts.md +60 -0
- package/docs/workflow/cli-reference.md +78 -0
- package/docs/workflow/dashboard.md +35 -0
- package/docs/workflow/gates.md +103 -0
- package/docs/workflow/harness.md +144 -0
- package/docs/workflow/lifecycle.md +107 -0
- package/docs/workflow/skills.md +52 -0
- package/docs/workflow/source-layout.md +47 -0
- package/docs/workflow/state-machine.md +83 -0
- package/kanban-flow/review/rules/README.md +30 -0
- package/kanban-flow/review/rules/general.md +41 -0
- package/kanban-flow/review/rules/performance.md +29 -0
- package/kanban-flow/review/rules/security.md +32 -0
- package/kanban-flow/review/stacks/go.md +33 -0
- package/kanban-flow/review/stacks/java.md +38 -0
- package/kanban-flow/review/stacks/node.md +28 -0
- package/kanban-flow/review/stacks/php.md +30 -0
- package/kanban-flow/review/stacks/python.md +34 -0
- package/kanban-flow/review/stacks/ruby.md +32 -0
- package/kanban-flow/review/stacks/rust.md +33 -0
- package/kanban-flow/templates/phase-1-bug-report.md +76 -0
- package/kanban-flow/templates/phase-1-spec-requirement.md +67 -0
- package/kanban-flow/templates/phase-2-implementation-plan.md +85 -0
- package/kanban-flow/templates/phase-2-test-case.md +68 -0
- package/kanban-flow/templates/phase-2-use-case-diagram.md +18 -0
- package/kanban-flow/templates/phase-2-use-case-specification.md +33 -0
- package/kanban-flow/templates/phase-2-use-case.md +60 -0
- package/kanban-flow/templates/phase-4-testing-result.md +63 -0
- package/kanban-flow/templates/phase-5-review-report.md +68 -0
- package/kanban-flow/templates/phase-6-feature-report.md +78 -0
- package/package.json +63 -0
- package/skills/kanban-archive/SKILL.md +78 -0
- package/skills/kanban-brainstorm/SKILL.md +310 -0
- package/skills/kanban-bug/SKILL.md +55 -0
- package/skills/kanban-flow/SKILL.md +136 -0
- package/skills/kanban-implement/SKILL.md +72 -0
- package/skills/kanban-plan/SKILL.md +102 -0
- package/skills/kanban-review/SKILL.md +90 -0
- package/skills/kanban-test/SKILL.md +76 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { ARTIFACTS, STAGE_INDEX } from "./schema.js";
|
|
4
|
+
import { splitFrontmatter, isFilledFile } from "../shared/frontmatter.js";
|
|
5
|
+
import { finding } from "./findings.js";
|
|
6
|
+
/**
|
|
7
|
+
* Traceability for features from planning on: every use case has its own file
|
|
8
|
+
* matching the index, and every test case references FR/UC ids that exist.
|
|
9
|
+
*/
|
|
10
|
+
export function checkTraceability(feature) {
|
|
11
|
+
const issues = [];
|
|
12
|
+
if (STAGE_INDEX[feature.stage] < STAGE_INDEX.planning || feature.meta?.kind === "bug")
|
|
13
|
+
return issues;
|
|
14
|
+
const error = (file, code, message) => {
|
|
15
|
+
issues.push(finding(feature, "ERROR", file, code, message));
|
|
16
|
+
};
|
|
17
|
+
const tcFile = ARTIFACTS["test-cases"].file;
|
|
18
|
+
const ucIndexFile = ARTIFACTS["use-case-specification"].file;
|
|
19
|
+
const tcPath = join(feature.dir, tcFile);
|
|
20
|
+
const frPath = join(feature.dir, ARTIFACTS["spec-requirement"].file);
|
|
21
|
+
const ucPath = join(feature.dir, ucIndexFile);
|
|
22
|
+
const ucDir = join(feature.dir, "use-cases");
|
|
23
|
+
const ucFiles = existsSync(ucDir)
|
|
24
|
+
? readdirSync(ucDir).filter((file) => /^UC-\d+\.md$/i.test(file))
|
|
25
|
+
: [];
|
|
26
|
+
if (ucFiles.length === 0) {
|
|
27
|
+
error("use-cases/", "use_cases_missing", "Each use case must be written in its own use-cases/UC-###.md file.");
|
|
28
|
+
}
|
|
29
|
+
const fileIds = new Set(ucFiles.map((file) => file.slice(0, -3).toUpperCase()));
|
|
30
|
+
if (existsSync(ucPath)) {
|
|
31
|
+
const index = readFileSync(ucPath, "utf8");
|
|
32
|
+
const indexedIds = new Set([...index.matchAll(/\bUC-\d+\b/gi)].map((match) => match[0].toUpperCase()));
|
|
33
|
+
for (const id of indexedIds) {
|
|
34
|
+
if (!fileIds.has(id))
|
|
35
|
+
error(`use-cases/${id}.md`, "use_case_file_missing", `${id} is listed in the index but has no individual file.`);
|
|
36
|
+
}
|
|
37
|
+
for (const id of fileIds) {
|
|
38
|
+
if (!indexedIds.has(id))
|
|
39
|
+
error(ucIndexFile, "use_case_not_indexed", `${id} must be listed in the use-case index.`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (const file of ucFiles) {
|
|
43
|
+
const content = readFileSync(join(ucDir, file), "utf8");
|
|
44
|
+
const id = file.slice(0, -3).toUpperCase();
|
|
45
|
+
if (!isFilledFile(content, splitFrontmatter(content).body)) {
|
|
46
|
+
error(`use-cases/${file}`, "use_case_unfilled", `${file} is empty or still contains template placeholders.`);
|
|
47
|
+
}
|
|
48
|
+
if (!new RegExp(`\\b${id}\\b`, "i").test(content)) {
|
|
49
|
+
error(`use-cases/${file}`, "use_case_id_missing", `${file} must declare its matching ${id} identifier.`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (!existsSync(tcPath))
|
|
53
|
+
return issues;
|
|
54
|
+
const tcs = readFileSync(tcPath, "utf8");
|
|
55
|
+
const cases = [...tcs.matchAll(/^##\s+(TC-\d+)\b[^\n]*(?:\n|$)([\s\S]*?)(?=^##\s+TC-\d+\b|(?![\s\S]))/gm)];
|
|
56
|
+
if (cases.length === 0) {
|
|
57
|
+
error(tcFile, "no_test_cases", "Test cases must be defined in separate ## TC-XXX sections.");
|
|
58
|
+
}
|
|
59
|
+
const caseIds = new Set();
|
|
60
|
+
for (const [, id, body] of cases) {
|
|
61
|
+
if (caseIds.has(id.toUpperCase()))
|
|
62
|
+
error(tcFile, "duplicate_tc", `Duplicate test case ${id}.`);
|
|
63
|
+
caseIds.add(id.toUpperCase());
|
|
64
|
+
if (!/\bFR-\d+\b/i.test(body) || !/\bUC-\d+\b/i.test(body)) {
|
|
65
|
+
error(tcFile, "tc_refs_missing", `${id} must reference both a requirement (FR-XXX) and a use case (UC-XXX).`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (!/FR-\d+/i.test(tcs)) {
|
|
69
|
+
error(tcFile, "no_fr_refs", "test-cases has no requirement references (FR-XXX); traceability chain broken");
|
|
70
|
+
}
|
|
71
|
+
if (!/UC-\d+/i.test(tcs)) {
|
|
72
|
+
error(tcFile, "no_uc_refs", "test-cases has no use case references (UC-XXX); traceability chain broken");
|
|
73
|
+
}
|
|
74
|
+
if (existsSync(frPath)) {
|
|
75
|
+
const frDoc = readFileSync(frPath, "utf8");
|
|
76
|
+
const refs = [...tcs.matchAll(/\b(FR-\d+)\b/gi)].map((m) => m[1].toUpperCase());
|
|
77
|
+
const declared = new Set([...frDoc.matchAll(/\bFR-\d+\b/gi)].map((m) => m[0].toUpperCase()));
|
|
78
|
+
const missing = [...new Set(refs)].filter((r) => !declared.has(r));
|
|
79
|
+
if (missing.length > 0) {
|
|
80
|
+
error(tcFile, "fr_ref_missing", `test-cases reference requirements not in spec-requirement: ${missing.join(", ")}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (existsSync(ucPath) || ucFiles.length > 0) {
|
|
84
|
+
const refs = [...tcs.matchAll(/\b(UC-\d+)\b/gi)].map((m) => m[1].toUpperCase());
|
|
85
|
+
const missing = [...new Set(refs)].filter((r) => !fileIds.has(r));
|
|
86
|
+
if (missing.length > 0) {
|
|
87
|
+
error(tcFile, "uc_ref_missing", `test-cases reference use cases without individual files: ${missing.join(", ")}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return issues;
|
|
91
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { STAGES } from "./schema.js";
|
|
2
|
+
import { finding } from "./findings.js";
|
|
3
|
+
import { checkDueArtifacts, checkStageGate, checkSecrets } from "./validate-artifacts.js";
|
|
4
|
+
import { checkApproval, checkBypasses } from "./validate-approval.js";
|
|
5
|
+
import { checkTasks, checkTestingResult, checkReviewReport, checkDonesArtifacts } from "./validate-reports.js";
|
|
6
|
+
import { checkTraceability } from "./validate-traceability.js";
|
|
7
|
+
import { checkCancellation } from "./validate-cancel.js";
|
|
8
|
+
export { findSecretLike } from "./secrets.js";
|
|
9
|
+
export { checkDirectionGate } from "./direction.js";
|
|
10
|
+
export { STAGES };
|
|
11
|
+
/** Checks for the CURRENT stage. If the feature can leave the current stage, all its gate artifacts must exist & be filled. */
|
|
12
|
+
export function validateFeature(feature, strict = false, requireApproval = true) {
|
|
13
|
+
const issues = [];
|
|
14
|
+
if (!feature.meta) {
|
|
15
|
+
issues.push(finding(feature, "ERROR", ".kfw.json", feature.metaError ? "metadata_invalid" : "metadata_missing", feature.metaError ?? "Feature metadata is required for approval and execution tracking."));
|
|
16
|
+
}
|
|
17
|
+
// A cancelled item is asked for no artifact, no approval and no report. `STAGE_INDEX = -1`
|
|
18
|
+
// already makes most of those checks inert, but one that compares no index is not covered by
|
|
19
|
+
// that trick, and it made an item cancelled out of brainstorm permanently invalid — including
|
|
20
|
+
// the reopen command `kf cancel` itself prints. Deciding it here rather than inside each check
|
|
21
|
+
// means a check added later cannot reintroduce the trap by forgetting a guard.
|
|
22
|
+
//
|
|
23
|
+
// The bypass trail is deliberately NOT skipped: a recorded --force is an audit record about
|
|
24
|
+
// what someone did, not a demand on the item, and three places promise it shows up on every
|
|
25
|
+
// validation. Everything else is, including the `no_tasks` warning.
|
|
26
|
+
//
|
|
27
|
+
// Secrets are the one thing every stage owes, cancelled included. checkSecrets therefore sits
|
|
28
|
+
// OUTSIDE the branch, so neither side can drop it: it used to live inside checkDueArtifacts,
|
|
29
|
+
// where `STAGE_INDEX = -1` skipped it along with everything else, and cancelling an item was
|
|
30
|
+
// the quietest way to take a committed token off the radar while leaving it in the repo.
|
|
31
|
+
issues.push(...checkSecrets(feature));
|
|
32
|
+
issues.push(...(feature.stage === "cancelled"
|
|
33
|
+
? [...checkCancellation(feature), ...checkBypasses(feature)]
|
|
34
|
+
: [
|
|
35
|
+
...checkDueArtifacts(feature),
|
|
36
|
+
...checkStageGate(feature),
|
|
37
|
+
...checkApproval(feature, requireApproval),
|
|
38
|
+
...checkBypasses(feature),
|
|
39
|
+
...checkTasks(feature),
|
|
40
|
+
...checkTestingResult(feature),
|
|
41
|
+
...checkReviewReport(feature),
|
|
42
|
+
...checkTraceability(feature),
|
|
43
|
+
...checkDonesArtifacts(feature),
|
|
44
|
+
]));
|
|
45
|
+
const hasErrors = issues.some((i) => i.severity === "ERROR");
|
|
46
|
+
const hasWarnings = issues.some((i) => i.severity === "WARNING");
|
|
47
|
+
return {
|
|
48
|
+
feature: feature.name,
|
|
49
|
+
stage: feature.stage,
|
|
50
|
+
valid: !hasErrors && !(strict && hasWarnings),
|
|
51
|
+
issues,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function renderValidateText(r) {
|
|
55
|
+
const lines = [];
|
|
56
|
+
if (r.issues.length === 0) {
|
|
57
|
+
lines.push(`✓ ${r.feature} (stage ${r.stage}) — valid`);
|
|
58
|
+
return lines.join("\n");
|
|
59
|
+
}
|
|
60
|
+
lines.push(`✗ ${r.feature} (stage ${r.stage}) — ${r.valid ? "warnings" : "invalid"}`);
|
|
61
|
+
for (const i of r.issues) {
|
|
62
|
+
lines.push(` [${i.severity}] ${i.file}: ${i.message} (${i.code})`);
|
|
63
|
+
}
|
|
64
|
+
return lines.join("\n");
|
|
65
|
+
}
|
|
66
|
+
export function validateToJson(r) {
|
|
67
|
+
return {
|
|
68
|
+
feature: r.feature,
|
|
69
|
+
stage: r.stage,
|
|
70
|
+
valid: r.valid,
|
|
71
|
+
issues: r.issues,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Kanban Flow Workflow
|
|
2
|
+
|
|
3
|
+
`kanban-flow` drives a feature's life cycle through the `kf` CLI and the phase skills:
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
brainstorm → planning → implementation → testing → review → dones
|
|
7
|
+
↘ backlog ↗
|
|
8
|
+
|
|
9
|
+
any stage ──kf cancel──→ cancelled ──back to the stage it stopped in──→ (resumes)
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The pipeline exists to turn an idea into an approved execution contract, then execute it with traceability, and test and review the right version of it before archiving.
|
|
13
|
+
|
|
14
|
+
Features and bugs share one state machine. Create a bug with `kf new <name> --type bug`; it goes through `kanban-bug` for triage and reproduction before it reaches planning.
|
|
15
|
+
|
|
16
|
+
## Where to start
|
|
17
|
+
|
|
18
|
+
1. [Lifecycle](lifecycle.md) — who does what, and in what order.
|
|
19
|
+
2. [State machine](state-machine.md) — the states and the transitions each one allows.
|
|
20
|
+
3. [Gates](gates.md) — artifacts, approval, execution ids and report status.
|
|
21
|
+
4. [Artifact contract](artifacts.md) — file structure, traceability and the canonical output.
|
|
22
|
+
5. [CLI reference](cli-reference.md) — the command syntax an agent uses to move state.
|
|
23
|
+
6. [Skill routing](skills.md) — which skill loads in which state.
|
|
24
|
+
7. [Dashboard](dashboard.md) — the KPIs, the charts, the filters and what each number means.
|
|
25
|
+
8. [Agent harness](harness.md) — the stage → role → runner mapping behind `kf run`, `kf runs` and `kf harness`.
|
|
26
|
+
9. [Source layout](source-layout.md) — the shape of `src/` and how to extend it.
|
|
27
|
+
|
|
28
|
+
## The rules that never bend
|
|
29
|
+
|
|
30
|
+
- Never move a folder by hand; use `kf stage`, `kf cancel` or `kf archive`.
|
|
31
|
+
- `kf cancel` is the second way out. It needs `--reason`, moves the item to `.works/cancelled/`, and the only way back is the stage it stopped in.
|
|
32
|
+
- The requirement or bug report must be `status: confirmed` before it leaves brainstorm.
|
|
33
|
+
- Once planning is approved, the user chooses to start now or to send the item to `backlog`.
|
|
34
|
+
- Planning needs human approval. A feature's fingerprint covers the requirement, the four planning artifacts and every UC file; a bug's fingerprint covers only the bug report.
|
|
35
|
+
- Editing the execution contract after approval forces a return to planning and a fresh approval.
|
|
36
|
+
- Every entry into testing mints a new execution id. The testing and review reports must reference that exact id.
|
|
37
|
+
- A FAIL or a REJECT returns to implementation and must be tested again. BLOCKED stops the pipeline.
|
|
38
|
+
- REQUIREMENT_BUG stops every ordinary transition so the user can decide.
|
|
39
|
+
- The feature report must be written before archive; the CLI syncs the canonical docs when a feature is archived. A bug only updates the related docs when there is a docs impact.
|
|
40
|
+
|
|
41
|
+
One rule in that list is not like the others: the pipeline granting itself no access to a database, a deployment, a publish or a message is a **policy carried in the skill prompts**, not a gate. Nothing in `src/` enforces it, and the runner presets start workers with edits auto-accepted. It bends exactly as far as the worker does.
|
|
42
|
+
|
|
43
|
+
## Filesystem model
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
project/
|
|
47
|
+
├── .kf/
|
|
48
|
+
│ ├── config.json
|
|
49
|
+
│ ├── templates/
|
|
50
|
+
│ ├── hooks/
|
|
51
|
+
│ └── review/rules/
|
|
52
|
+
├── .works/
|
|
53
|
+
│ ├── brainstorm/
|
|
54
|
+
│ ├── planning/
|
|
55
|
+
│ ├── backlog/
|
|
56
|
+
│ ├── implementation/
|
|
57
|
+
│ ├── testing/
|
|
58
|
+
│ ├── review/
|
|
59
|
+
│ ├── cancelled/
|
|
60
|
+
│ └── dones/
|
|
61
|
+
└── docs/
|
|
62
|
+
├── requirement/{context}/{feature}.md
|
|
63
|
+
├── use-cases/{context}/{feature}/README.md + UC-###.md + diagram.md
|
|
64
|
+
└── testplan/{context}/{feature}{,-result}.md
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Each work item folder is named `{feature}_{YYYYMMDD_HHmm}` and carries a `.kfw.json`. The standard artifacts all use the `phase-{number}-` prefix.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# The artifact contract and how to read it
|
|
2
|
+
|
|
3
|
+
Artifacts are written inside the work item folder under `.works/`. Each file answers a different question; never use one report in place of another phase's.
|
|
4
|
+
|
|
5
|
+
## Reading order inside a work item
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
phase-1-spec-requirement.md
|
|
9
|
+
├── phase-2-implementation-plan.md (feature only)
|
|
10
|
+
├── phase-2-use-case-specification.md (feature only: index + coverage)
|
|
11
|
+
├── use-cases/UC-###.md (feature only: one file per UC)
|
|
12
|
+
├── phase-2-use-case-diagram.md (feature only)
|
|
13
|
+
└── phase-2-test-case.md (feature only: the test contract)
|
|
14
|
+
└── phase-4-testing-result.md (the outcome of one execution)
|
|
15
|
+
└── phase-5-review-report.md (review of that same execution)
|
|
16
|
+
└── phase-6-feature-report.md (feature only: the handover)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
A bug uses the `phase-1-bug-report.md` template but still stores its triage record at `phase-1-spec-requirement.md` so the CLI keeps working. Beyond that record a bug needs only the testing and review reports; the planning set and the feature report are not required. If behaviour appears beyond the scope of the defect fix, report the scope change and let the user decide whether a separate feature is warranted.
|
|
20
|
+
|
|
21
|
+
`phase-2-use-case-specification.md` is only an index. A feature's narrative belongs in `use-cases/UC-###.md`, and the ID in the file name must match the ID declared inside it. Every test case must trace `FR-###` → `UC-###`.
|
|
22
|
+
|
|
23
|
+
## Shared conventions
|
|
24
|
+
|
|
25
|
+
| Convention | What it means |
|
|
26
|
+
|---|---|
|
|
27
|
+
| Frontmatter | Identifies the work item, its context, its status and the current execution |
|
|
28
|
+
| Placeholder | Lives only in the template; every one must be replaced with real content before a gate |
|
|
29
|
+
| ID | `FR-###`, `UC-###`, `TC-###`, used consistently across every artifact |
|
|
30
|
+
| Report status | Testing: `PASS/FAIL/REJECT/BLOCKED`; review: `PASS/FAIL/REJECT/REQUIREMENT_BUG` |
|
|
31
|
+
| Execution | Testing and review must carry the same `executionId` as the current run |
|
|
32
|
+
| Summary tables | Totals must match the detail rows, not merely describe them |
|
|
33
|
+
|
|
34
|
+
The CLI checks the files, the placeholders, secret-like content, ID references, the approval fingerprint and each report's execution and status. Table totals, measured coverage and the quality of the narrative are the agent's job during planning, testing and review; a passing validator proves none of them.
|
|
35
|
+
|
|
36
|
+
## On archive into `dones`
|
|
37
|
+
|
|
38
|
+
`kf archive` leaves the artifact set in `.works/dones/{feature}_{timestamp}/` for audit. For a feature, the CLI copies the documents people actually read into the canonical docs:
|
|
39
|
+
|
|
40
|
+
| Canonical doc | Contents |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `docs/requirement/{context}/{feature}.md` | The archived requirement |
|
|
43
|
+
| `docs/use-cases/{context}/{feature}/README.md` | The UC index and coverage |
|
|
44
|
+
| `docs/use-cases/{context}/{feature}/UC-###.md` | Each use case narrative |
|
|
45
|
+
| `docs/use-cases/{context}/{feature}/diagram.md` | The actor and use case diagram |
|
|
46
|
+
| `docs/testplan/{context}/{feature}.md` | The test plan and the coverage matrix |
|
|
47
|
+
| `docs/testplan/{context}/{feature}-result.md` | The most recent execution result |
|
|
48
|
+
|
|
49
|
+
For a bug, archive neither creates nor overwrites an existing feature's docs. The archive skill updates the related docs only when the bug report states a docs impact; when there is none, it says "No documentation update required" in the closure or review.
|
|
50
|
+
|
|
51
|
+
Archiving a feature that is already in `dones` refuses to overwrite canonical docs that have changed since the snapshot, so updates from a bug or from extra documentation survive. Use `--skip-specs` to leave the docs alone; use `--force` only when restoring the old snapshot is what you actually want.
|
|
52
|
+
|
|
53
|
+
## Checklist before closing
|
|
54
|
+
|
|
55
|
+
- [ ] The requirement or bug report is `confirmed` and free of placeholders.
|
|
56
|
+
- [ ] Feature: four planning artifacts, one file per UC, and a test matrix whose IDs line up.
|
|
57
|
+
- [ ] Bug: a triage record carrying the reproduction, the severity and the regression strategy.
|
|
58
|
+
- [ ] Testing and review both `PASS`, on the current execution.
|
|
59
|
+
- [ ] The feature report records what changed, which tests ran, which docs moved and what limits remain. Not required for a bug.
|
|
60
|
+
- [ ] Canonical docs synced where needed, and no database, deploy or publish action outside the approved scope.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# CLI reference
|
|
2
|
+
|
|
3
|
+
The binary is `kf`. Every command *except* `kf init` looks for `.works/` from the current directory upwards to the project root, so you can run it from the root or from any subdirectory.
|
|
4
|
+
|
|
5
|
+
`kf init` is the exception: it resolves its path argument against the current directory and does not search upwards. Running it inside a subdirectory of a project that is already initialised creates a second `.works/`, `.kf/` and skills set there rather than finding the existing one.
|
|
6
|
+
|
|
7
|
+
## Setting up and creating work
|
|
8
|
+
|
|
9
|
+
| Command | What it does |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| `kf init [path]` | Onboarding. On a TTY it asks for the context, the stack, the reviewer, the agents, the gitignore entry and whether to seed a demo feature; without a TTY it takes the defaults. Creates `.works/`, `docs/{requirement,use-cases,testplan}` and `.kf`, installs the project-scope skills, and seeds `AGENTS.md` when neither `AGENTS.md` nor `CLAUDE.md` exists. |
|
|
12
|
+
| `kf init --defaults` | Non-interactive onboarding on default values, for agents and scripts. |
|
|
13
|
+
| `kf init --minimal` | Skips the questions, not the scaffolding. Creates `.works/`, the docs roots, the skills, `.kf/config.json` with the schema and the runner presets, the empty `.kf/{templates,hooks,review/rules}` directories, and `AGENTS.md` when neither `AGENTS.md` nor `CLAUDE.md` exists. What it does *not* do is copy template, hook or review-rule files into those directories — the full path does that. With `--context` on a genuinely new project it declares that context, exactly as the full path does. |
|
|
14
|
+
| `kf new <feature> [--context <ctx>] [--goal <text>] [--type feature\|bug]` | Creates a feature or bug in `brainstorm`; a bug routes through `kanban-bug`. Feature and context names must match `[a-z0-9][a-z0-9_-]*` **case-insensitively**, so `LoginFlow` is accepted. Context names are then compared case-insensitively against the declared list, which refuses `Auth` beside `auth`. When the project declares contexts, an undeclared one is refused with the nearest declared name. |
|
|
15
|
+
| `kf list [--json]` | Lists every work item with its kind and state. |
|
|
16
|
+
| `kf doctor [--json]` | Diagnoses the project rather than a work item: stage directories, a config that parses, work item metadata that can be read, skills still installed, and config fields that no longer mean what they say. Read-only, keeps going after the first problem, and exits 1 when anything is at ERROR. Work items that are not valid are counted but never change the verdict — that is the normal state of a pipeline in motion. |
|
|
17
|
+
| `kf contexts [--json]` | Lists the declared contexts with a work-item count each, marks any context in use but not declared, and prints a survey brief when none are declared. Read-only. See [contexts](#contexts). |
|
|
18
|
+
| `kf show <feature> [--json]` | Shows a work item's requirement or bug report. |
|
|
19
|
+
| `kf view [--json]` | Workflow statistics in the terminal; the JSON carries metrics, charts and the per-stage detail. |
|
|
20
|
+
| `kf dashboard [--port <1-65535>]` | KPI and chart dashboard with context and kind filters, on port `8787` by default. See [how each number is computed](dashboard.md). |
|
|
21
|
+
|
|
22
|
+
## Driving the workflow
|
|
23
|
+
|
|
24
|
+
| Command | What it does |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| `kf status --change <feature> [--json]` | One work item's state, including how many gate or hook bypasses have been recorded, and any blocking findings the validator raises. The artifact checklist only says which files exist and are filled; the blocking list is what `kf approve` or `kf stage` would refuse on, so the two cannot disagree. The human approval gate is reported by the `Approval:` field rather than counted as a blocker. |
|
|
27
|
+
| `kf status --all [--json]` | Every work item, `backlog` and `dones` included. |
|
|
28
|
+
| `kf instruct <artifact\|use-case> [--change <feature>] [--id UC-###] [--json]` | Renders an artifact template; `use-case` produces the instruction for exactly one `use-cases/UC-###.md`. |
|
|
29
|
+
| `kf templates [--json]` | Lists the templates currently resolved and where each came from. |
|
|
30
|
+
| `kf validate --change <feature> [--strict] [--json]` | Checks artifacts, placeholders, secret-like content, traceability and the gates. Exits `1` on failure. |
|
|
31
|
+
| `kf validate --all [--strict] [--json]` | Validates every work item. |
|
|
32
|
+
| `kf approve <feature> [--by <name>]` | The human gate on the execution contract in planning; records the approver, the moment and the contract hash. |
|
|
33
|
+
| `kf stage <feature> <next-stage> [--force] [--skip-hooks]` | Performs a legal transition and runs the destination state's hook. Planning may go to `backlog` or to `implementation`; `dones` is reached through archive. |
|
|
34
|
+
| `kf cancel <feature> --reason "<why>" [--by <name>] [--purge-docs] [--force] [--skip-hooks]` | Stops a work item for good and moves it to `.works/cancelled/`, recording `cancellation { at, by, reason, fromStage }`. Refuses while a run is live unless `--force`. An item in `dones` has its canonical docs listed, and only `--purge-docs` deletes them, asking first on a TTY; `--force` answers that question in advance, and without a TTY it is the only way through. Reopen with `kf stage <feature> <fromStage>`. |
|
|
35
|
+
| `kf archive <feature> [--force] [--skip-specs] [--skip-hooks]` | Archives from review into dones and updates the metadata; a feature receives the canonical copies, a bug keeps its existing docs. |
|
|
36
|
+
| `kf rules [--stack <id> ...] [--list] [--force]` | Copies the stack best-practice review rules into `.kf/review/rules/`. Detects the stacks automatically, installing several packs in a monorepo; `--list` shows the packs and `--force` overwrites files you have edited. |
|
|
37
|
+
| `kf autoconfig` | Prints a briefing for an agent on stdout: the project context, a config checklist of what is done and what is missing with the command to fix it, the effective review rules and the workflow guide, so the agent can configure the project itself. |
|
|
38
|
+
| `kf run <feature> [--stage <s>] [--role <r>] [--fresh] [--detach] [--timeout <minutes>] [--dry-run]` | Runs, in order, the role chain that `harness.stages` assigns to the current stage. Records a `runs[]` entry per role and resumes the session per work item and role. A role that does not finish `DONE` stops the chain. `--detach` returns immediately and leaves a supervisor to finish. Exits 1 when the chain does not complete. See [harness](harness.md). |
|
|
39
|
+
| `kf runs [<feature>] [--json]` | Worker run history with role, runner, stage, mode, status and STATUS line, newest first. |
|
|
40
|
+
| `kf harness [--json]` | The harness in effect: the main role, stage to role chain, role to runner with its brief and output, and which runner CLIs are on PATH. |
|
|
41
|
+
|
|
42
|
+
`--force` deliberately skips a gate; when re-archiving a work item in `dones` it also allows the archive snapshot to overwrite canonical docs that were edited. `--skip-hooks` skips the destination phase's hook. `--skip-specs` touches no canonical doc during archive. Whenever `--force` or `--skip-hooks` actually skips something, the CLI writes a record into `.kfw.json` under `bypasses[]` and says so in its output. See [gates](gates.md#force-and-recovery).
|
|
43
|
+
|
|
44
|
+
## Skill installation
|
|
45
|
+
|
|
46
|
+
Skills always live at **project scope** (`{root}/.claude/skills`, `{root}/.agents/skills` and so on). The `kf` CLI is the only thing installed globally, through `npm link`. `kf init` installs the skills during setup; `kf install` and `kf uninstall` work on the project root resolved from the nearest `.works/` above the working directory. Neither writes anything into `~/`.
|
|
47
|
+
|
|
48
|
+
| Command | What it does |
|
|
49
|
+
| --- | --- |
|
|
50
|
+
| `kf install [--agent <id> ...]` | Installs the 8 skills into each agent's own directory, defaulting to `claude`. Must run inside a kanban project, which means a `.works/` exists; run `kf init` first if it does not. The directory is `.claude/skills`, `.gemini/skills`, `.kiro/skills`, `.cursor/skills`, `.opencode/skills` — and `.agents/skills` for `codex`, which follows the open standard rather than its own name. An unknown agent also falls back to `.agents/skills`. |
|
|
51
|
+
| `kf uninstall [--agent <id> ...] [--purge] [--force]` | Removes exactly the 8 skills that kanban-flow manages, leaving every other skill alone. `--purge` also deletes `.works/`, `.kf/` and `docs/{requirement,use-cases,testplan}/`, asking first on a TTY and requiring `--force` without one. |
|
|
52
|
+
|
|
53
|
+
Uninstall only removes skills. To take the CLI off PATH: `npm rm -g @phuthuycoding/kanban-flow`.
|
|
54
|
+
|
|
55
|
+
## Error conventions
|
|
56
|
+
|
|
57
|
+
- Success exits `0`. Bad input, a failed gate, a failed hook, a missing work item or an exception exits `1`. The readable report goes to **stdout**; stderr carries only a short reason line. A CI step that keeps stderr and discards stdout captures the reason but none of the detail.
|
|
58
|
+
- The CLI never runs a migration, updates a database, deploys or publishes on its own.
|
|
59
|
+
- Hooks resolve in order: the project `.kf/hooks`, then the user's `~/.kf/hooks`, then the package hooks. The environment handed to a hook carries `KFW_FEATURE`, `KFW_CONTEXT`, `KFW_FROM_STAGE`, `KFW_TO_STAGE`, `KFW_FEATURE_DIR`, `KFW_WORK_ROOT` and `KFW_APPROVAL`.
|
|
60
|
+
|
|
61
|
+
## Contexts
|
|
62
|
+
|
|
63
|
+
A context groups work items and their canonical docs by business domain: `docs/requirement/{context}/`, and the same under `use-cases` and `testplan`.
|
|
64
|
+
|
|
65
|
+
A project may declare which contexts exist, in `.kf/config.json`:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
"contexts": ["auth", "billing", "catalog"]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Two things follow from that list, and nothing follows without it:
|
|
72
|
+
|
|
73
|
+
- **The first entry is the default context** for `kf new` without `--context`. There is no separate default field to keep in step with the list. `defaultContext` is still read for projects created before `contexts` existed, and is ignored once a list is declared.
|
|
74
|
+
- **`kf new` refuses a context that is not on the list**, naming the nearest declared spelling. A name differing only in case is refused too, because accepting `Auth` beside `auth` is how a second docs tree appears on a case-sensitive filesystem.
|
|
75
|
+
|
|
76
|
+
A project with no `contexts` key is unrestricted. Re-running `kf init` there does not add the key, and neither does a project that has work items but no config file yet: a project counts as existing if it has either. `kf init` writes the list only for a genuinely new project, or when you answer its question on a terminal. The one behaviour that did change for an unrestricted project: `kf new` now reads the config on every path, so a malformed config fails loudly instead of only when `--context` was omitted.
|
|
77
|
+
|
|
78
|
+
`kf contexts` reports each in-use context with the spelling found on disk, not a lowercased one. Where an undeclared spelling differs from a declared one only by case, it says so instead of telling you to add it, because the config reader refuses that repeat: rename the work items, or change the declared entry. It never writes anything. When no list is declared it prints a brief for an agent to survey the repo and propose one, which a human then confirms and writes.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Dashboard metrics and charts
|
|
2
|
+
|
|
3
|
+
Run `kf dashboard` and open `http://localhost:8787`. Change the port with `--port`. The dashboard refreshes every 5 seconds, has a manual refresh button and filters by context and by work item kind.
|
|
4
|
+
|
|
5
|
+
## KPI
|
|
6
|
+
|
|
7
|
+
| Metric | How it is computed |
|
|
8
|
+
|---|---|
|
|
9
|
+
| Work items | Every feature and bug matching the filter, `dones` included |
|
|
10
|
+
| In execution | Items in `implementation`, `testing` or `review` |
|
|
11
|
+
| Backlog | Items in `backlog` |
|
|
12
|
+
| Completed | Items in `dones`; the rate is dones divided by total items **minus cancelled ones** |
|
|
13
|
+
| Cancelled | Items in `cancelled`; shown so the gap in the completion rate's denominator is visible |
|
|
14
|
+
| Gate bypasses | Items carrying a recorded `--force` or `--skip-hooks` |
|
|
15
|
+
| Task progress | Completed checkboxes divided by all checkboxes across the items in execution |
|
|
16
|
+
|
|
17
|
+
With no items or no tasks to divide by, the figure shows as `—`. An item in execution with no task checkboxes is counted separately and never defaults to done. Task progress is not a test pass rate and not code coverage.
|
|
18
|
+
|
|
19
|
+
## Charts
|
|
20
|
+
|
|
21
|
+
- Bars by stage: the total per state and the feature/bug split within it.
|
|
22
|
+
- Feature and bug donut: the share of each work item kind under the current filter.
|
|
23
|
+
- Bars by context: item volume across contexts, ordered by total, largest first.
|
|
24
|
+
- Approval bars: pending, approved and changed. The filter excludes exactly two stages, `brainstorm` and `dones` — so besides planning through review and backlog, **cancelled items are counted too**, and a cancelled item that never reached approval lands in the pending column.
|
|
25
|
+
- Task progress bar: tasks done, items that have tasks and items that do not, across the stages in execution.
|
|
26
|
+
|
|
27
|
+
The charts show the filesystem as it is right now. The workflow keeps no history of stage transitions, so the dashboard infers no throughput, no lead time and no trend over time from these counts.
|
|
28
|
+
|
|
29
|
+
## CLI and API
|
|
30
|
+
|
|
31
|
+
`kf view` prints the same summary in the terminal. `kf view --json` and `/api/data` return `metrics`, `charts`, `availableContexts` and `stages`, so existing agents and tools can still read it.
|
|
32
|
+
|
|
33
|
+
The API takes `?kind=feature|bug&context=<slug>`. Drop a parameter to see everything. `context=__none__` selects older items that carry no context. The context list behind the filter is always drawn from the whole project.
|
|
34
|
+
|
|
35
|
+
When the API fails, the dashboard says so and keeps the previous snapshot with a warning that the numbers may be stale. It never turns an error into a zero.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Gates and the artifact contract
|
|
2
|
+
|
|
3
|
+
A gate is checked on the way out of the current state. `kf validate` runs most of the same checks so you see the failures early; `kf stage` and `kf archive` refuse the transition when a gate does not hold.
|
|
4
|
+
|
|
5
|
+
One group is not shared: the *direction* gate, which decides where a PASS or FAIL report may send an item. `validateFeature` does not call it, so `tasks_incomplete` and `testing_already_pass` never appear in `kf validate` and first surface when `kf stage` refuses the move. A clean `kf validate` is therefore not a promise that the next transition will be allowed.
|
|
6
|
+
|
|
7
|
+
## Required artifacts
|
|
8
|
+
|
|
9
|
+
| Phase | File | Minimum contents | Unlocks |
|
|
10
|
+
| --- | --- | --- | --- |
|
|
11
|
+
| 1 — Brainstorm / bug triage | `phase-1-spec-requirement.md`, a bug using the bug-report template | Feature: the requirement plus FR-XXX. Bug: reproduction, actual against expected, severity, regression strategy | Planning |
|
|
12
|
+
| 2 — Planning (feature) | `phase-2-implementation-plan.md` | Scope, tasks, impact, definition of done, risks | The execution contract |
|
|
13
|
+
| 2 — Planning (feature) | `phase-2-use-case-specification.md` plus `use-cases/UC-###.md` | Index and coverage in the phase file; each UC carries its own preconditions, flows and alternate or error flows | Design and testing |
|
|
14
|
+
| 2 — Planning (feature) | `phase-2-use-case-diagram.md` | A valid actor and use case diagram | Traceability |
|
|
15
|
+
| 2 — Planning (feature) | `phase-2-test-case.md` | TC-XXX entries linked to FR-XXX and UC-XXX | The testing contract |
|
|
16
|
+
| 4 — Testing | `phase-4-testing-result.md` | The current execution id, a PASS/FAIL/REJECT/BLOCKED verdict, the evidence | Review, or the repair loop |
|
|
17
|
+
| 5 — Review | `phase-5-review-report.md` | The current execution id, a PASS/FAIL/REJECT/REQUIREMENT_BUG verdict, the findings | Archive, or the repair loop |
|
|
18
|
+
| 6 — Artifact (feature) | `phase-6-feature-report.md` | The summary, what changed, the tests, the docs, the known limits | A finished feature |
|
|
19
|
+
|
|
20
|
+
Implementation has no required artifact of its own in the schema, but the implement skill must finish the tasks in the plan and leave the code in a state that can be tested.
|
|
21
|
+
|
|
22
|
+
## Canonical output on entering `dones`
|
|
23
|
+
|
|
24
|
+
`kf archive` copies from the work item folder to stable paths under the context. Only a feature gets its canonical docs copied automatically:
|
|
25
|
+
|
|
26
|
+
| Source | Destination |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| `phase-1-spec-requirement.md` | `docs/requirement/{context}/{feature}.md` |
|
|
29
|
+
| `phase-2-use-case-specification.md` | `docs/use-cases/{context}/{feature}/README.md`, the index |
|
|
30
|
+
| `use-cases/UC-###.md` | `docs/use-cases/{context}/{feature}/UC-###.md`, one file per use case |
|
|
31
|
+
| `phase-2-use-case-diagram.md` | `docs/use-cases/{context}/{feature}/diagram.md` |
|
|
32
|
+
| `phase-2-test-case.md` | `docs/testplan/{context}/{feature}.md` |
|
|
33
|
+
| `phase-4-testing-result.md` | `docs/testplan/{context}/{feature}-result.md` |
|
|
34
|
+
|
|
35
|
+
The canonical requirement is marked `archived`; the other artifacts keep their frontmatter and evidence so they can be traced later. For a bug, archive only moves the work item into `dones`; the related feature's docs change only when the bug report states a docs impact. `--skip-specs` skips this whole table.
|
|
36
|
+
|
|
37
|
+
## What each direction requires
|
|
38
|
+
|
|
39
|
+
```mermaid
|
|
40
|
+
flowchart LR
|
|
41
|
+
B[brainstorm] -->|requirement confirmed| P[planning]
|
|
42
|
+
P -->|feature: 4 artifacts + approval<br/>bug: bug report + approval| I[implementation]
|
|
43
|
+
I -->|implementation complete + tasks done| T[testing]
|
|
44
|
+
T -->|PASS + current execution| R[review]
|
|
45
|
+
T -->|FAIL/REJECT| I
|
|
46
|
+
R -->|PASS + current execution<br/>feature additionally requires feature report| D[dones]
|
|
47
|
+
R -->|FAIL/REJECT| I
|
|
48
|
+
T -->|scope change| P
|
|
49
|
+
R -->|scope change| P
|
|
50
|
+
P -->|hold: no gate| BL[backlog]
|
|
51
|
+
BL -->|start: same gate as planning| I
|
|
52
|
+
BL -->|scope change| P
|
|
53
|
+
I -->|scope change| P
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`implementation → testing` is also blocked while `tasks.md` still holds an unfinished checkbox, which is the definition of done. `tasks.md` is not a required artifact: with no such file, this gate does not apply.
|
|
57
|
+
|
|
58
|
+
## Contract and traceability
|
|
59
|
+
|
|
60
|
+
Feature planning builds a chain you can follow:
|
|
61
|
+
|
|
62
|
+
`FR-XXX` → `UC-XXX` → `TC-XXX` → implementation → testing evidence → review finding.
|
|
63
|
+
|
|
64
|
+
IDs must match exactly; `FR-001` is never treated as `FR-0010`. A TC missing its FR or UC reference, a reference that does not exist, a duplicate TC id, an empty file or an unreplaced placeholder all fail validation. The agent still has to review the content of each section and the totals in each table.
|
|
65
|
+
|
|
66
|
+
The validator also scans artifact content for real secrets, such as a Bearer token, an API key, a private key or a password written as `KEY=value`, and fails with `artifact_secret` when it finds one. An artifact must never carry a credential. Placeholder values like `{key}`, `<token>`, `changeme`, `redacted` or a run of four or more `x` are not flagged. The exemption applies to the **captured value**, not to the whole line: `TOKEN=ghp_… # example` is still flagged. High-confidence formats (`ghp_`/`github_pat_`, `sk-`, `AKIA`, `xox*-`, a PRIVATE KEY header, a three-segment JWT starting `eyJ`, and Slack or Discord webhook URLs) are exempt only when the value itself is masked with `xxxx` or `****`. Each of those begins with something no honest template would invent, so no wording on the line excuses them.
|
|
67
|
+
|
|
68
|
+
A connection string carrying a password (`scheme://user:<password>@host`) is also flagged, with the password as the captured value — but it is **not** high-confidence, because it has no such marker: it is pure URL shape, which a template like `scheme://user:<password>@host` has too. It uses the ordinary placeholder exemption, so a real password is caught and an obvious placeholder is not. A URL with no password is never flagged; there is nothing to leak. The error message never echoes the secret.
|
|
69
|
+
|
|
70
|
+
The secret scan is the one check that ignores the stage entirely. It runs on **every artifact that exists on disk**, whether or not the workflow has reached the phase that asks for that file, and including items in `cancelled` — which sit at `STAGE_INDEX = -1` and are exempt from every other artifact check. A credential is a credential regardless of where the item stands, and cancelling an item must not be a way to take a committed token off the radar.
|
|
71
|
+
|
|
72
|
+
A testing report with `status: PASS` must also carry a table under the `## Commands and Evidence` heading with at least one command line and every Exit code cell equal to `0`; breaking that is `testing_exit_code`. The rule does not prove the tests ran. It only stops a PASS report that has no numeric evidence behind it. FAIL, REJECT and BLOCKED reports are not bound by it.
|
|
73
|
+
|
|
74
|
+
The Phase 2 approval is a SHA-256 fingerprint of the requirement, the four planning artifacts and every `use-cases/UC-###.md` for a feature; a bug's fingerprint covers the bug report alone. Editing the contract after approval forces a return to planning, a rewrite and a fresh approval.
|
|
75
|
+
|
|
76
|
+
## Cancelled
|
|
77
|
+
|
|
78
|
+
`cancelled` is the one stage with **no artifact gate**. Its `STAGE_INDEX` is `-1`, so every "is this artifact due yet" and "are we past planning" comparison comes out false, and the validator skips artifacts, approval, traceability and report semantics entirely. In exchange it has exactly one requirement of its own: `cancellation.reason` must not be empty, and a missing one is `cancellation_missing`.
|
|
79
|
+
|
|
80
|
+
`kf cancel` runs the `cancelled.sh` hook like any other transition, refuses while a worker run is live unless `--force`, and for an item in `dones` it **lists** the canonical docs rather than deleting them. Only `--purge-docs` deletes. On a TTY it asks first — unless `--force` is also given, which takes the confirmation as already granted; without a TTY, `--force` is the only way through. The deletion runs only **after** the work item has moved into `.works/cancelled/` successfully, so a failure during the move cannot lose documents. A cancelled item cannot be archived.
|
|
81
|
+
|
|
82
|
+
On the numbers: cancelled items are taken out of the denominator of `completionRate`, so dropping something does not dent the rate, and `kf runs` leaves out the runs of a dropped item unless you name it directly with `kf runs <feature>`, exactly as it treats an item in `dones`.
|
|
83
|
+
|
|
84
|
+
## Force and recovery
|
|
85
|
+
|
|
86
|
+
`--force` is a deliberate escape hatch for skipping validation or a directional gate. It does not belong in the normal flow, and when it is used the reason must be written into the review or the feature report.
|
|
87
|
+
|
|
88
|
+
Every time `--force` skips a gate that was actually failing, or `--skip-hooks` skips a hook that actually exists, `kf stage` and `kf archive` write a record into `.kfw.json`:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
"bypasses": [
|
|
92
|
+
{ "at": "20260919_1230", "from": "brainstorm", "to": "planning", "flag": "force", "codes": ["requirement_unconfirmed"] },
|
|
93
|
+
{ "at": "20260919_1231", "from": "planning", "to": "backlog", "flag": "skip-hooks", "codes": ["hook:/path/.kf/hooks/backlog.sh"] }
|
|
94
|
+
]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
A flag that skips nothing, because the gate passed or no hook exists, records nothing. `kf validate` raises the `gate_bypassed` warning, `kf status` prints `Bypasses: N`, and `kf view --json` and the dashboard count the work items carrying one. There is no command to erase a record. The limit is worth stating plainly: this is a trail for a human reviewer, not a guarantee, because an agent can still edit the JSON by hand.
|
|
98
|
+
|
|
99
|
+
- A phase hook fails: the transition is refused. Fix the hook, or use `--skip-hooks` once you understand what that skips.
|
|
100
|
+
- Testing or review comes back `FAIL` or `REJECT`: return to implementation, fix the code, then enter testing again for a new execution id.
|
|
101
|
+
- `BLOCKED`: stop and report the blocker. Never fake a PASS.
|
|
102
|
+
- `REQUIREMENT_BUG`: stop the feature and tell the user. Continue only on a clear decision from them about the scope or the requirement.
|
|
103
|
+
- Archive fails midway: the CLI returns the feature to review and restores the metadata and specs where it can. When the rollback is incomplete, the error says so plainly so it can be sorted out by hand.
|