@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,144 @@
|
|
|
1
|
+
# Multi-agent harness
|
|
2
|
+
|
|
3
|
+
A **role** does one job in the pipeline, and each role points at a **runner**: a CLI, a model and its permission flags. Stages are assigned to roles, never to vendors. Assign no stages and nothing changes: the main agent does everything itself.
|
|
4
|
+
|
|
5
|
+
## Why three layers
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
stage → role → runner
|
|
9
|
+
testing tester gemini (CLI + model + permission flags)
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
- **Stage to role almost never changes.** Testing always wants a tester, review always wants a reviewer. Write it once.
|
|
13
|
+
- **Role to runner is where you change your mind about a model.** Find one that writes better and `writer` becomes a one-line edit, with no stage touched.
|
|
14
|
+
- **Runner to CLI and flags** is what breaks when a vendor changes its interface. One broken runner does not take the rest down with it.
|
|
15
|
+
|
|
16
|
+
Every model is strong at something different: breadth of research, prose, code, review. A role is how you say "this job needs that strength" without hard-wiring a vendor's name into the pipeline.
|
|
17
|
+
|
|
18
|
+
## Why "resume the latest session" is never needed
|
|
19
|
+
|
|
20
|
+
kanban-flow keeps its state in files: `.works/`, the artifacts and `.kfw.json`. It never relies on what a conversation remembers. A worker for a stage is a fresh headless session whose context is that stage's skill plus the artifacts on disk. A session is kept **per work item and per role**, so the repair loop from FAIL back to implement continues in the session that did the work, and that id is either minted by kf or fetched deterministically, never guessed as "the latest". Two roles sharing one runner still get two separate sessions, so `coder` and `reviewer` on the same CLI never see each other's context.
|
|
21
|
+
|
|
22
|
+
## Config
|
|
23
|
+
|
|
24
|
+
The `harness` block in `.kf/config.json`, which `kf harness` displays. This example is a **hand-tuned** one, spreading roles across several runners. What `kf init` seeds is deliberately plainer: all six roles on the single agent you chose, and `"stages": {}` — so nothing is routed to a worker until you assign it:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
"harness": {
|
|
28
|
+
"main": "architect",
|
|
29
|
+
"roles": {
|
|
30
|
+
"architect": "claude-opus",
|
|
31
|
+
"researcher": { "runner": "codex", "brief": "Explores breadth: prior art, libraries, comparable features.", "output": "research.md" },
|
|
32
|
+
"writer": { "runner": "gemini", "brief": "Turns agreed decisions into precise prose." },
|
|
33
|
+
"coder": "claude-opus",
|
|
34
|
+
"tester": { "runner": "devin", "brief": "Runs the real suite and records exact commands and exit codes." },
|
|
35
|
+
"reviewer": "codex"
|
|
36
|
+
},
|
|
37
|
+
"stages": {
|
|
38
|
+
"brainstorm": ["researcher", "writer"],
|
|
39
|
+
"implementation": "coder",
|
|
40
|
+
"testing": "tester",
|
|
41
|
+
"review": "reviewer"
|
|
42
|
+
},
|
|
43
|
+
"runners": {
|
|
44
|
+
"claude-opus": {
|
|
45
|
+
"start": ["claude", "-p", "{prompt}", "--session-id", "{session}", "--permission-mode", "acceptEdits", "--output-format", "json"],
|
|
46
|
+
"resume": ["claude", "-p", "{prompt}", "-r", "{session}", "--permission-mode", "acceptEdits", "--output-format", "json"],
|
|
47
|
+
"session": "provided",
|
|
48
|
+
"usage": "json"
|
|
49
|
+
},
|
|
50
|
+
"codex": {
|
|
51
|
+
"start": ["codex", "exec", "--json", "{prompt}"],
|
|
52
|
+
"resume": ["codex", "exec", "resume", "{session}", "{prompt}"],
|
|
53
|
+
"session": { "stdout": "\"thread_id\":\"([^\"]+)\"" },
|
|
54
|
+
"usage": "json"
|
|
55
|
+
},
|
|
56
|
+
"devin": {
|
|
57
|
+
"start": ["devin", "-p", "{prompt}", "--permission-mode", "accept-edits"],
|
|
58
|
+
"resume": ["devin", "-p", "{prompt}", "-r", "{session}", "--permission-mode", "accept-edits"],
|
|
59
|
+
"session": { "command": ["devin", "list", "--format", "json"], "idField": "id", "matchField": "title" }
|
|
60
|
+
},
|
|
61
|
+
"gemini": { "start": ["gemini", "-p", "{prompt}", "--approval-mode", "auto_edit"] },
|
|
62
|
+
"opencode": { "start": ["opencode", "run", "{prompt}"] }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- `main`: the role the orchestrating agent plays. It must be a role, not a runner.
|
|
68
|
+
- `roles.<role>`: a runner name in short form, or `{ runner, brief?, output? }`.
|
|
69
|
+
- `brief`: a sentence or two describing the role, injected into the prompt so the worker knows what it was called for.
|
|
70
|
+
- `output`: an extra file the role must write inside the work item folder, such as `research.md`, for the next role to read. The path has to stay inside the work item folder.
|
|
71
|
+
- `stages.<stage>`: one role, or **an array of roles run in order**. The `backlog` stage cannot be assigned. Any stage left undeclared is handled by the main agent.
|
|
72
|
+
- `runners.<runner>`: see the table below. Permissions (`--permission-mode`, `--approval-mode`, `--sandbox`) live in the template; kf injects no flags of its own.
|
|
73
|
+
|
|
74
|
+
Adding a model means adding a runner and pointing a role at it. Two models on one CLI, such as `claude-opus` and `claude-haiku`, are two runners, assigned to the expensive role and the cheap one.
|
|
75
|
+
|
|
76
|
+
### Runner fields
|
|
77
|
+
|
|
78
|
+
| Field | What it means |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `start` | The argv for a fresh session. `{prompt}` is mandatory. `{session}` is allowed only under `session: "provided"`, where kf mints a UUID before running |
|
|
81
|
+
| `resume` | The argv to continue a stored session; it must contain `{session}`. Without it the role always starts fresh |
|
|
82
|
+
| `session` | `"provided"`, `{ "stdout": "<regex, group 1>" }`, or `{ "command", "idField", "matchField" }`, which runs a command returning a JSON array and picks the entry whose `matchField` contains the `kf-run:<id>` marker kf puts at the head of the prompt |
|
|
83
|
+
| `usage` | `"json"` parses `usage.input_tokens` and `usage.output_tokens`, plus `total_cost_usd` when present, from JSON on stdout |
|
|
84
|
+
| `skillsDir` | The runner's skills directory. Defaults follow `kf install`: `.claude/skills`, `.agents/skills` (codex), `.gemini/skills`, `.kiro/skills`, `.cursor/skills`, `.opencode/skills`, and any unfamiliar name falls back to `.agents/skills` |
|
|
85
|
+
| `resumeFailure` | A regex that recognises a failed resume; the default is `session\|not found\|no such\|unknown\|does not exist` |
|
|
86
|
+
|
|
87
|
+
### Presets, as verified on 2026-09-19
|
|
88
|
+
|
|
89
|
+
| Runner | Session | What was verified |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| claude | kf mints the UUID via `--session-id`, resumes with `-r`; usage and cost come from the JSON | Run for real: start and resume both work |
|
|
92
|
+
| codex | `thread_id` from the JSONL of `exec --json`, resumes with `exec resume <id>`; usage from `turn.completed` | Run for real: start and resume both work |
|
|
93
|
+
| devin | `devin list --format json` matched on `title` against the marker; resumes with `-r <id>` | Run for real: start, list and resume all work. Devin refuses an untrusted directory, so open `devin` interactively once inside the repo |
|
|
94
|
+
| gemini | no resume | Could not log in on the verification machine. `-r` accepts `latest` or an index; whether it accepts a UUID is unknown |
|
|
95
|
+
| opencode | no resume | How to obtain the id is unverified; `run -s <id>` does exist |
|
|
96
|
+
|
|
97
|
+
## Flow
|
|
98
|
+
|
|
99
|
+
1. Before each stage, the main agent, running the `kanban-flow` skill, reads `kf status --change <f> --json`. When `assignedRoles` is present it runs `kf run <f>`, adding `--detach` for a long stage such as implementation and then polling `kf runs <f>`.
|
|
100
|
+
2. `kf run` resolves the stage's role chain and runs it **in order**. Each role's prompt carries: the role and its `brief`, the work item, the stage, the folder, the path to that runner's phase `SKILL.md`, pointers to `kf status` and `kf instruct`, the requirement to write `output` when the role has one, a "Previous step" section naming the previous role, its output file and its log from the second step onward, and the contract: do only this stage's work, never run `kf stage`, `kf approve`, `kf archive` or `kf run`, never edit an approved contract, never commit, and finish with `STATUS: DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT` followed by `Summary:`.
|
|
101
|
+
3. Each role is its own run: its own process group, its own `runs/<id>.log`, and one entry in `.kfw.json.runs[]` carrying both `role` and `runner`.
|
|
102
|
+
4. A role that does not end in `DONE` or `DONE_WITH_CONCERNS` **stops the chain**. The roles after it do not run, `kf run` exits 1, and it names which role stopped and which were skipped.
|
|
103
|
+
5. The main agent reads `STATUS` and `Summary` from the tail of the log, without swallowing the transcript, runs `kf validate` and decides on the transition. The gate does not take the worker's word for anything.
|
|
104
|
+
6. On the repair loop, the next `kf run` resumes that role's session for that work item, and the prompt gains the path to the current FAIL report. `--fresh` forces a new session.
|
|
105
|
+
|
|
106
|
+
`kf run --role <name>` runs exactly one role from the chain. `--dry-run` prints the plan for the whole chain, one argv and prompt block per role. The timeout is 30 minutes by default (`--timeout <minutes>`, `0` for none); on expiry the whole process group is killed and the run is marked `timeout`. There is no automatic retry: a failed resume resets the session exactly once and starts fresh. A work item has at most one `running` run at a time.
|
|
107
|
+
|
|
108
|
+
With `--detach`, kf writes the chain plan, spawns a detached `kf run --supervise <id>` as the supervisor and returns immediately. The supervisor runs the whole chain and finds the folder again by work item name before writing results; when the folder is gone it writes `.works/harness/orphan-<id>.json`. `kf runs` reports `failed (supervisor lost)` when a record is still `running` but its pid is dead, and it never repairs the metadata on its own.
|
|
109
|
+
|
|
110
|
+
## Observability
|
|
111
|
+
|
|
112
|
+
- `kf harness [--json]`: the main role, stage to role chain, role to runner with brief and output, and runner to CLI, PATH, resume and session.
|
|
113
|
+
- `kf status --change <f>`: `Assigned: researcher (codex) → writer (gemini) (kf run)` and `Runs: N (role×n, …)`; the JSON carries `assignedRoles` and `runs[]`.
|
|
114
|
+
- `kf runs [<f>] [--json]`: every run with its role, its runner and its place in the chain, such as `2/2`, newest first. A run that ends a chain before the last role while nothing else is running shows `chain stopped 1/2` with a warning underneath, and the JSON carries `chainBroken`. This is how you spot a broken chain, from a dead supervisor or a Ctrl+C, instead of assuming the stage finished.
|
|
115
|
+
|
|
116
|
+
Typing a runner name into `stages` gets a message that says so, rather than "unknown role":
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
Invalid project config: .kf/config.json — harness.stages.testing "gemini" is a runner,
|
|
120
|
+
not a role; declare a role in harness.roles that points at it
|
|
121
|
+
```
|
|
122
|
+
- `kf view [--json]`: `metrics.runs.byRole` as `{ runs, done, failed }`, and `metrics.runs.usage` broken down by role.
|
|
123
|
+
|
|
124
|
+
## Token cost
|
|
125
|
+
|
|
126
|
+
- The real work of reading code, changing it and running tests does not grow. It simply moves onto the assigned runner's quota.
|
|
127
|
+
- What does grow: every handover makes a worker re-read the skill, the artifacts and the relevant code, roughly 10 to 30 thousand tokens. **A role chain multiplies that by its length**: a two-role brainstorm pays for two handovers. Chain roles only when the two jobs are genuinely different.
|
|
128
|
+
- The repair loop costs another handover when the runner cannot resume.
|
|
129
|
+
- The main agent gets cheaper: it spends nothing while a worker runs, and only reads the tail of the log.
|
|
130
|
+
- Waste is held down: prompts carry paths rather than content, the chain stops the moment a role fails, a worker that prints no `STATUS` counts as unfinished, and nothing retries.
|
|
131
|
+
- Measurement: a runner with `usage: "json"` records tokens and cost into `runs[]`, and `kf view` totals them **by role**, so you can see which role is the expensive one.
|
|
132
|
+
|
|
133
|
+
## Limits
|
|
134
|
+
|
|
135
|
+
- The "do not move the stage" rule is a contract in the prompt, not something kf can enforce, because the worker has `kf` on its PATH. `runs[]` and `bypasses[]` are there to check against.
|
|
136
|
+
- Chains are always sequential, never parallel. Stopping midway leaves a half-done state: the first role wrote its file, the next never ran. `kf run` says so, `kf runs` marks it `chain stopped i/n`, and the stage's artifact gate is still what decides.
|
|
137
|
+
- Killing a process group uses `process.kill(-pid)`, which is POSIX. On Windows, kf cannot clean up a worker's children.
|
|
138
|
+
- `.kfw.json` is written both by the supervisor and by the main agent's `kf stage`. kf re-reads before writing and writes atomically, but there is no lock.
|
|
139
|
+
- A worker log can contain whatever sensitive content the CLI printed. `.works/` is usually gitignored; keep it that way.
|
|
140
|
+
- There is no async bridge yet, meaning nothing wakes the main agent once it is gone, and no `kf run --task` for ad-hoc work outside a stage.
|
|
141
|
+
|
|
142
|
+
## Terms of use
|
|
143
|
+
|
|
144
|
+
kf only spawns each vendor's official CLI using the headless flags that vendor documents (`claude -p`, `codex exec`, `gemini -p`, `devin -p`, `opencode run`), under the account already logged in on the machine running it. kf **never** reads, stores or forwards any CLI's credentials or tokens, never calls a vendor API directly and never retries in bursts. Each user remains responsible for the terms of the plan they are on, covering commercial use, account sharing and rate limits. This document is not legal advice.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Workflow Lifecycle
|
|
2
|
+
|
|
3
|
+
## The whole flow
|
|
4
|
+
|
|
5
|
+
```mermaid
|
|
6
|
+
flowchart TD
|
|
7
|
+
A([User describes a feature or a bug]) --> B{Does the project have .works?}
|
|
8
|
+
B -- No --> C[kf init]
|
|
9
|
+
B -- Yes --> D[Read the repo and pick the current phase]
|
|
10
|
+
C --> D
|
|
11
|
+
D --> E{Is the work item a bug?}
|
|
12
|
+
E -- No --> F[Brainstorm: pin down scope and acceptance]
|
|
13
|
+
E -- Yes --> G[Bug triage: reproduce, actual vs expected, severity]
|
|
14
|
+
F --> H[kf new + phase-1-spec-requirement.md]
|
|
15
|
+
G --> H
|
|
16
|
+
H --> I{Requirement confirmed?}
|
|
17
|
+
I -- Not yet --> E
|
|
18
|
+
I -- Yes --> J[kf stage item planning]
|
|
19
|
+
J --> K{Work item kind?}
|
|
20
|
+
K -- Feature --> KP[Planning: implementation plan + one file per UC + diagram + test plan]
|
|
21
|
+
K -- Bug --> KB[Planning: triage report + fix scope + regression strategy]
|
|
22
|
+
KP --> L{Human approves the execution contract?}
|
|
23
|
+
KB --> L
|
|
24
|
+
L -- Not yet --> K
|
|
25
|
+
L -- Yes --> M[kf approve: store the contract fingerprint]
|
|
26
|
+
M --> N{Start implementation now?}
|
|
27
|
+
N -- Yes --> O[Implementation: tasks.md + code]
|
|
28
|
+
N -- Not yet --> P[Backlog: hold the approved contract]
|
|
29
|
+
P --> Q{User chooses to start?}
|
|
30
|
+
Q -- Not yet --> P
|
|
31
|
+
Q -- Yes --> O
|
|
32
|
+
O --> R{Build green and tasks done?}
|
|
33
|
+
R -- Not yet --> O
|
|
34
|
+
R -- Yes --> S[kf stage item testing]
|
|
35
|
+
S --> T[Mint a new execution id]
|
|
36
|
+
T --> U[Run the tests from the Test Strategy]
|
|
37
|
+
U --> V[Write testing-result carrying the execution id]
|
|
38
|
+
V --> W{Testing PASS?}
|
|
39
|
+
W -- FAIL/REJECT --> O
|
|
40
|
+
W -- BLOCKED --> X([Stop and report the blocker])
|
|
41
|
+
W -- PASS --> Y[kf stage item review]
|
|
42
|
+
Y --> Z[Review changed files against rules: project, then user, then package]
|
|
43
|
+
Z --> AA[Write review-report carrying the execution id]
|
|
44
|
+
AA --> AB{Review result?}
|
|
45
|
+
AB -- FAIL/REJECT --> O
|
|
46
|
+
AB -- REQUIREMENT_BUG --> AC([Stop and ask the user to decide])
|
|
47
|
+
AB -- PASS --> AD{Work item kind?}
|
|
48
|
+
AD -- Feature --> FC[Write feature-report]
|
|
49
|
+
FC --> AE[kf archive: copy requirement, use-case and testplan docs]
|
|
50
|
+
AD -- Bug --> BC[Update the related feature docs if needed]
|
|
51
|
+
BC --> BA[kf archive: keep the bug record with its test and review]
|
|
52
|
+
BA --> AF
|
|
53
|
+
AE --> AF([dones: archive complete])
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
There is a second way out of this flow: `kf cancel <feature> --reason "<why>"` stops a work item for good at any stage, `dones` included when something supersedes it. The reason is mandatory and is stored in `.kfw.json` together with the stage it stopped in, so reopening it is `kf stage <feature> <that stage>`. This is the user's decision; the agent only suggests it on a `REQUIREMENT_BUG` or a dead scope.
|
|
57
|
+
|
|
58
|
+
Phase 1, the Phase 2 approval and the start-or-backlog decision are the points where the user decides. A feature produces all four planning artifacts; a bug uses its bug report as the triage contract and produces no feature use cases or test plan. If behaviour appears beyond the scope of the fix, tell the user and let them decide before opening a separate feature. Once start is chosen the agent runs on its own inside the execution contract. Two exceptions still need the user: `REQUIREMENT_BUG`, and any change of scope.
|
|
59
|
+
|
|
60
|
+
## Starting a feature, step by step
|
|
61
|
+
|
|
62
|
+
```mermaid
|
|
63
|
+
sequenceDiagram
|
|
64
|
+
actor User
|
|
65
|
+
participant Orchestrator as kanban-flow
|
|
66
|
+
participant CLI as kf
|
|
67
|
+
participant FS as .works/.kf/docs
|
|
68
|
+
|
|
69
|
+
User->>Orchestrator: Describes the context and the feature
|
|
70
|
+
Orchestrator->>CLI: kf init when .works is missing
|
|
71
|
+
Orchestrator->>CLI: kf new item --context context [--type bug]
|
|
72
|
+
CLI->>FS: Create the brainstorm folder, the metadata and the spec or bug template
|
|
73
|
+
Orchestrator->>User: Summarise the requirement or the triage, plus the open questions
|
|
74
|
+
User-->>Orchestrator: Confirms, or adjusts the scope
|
|
75
|
+
Orchestrator->>FS: Write status: confirmed into the requirement or bug report
|
|
76
|
+
Orchestrator->>CLI: kf stage feature planning
|
|
77
|
+
Orchestrator->>User: Summarise the execution contract
|
|
78
|
+
User-->>Orchestrator: approve
|
|
79
|
+
Orchestrator->>CLI: kf approve item
|
|
80
|
+
CLI->>FS: Store the approval contractHash
|
|
81
|
+
Orchestrator->>User: Start now, or send to backlog?
|
|
82
|
+
User-->>Orchestrator: start now / defer
|
|
83
|
+
Orchestrator->>CLI: kf stage item implementation or backlog
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Fixing a failure, step by step
|
|
87
|
+
|
|
88
|
+
```mermaid
|
|
89
|
+
sequenceDiagram
|
|
90
|
+
participant Test as kanban-test
|
|
91
|
+
participant CLI as kf
|
|
92
|
+
participant Impl as kanban-implement
|
|
93
|
+
participant FS as Work item folder
|
|
94
|
+
|
|
95
|
+
Test->>CLI: kf stage feature review
|
|
96
|
+
CLI-->>Test: Refused when the testing report is not PASS on the current execution
|
|
97
|
+
Test->>FS: Write testing-result with status FAIL or REJECT
|
|
98
|
+
Test->>CLI: kf stage feature implementation
|
|
99
|
+
CLI->>FS: Retire the current execution id
|
|
100
|
+
Impl->>FS: Fix the code and tick the tasks
|
|
101
|
+
Impl->>CLI: kf stage feature testing
|
|
102
|
+
CLI->>FS: Mint a new execution id
|
|
103
|
+
Test->>FS: Write testing-result for the new execution
|
|
104
|
+
Test->>CLI: kf stage feature review
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
An old report is kept as evidence, but it can never stand in as the result of a new execution.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Skill routing
|
|
2
|
+
|
|
3
|
+
`kanban-flow` is the orchestrator. Each phase skill owns only that phase's work; the real state stays with the CLI and the filesystem.
|
|
4
|
+
|
|
5
|
+
The orchestrator also owns the harness: when `.kf/config.json` assigns roles to a stage, `kf run` hands that stage to worker sessions instead of the orchestrator doing the work itself. The routing below still decides *which skill* loads; the harness decides *who runs it*. See [the harness guide](harness.md).
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
flowchart TD
|
|
9
|
+
O[kanban-flow orchestrator] --> B[kanban-brainstorm]
|
|
10
|
+
O --> BUG[kanban-bug: kind=bug]
|
|
11
|
+
B --> P[kanban-plan]
|
|
12
|
+
BUG --> P
|
|
13
|
+
P --> H{Human approve}
|
|
14
|
+
H --> D{Start now?}
|
|
15
|
+
D -->|Yes| I[kanban-implement]
|
|
16
|
+
D -->|No| BL[backlog]
|
|
17
|
+
BL -->|User starts| I
|
|
18
|
+
I --> T[kanban-test]
|
|
19
|
+
T -->|PASS| R[kanban-review]
|
|
20
|
+
T -->|FAIL/REJECT| I
|
|
21
|
+
T -->|scope change| P
|
|
22
|
+
R -->|PASS| A[kanban-archive]
|
|
23
|
+
R -->|FAIL/REJECT| I
|
|
24
|
+
R -->|scope change| P
|
|
25
|
+
A --> DONE[feature canonical docs or bug docs update + dones]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Responsibilities
|
|
29
|
+
|
|
30
|
+
| Skill | What it owns | What it must not decide alone |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| `kanban-flow` | Read the state, route to the phase, name the gate, resume at the right point | Never treat a requirement as confirmed on its own, never bypass a human gate |
|
|
33
|
+
| `kanban-brainstorm` | Ask about and pin down the problem, the goal, the scope and the acceptance criteria; write Phase 1 | Never move to planning before the user has confirmed |
|
|
34
|
+
| `kanban-plan` | For a feature, produce the execution plan, each UC file, the diagram, the test plan and the traceability; for a simple bug, keep the triage contract and write a full plan only when the behaviour contract changes | Never approve the contract, never choose start or backlog |
|
|
35
|
+
| `kanban-bug` | Triage the bug: reproduce it, record actual against expected, severity, root cause and the regression requirement | Never settle on a root cause alone, never start implementation alone |
|
|
36
|
+
| `kanban-implement` | Execute the tasks in the contract, hold the scope, update code and tests; subagents run under a prompt contract of task, files, acceptance and constraints, plus the status protocol | Never widen the scope or skip the plan without returning to planning |
|
|
37
|
+
| `kanban-test` | Run the tests, record the execution id and the evidence, classify as PASS, FAIL, REJECT or BLOCKED | Never turn a BLOCKED into a PASS |
|
|
38
|
+
| `kanban-review` | Review the implementation, the tests, the architecture, the security and the scope, including the AI-risk lens: phantom tests, catch-and-swallow, scope drift | Never archive when the report is not PASS |
|
|
39
|
+
| `kanban-archive` | For a feature, write the feature report and then call `kf archive`, which is what copies the canonical docs; for a bug, settle the docs impact and update only the related docs when needed | Never copy the canonical docs by hand — that skips the link rewrite and the `status: archived` stamp, and the next archive refuses. Never delete data, never deploy or publish on its own |
|
|
40
|
+
|
|
41
|
+
## Resuming and handing off
|
|
42
|
+
|
|
43
|
+
When starting or resuming a feature:
|
|
44
|
+
|
|
45
|
+
1. Read `kf status --change <feature> --json` and `kf validate --change <feature> --json`.
|
|
46
|
+
2. Read the artifacts of the current state and the one before it. Do not guess from the folder name.
|
|
47
|
+
3. In `planning` with a stale approval, finish the contract again and ask for a fresh `kf approve`.
|
|
48
|
+
4. In `testing` or `review`, use the `executionId` the metadata holds. A report from another execution is not valid.
|
|
49
|
+
5. On a `FAIL` or a `REJECT`, fix it in implementation and return to testing. On a `REQUIREMENT_BUG`, stop and tell the user. On a `BLOCKED`, stop and report the blocker.
|
|
50
|
+
6. Call archive only after a PASS review. A feature needs its full feature report; a bug needs a settled docs impact.
|
|
51
|
+
|
|
52
|
+
The phase 6 artifact is the handover document. It states what actually changed, which tests ran, which docs were updated, what limits remain and which follow-ups were accepted.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Source layout
|
|
2
|
+
|
|
3
|
+
CLI runtime code lives under `src/` and is grouped by responsibility. File moves do not change the public `kf` commands or the generated entrypoint `dist/index.js`.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
src/
|
|
7
|
+
├── index.ts # CLI entrypoint and command dispatch
|
|
8
|
+
├── cli/
|
|
9
|
+
│ ├── args.ts # argument parsing and help metadata
|
|
10
|
+
│ ├── result.ts # command result contract
|
|
11
|
+
│ └── commands/ # command handlers, split by use
|
|
12
|
+
│ ├── init.ts # project initialization
|
|
13
|
+
│ ├── new.ts # feature/bug creation
|
|
14
|
+
│ ├── inspect.ts # list, show, view, status, validate
|
|
15
|
+
│ ├── artifacts.ts # instruct and templates
|
|
16
|
+
│ ├── stage.ts # state transitions
|
|
17
|
+
│ ├── approve.ts # planning approval
|
|
18
|
+
│ ├── rules.ts # stack review-rule pack installation
|
|
19
|
+
│ ├── autoconfig.ts # agent-facing setup briefing (context, checklist, rules, workflow)
|
|
20
|
+
│ ├── run.ts # kf run / kf runs (hand a stage to a worker agent)
|
|
21
|
+
│ ├── harness.ts # kf harness (effective harness config)
|
|
22
|
+
│ └── archive.ts # closure and canonical docs sync
|
|
23
|
+
├── workflow/ # domain state, artifacts and validation
|
|
24
|
+
│ ├── schema.ts # stages, artifacts, transitions
|
|
25
|
+
│ ├── features.ts # .kfw.json metadata (approval, execution id, bypasses), feature listing
|
|
26
|
+
│ ├── status.ts # artifact checklist rendering
|
|
27
|
+
│ ├── findings.ts # Finding/ValidationResult types
|
|
28
|
+
│ ├── secrets.ts # secret-like content scan
|
|
29
|
+
│ ├── validate-artifacts.ts # due artifacts, stage gate, requirement confirmed
|
|
30
|
+
│ ├── validate-approval.ts # approval fingerprint, recorded bypasses
|
|
31
|
+
│ ├── validate-reports.ts # tasks.md, testing/review report semantics, exit codes
|
|
32
|
+
│ ├── validate-traceability.ts # FR → UC → TC references
|
|
33
|
+
│ ├── direction.ts # directional gate (PASS/FAIL/REQUIREMENT_BUG)
|
|
34
|
+
│ └── validate.ts # facade: composes the checks, renders results, re-exports
|
|
35
|
+
├── harness/ # multi-agent harness: role/runner config, worker prompt, session, run executor, role chain, detached supervisor
|
|
36
|
+
├── project/ # project config, declared contexts and bootstrap prompts
|
|
37
|
+
├── integrations/ # agents, skill installation and hooks
|
|
38
|
+
├── dashboard/ # analytics HTTP server and HTML view
|
|
39
|
+
├── shared/ # filesystem paths, frontmatter and time helpers
|
|
40
|
+
└── tests/ # all Vitest tests, grouped separately from runtime
|
|
41
|
+
├── helpers/ # fake agent CLIs and harness project fixture
|
|
42
|
+
└── setup/ # vitest globalSetup (builds dist for detached-run tests)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Dependency direction is intentionally one-way: command handlers call workflow/project/integration services; workflow code does not import CLI handlers. Shared utilities contain no command dispatch. This keeps changes to the CLI surface isolated from state and artifact rules.
|
|
46
|
+
|
|
47
|
+
When adding code, place it beside the responsibility it serves. Add a command handler under `src/cli/commands/`, a state or gate rule under `src/workflow/`, and its test under `src/tests/`. Keep the public dispatch in `src/index.ts` limited to wiring.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# State machine
|
|
2
|
+
|
|
3
|
+
```mermaid
|
|
4
|
+
stateDiagram-v2
|
|
5
|
+
[*] --> brainstorm: kf new
|
|
6
|
+
brainstorm --> planning: requirement/bug report filled + confirmed
|
|
7
|
+
planning --> backlog: approved + defer
|
|
8
|
+
planning --> implementation: approved + start now
|
|
9
|
+
backlog --> implementation: user chooses start
|
|
10
|
+
backlog --> planning: revise scope/plan
|
|
11
|
+
implementation --> testing: implementation complete
|
|
12
|
+
implementation --> planning: scope/plan needs change
|
|
13
|
+
testing --> review: testing result PASS
|
|
14
|
+
testing --> implementation: testing FAIL/REJECT
|
|
15
|
+
testing --> planning: scope change
|
|
16
|
+
review --> dones: review PASS + closure for kind
|
|
17
|
+
review --> implementation: review FAIL/REJECT
|
|
18
|
+
review --> planning: scope change
|
|
19
|
+
dones --> [*]
|
|
20
|
+
brainstorm --> cancelled: kf cancel --reason
|
|
21
|
+
planning --> cancelled: kf cancel --reason
|
|
22
|
+
backlog --> cancelled: kf cancel --reason
|
|
23
|
+
implementation --> cancelled: kf cancel --reason
|
|
24
|
+
testing --> cancelled: kf cancel --reason
|
|
25
|
+
review --> cancelled: kf cancel --reason
|
|
26
|
+
dones --> cancelled: kf cancel --reason
|
|
27
|
+
cancelled --> brainstorm: reopen at cancellation.fromStage
|
|
28
|
+
cancelled --> [*]
|
|
29
|
+
|
|
30
|
+
state testing {
|
|
31
|
+
[*] --> execution
|
|
32
|
+
execution: executionId is required
|
|
33
|
+
}
|
|
34
|
+
state review {
|
|
35
|
+
[*] --> review_execution
|
|
36
|
+
review_execution: report must use current executionId
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## States and transitions
|
|
41
|
+
|
|
42
|
+
| State | What it means | Allowed transitions |
|
|
43
|
+
| --- | --- | --- |
|
|
44
|
+
| `brainstorm` | Working the requirement out with the user | `planning` |
|
|
45
|
+
| `planning` | A feature settles its execution contract, a bug confirms its triage contract; then approval, then the start or backlog decision | `backlog`, `implementation` |
|
|
46
|
+
| `backlog` | The contract is approved but work has not started | `implementation`, `planning` |
|
|
47
|
+
| `implementation` | The agent executes against the approved contract | `testing`, `planning` |
|
|
48
|
+
| `testing` | Run the tests from the test plan and record the outcome | `review`, `implementation`, `planning` |
|
|
49
|
+
| `review` | Review the code, the scope and the architecture, and write the report | `dones`, `implementation`, `planning` |
|
|
50
|
+
| `dones` | Archived; a terminal state | `cancelled`, via `kf cancel` |
|
|
51
|
+
| `cancelled` | Stopped for good; it sits off the linear track, so no artifact is ever demanded of it | Back to `cancellation.fromStage` only |
|
|
52
|
+
|
|
53
|
+
The CLI allows only the edges above. Never move a `.works/` folder by hand.
|
|
54
|
+
|
|
55
|
+
## The guards that matter
|
|
56
|
+
|
|
57
|
+
- The requirement or bug report must be filled in and marked confirmed before it leaves `brainstorm`.
|
|
58
|
+
- Leaving `planning` needs all four planning artifacts and the UC files for a feature; a bug needs only a filled bug report and a real human's approval. The approval stores a fingerprint of the matching contract, so editing the contents afterwards makes it stale.
|
|
59
|
+
- Every entry into `testing` mints a new `executionId`. Both `phase-4-testing-result.md` and `phase-5-review-report.md` must carry the current one.
|
|
60
|
+
- `FAIL` and `REJECT` return to `implementation`. `BLOCKED` stops the flow. `REQUIREMENT_BUG` is a stop condition in review: never rewrite the requirement or move the state on your own.
|
|
61
|
+
- Only a `PASS` review whose testing and review match the current execution reaches `dones`. A feature also needs `phase-6-feature-report.md`; a bug does not.
|
|
62
|
+
- The only way into `cancelled` is `kf cancel`, and `--reason` is mandatory. The only way out is back to the stage it stopped in (`cancellation.fromStage`), at which point `cancellation` and `status` are cleared from the metadata. `kf archive` refuses a cancelled item.
|
|
63
|
+
|
|
64
|
+
The minimum metadata looks like this:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"schema": "kanban-flow",
|
|
69
|
+
"kind": "feature",
|
|
70
|
+
"feature": "payment-retry",
|
|
71
|
+
"context": "billing",
|
|
72
|
+
"created": "20260917_1405",
|
|
73
|
+
"approval": {
|
|
74
|
+
"status": "approved",
|
|
75
|
+
"by": "human",
|
|
76
|
+
"at": "20260917_1430",
|
|
77
|
+
"contractHash": "sha256:..."
|
|
78
|
+
},
|
|
79
|
+
"executionId": "uuid-of-the-current-testing-run"
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The `executionId` is cleared on a return to planning **and on every entry into implementation**, then reissued when a new testing execution begins. The implementation reset is the one that matters in a FAIL loop: it is what stops the old testing evidence from counting for the repaired code. A bug report lives in `phase-1-spec-requirement.md` using the bug template; it needs none of the feature planning artifacts. If new behaviour appears beyond the scope of the fix, tell the user and let them decide before opening a separate feature.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Kanban Flow Review Rules
|
|
2
|
+
|
|
3
|
+
## Structure
|
|
4
|
+
- `general.md` — Rules applied to every review
|
|
5
|
+
- `security.md` — Security-specific checks
|
|
6
|
+
- `performance.md` — Performance-specific checks
|
|
7
|
+
- `{stack}.md` — Stack-specific rules. Packs ship in the package at `kanban-flow/review/stacks/{stack}.md` (7 packs: `node`, `go`, `rust`, `python`, `php`, `ruby`, `java`) and are installed into this directory via `kf rules`.
|
|
8
|
+
|
|
9
|
+
## How to Use
|
|
10
|
+
Skill `kanban-review` loads all rules in this directory at review time.
|
|
11
|
+
Project-specific rules override global rules when same filename exists.
|
|
12
|
+
|
|
13
|
+
## Installing Stack Rules
|
|
14
|
+
```bash
|
|
15
|
+
kf rules # auto-detect stacks from manifests (monorepo: installs every detected pack)
|
|
16
|
+
kf rules --stack go --stack python # install specific packs
|
|
17
|
+
kf rules --list # list available packs and detected stacks
|
|
18
|
+
kf rules --force # overwrite a project rule file that differs from the pack
|
|
19
|
+
```
|
|
20
|
+
Without `--force`, an existing `.kf/review/rules/{stack}.md` that differs from the pack is skipped with a warning — project rules are user-owned. Re-running on an identical file reports "already installed". Works before `kf init`.
|
|
21
|
+
|
|
22
|
+
## Adding Rules
|
|
23
|
+
Create a new `.md` file in this directory. Each rule should be:
|
|
24
|
+
- A short imperative sentence
|
|
25
|
+
- Specific enough to verify (not "write good code")
|
|
26
|
+
|
|
27
|
+
## Severity Levels
|
|
28
|
+
- **HIGH** — Must fix before merge (security risk, data loss, crash)
|
|
29
|
+
- **MEDIUM** — Should fix before merge (performance, maintainability)
|
|
30
|
+
- **LOW** — Suggestion, can defer
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# General Code Review Rules
|
|
2
|
+
|
|
3
|
+
## Error Handling
|
|
4
|
+
- Never swallow errors (empty catch/try)
|
|
5
|
+
- Catch only specific exception types
|
|
6
|
+
- Every catch must handle or rethrow with context
|
|
7
|
+
- App must not panic on exception
|
|
8
|
+
- Log with stack trace, request id, input, and correct level
|
|
9
|
+
|
|
10
|
+
## Code Quality
|
|
11
|
+
- One file max 500 lines (if longer, re-evaluate responsibilities)
|
|
12
|
+
- Split by responsibility, not by line count
|
|
13
|
+
- One file = one clear responsibility
|
|
14
|
+
- Separate UI logic from display logic when file grows
|
|
15
|
+
|
|
16
|
+
## Naming & Changes
|
|
17
|
+
- Do not rename functions/files for style preference only
|
|
18
|
+
- Rename only when name causes semantic confusion
|
|
19
|
+
- No reformatting existing code (no import reorder, no quote changes)
|
|
20
|
+
- Each edit = one purpose, no refactoring during bug fix
|
|
21
|
+
|
|
22
|
+
## Comments
|
|
23
|
+
- No unnecessary comments describing what code does
|
|
24
|
+
- Comment only "why" (decisions, constraints, gotchas)
|
|
25
|
+
- No TODO comments, no "changed by AI", no "removed old logic"
|
|
26
|
+
|
|
27
|
+
## Review Discipline
|
|
28
|
+
- Scout first: read the actual repo/code before asking the user or flagging — no findings based on guesses
|
|
29
|
+
- Review only files that actually changed; verify claims against the real diff
|
|
30
|
+
- Preserve verified decisions: do not reopen a decision already verified earlier without new evidence
|
|
31
|
+
- Preserve user decisions: never silently undo user-chosen scope, libraries, or thresholds
|
|
32
|
+
- Threat-model before applying a finding: state what the code stores, protects, and exposes; fix the real failure mode, not the abstract one
|
|
33
|
+
|
|
34
|
+
## Stable Artifacts
|
|
35
|
+
- Do not embed plan IDs, phase numbers, or finding codes (FR-001, TC-002, HIGH-1) in code comments, test names, or commit messages — they rot when the plan changes
|
|
36
|
+
- Reference artifacts by stable names in docs; keep mutable anchors out of the codebase
|
|
37
|
+
|
|
38
|
+
## Security
|
|
39
|
+
- Never commit secrets or keys
|
|
40
|
+
- Never expose secrets in logs
|
|
41
|
+
- Validate and sanitize input at boundaries
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Performance Review Rules
|
|
2
|
+
|
|
3
|
+
## Queries & Data Access
|
|
4
|
+
- No N+1 queries (check for loops with DB calls inside)
|
|
5
|
+
- Use pagination for list endpoints
|
|
6
|
+
- Add indexes for frequently queried fields
|
|
7
|
+
- Prefer batch operations over individual operations
|
|
8
|
+
|
|
9
|
+
## Caching
|
|
10
|
+
- Identify cacheable data (read-heavy, slow-compute)
|
|
11
|
+
- Set appropriate TTL
|
|
12
|
+
- Invalidate cache on data mutation
|
|
13
|
+
|
|
14
|
+
## Network & I/O
|
|
15
|
+
- Prefer async/parallel for independent I/O
|
|
16
|
+
- Set timeouts on external calls
|
|
17
|
+
- Handle connection pooling properly
|
|
18
|
+
- Avoid unnecessary data transfer
|
|
19
|
+
|
|
20
|
+
## Memory
|
|
21
|
+
- Stream large data instead of loading into memory
|
|
22
|
+
- Watch for memory leaks in event listeners
|
|
23
|
+
- Clean up resources (close files, connections)
|
|
24
|
+
|
|
25
|
+
## Frontend (if applicable)
|
|
26
|
+
- Lazy load non-critical resources
|
|
27
|
+
- Optimize bundle size
|
|
28
|
+
- Minimize re-renders (React memoization)
|
|
29
|
+
- Compress images and assets
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Security Review Rules
|
|
2
|
+
|
|
3
|
+
## Secrets Management
|
|
4
|
+
- No hardcoded credentials, API keys, or tokens
|
|
5
|
+
- No secrets in workflow artifacts (specs, plans, reports) — `kf validate` rejects secret-like content
|
|
6
|
+
- Use environment variables or secret managers
|
|
7
|
+
- Never log sensitive data
|
|
8
|
+
|
|
9
|
+
## Threat Model First
|
|
10
|
+
- Before applying a security finding, state what the code stores, protects, and exposes
|
|
11
|
+
- Fix the real failure mode, not the abstract pattern — a finding without a reachable attack path is LOW
|
|
12
|
+
- Do not add auth/crypto/validation where the data is not sensitive and not externally reachable
|
|
13
|
+
|
|
14
|
+
## Input Validation
|
|
15
|
+
- Validate all external input at system boundary
|
|
16
|
+
- Sanitize before using in queries, commands, templates
|
|
17
|
+
- Use parameterized queries (no string concatenation for SQL)
|
|
18
|
+
|
|
19
|
+
## Authentication & Authorization
|
|
20
|
+
- Check auth before business logic
|
|
21
|
+
- Use established auth patterns (not custom crypto)
|
|
22
|
+
- Enforce least-privilege access
|
|
23
|
+
|
|
24
|
+
## Dependencies
|
|
25
|
+
- No known vulnerable dependencies
|
|
26
|
+
- Review new dependencies before adding
|
|
27
|
+
- Lock dependency versions
|
|
28
|
+
|
|
29
|
+
## Data Protection
|
|
30
|
+
- Encrypt sensitive data at rest and in transit
|
|
31
|
+
- Mask sensitive data in logs
|
|
32
|
+
- Apply rate limiting on public endpoints
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Go Review Rules
|
|
2
|
+
|
|
3
|
+
## Error Handling
|
|
4
|
+
- No ignored errors — every `err` is checked, wrapped with `%w` context, or explicitly documented why safe
|
|
5
|
+
- No `panic` in library code; reserve for truly unrecoverable startup failures
|
|
6
|
+
- Error return is the last return value; sentinel errors via `errors.Is`/`errors.As`, not `==` on messages
|
|
7
|
+
- No empty `if err != nil {}` blocks and no `_ =` discarding of meaningful errors
|
|
8
|
+
|
|
9
|
+
## Concurrency
|
|
10
|
+
- Every goroutine has a defined lifecycle — no fire-and-forget without a stop/join path
|
|
11
|
+
- Shared state guarded by mutex/channel, never by convention; run `go test -race` clean
|
|
12
|
+
- Channels closed by the sender only; no send on possibly-closed channel
|
|
13
|
+
- `context.Context` is the first parameter and propagates cancellation — no `context.Background()` deep in call chains
|
|
14
|
+
|
|
15
|
+
## Resources
|
|
16
|
+
- `defer x.Close()` immediately after successful open/conn/resp — before the error return path
|
|
17
|
+
- HTTP response bodies always drained and closed
|
|
18
|
+
- No goroutine leaks via unbounded blocking writes — use buffered channels or select+ctx
|
|
19
|
+
|
|
20
|
+
## Code Quality
|
|
21
|
+
- Exported symbols have doc comments starting with the symbol name
|
|
22
|
+
- Interfaces defined at the consumer, small (1-3 methods); no giant interface up front
|
|
23
|
+
- No init() side effects beyond registration; wiring happens in main/composition root
|
|
24
|
+
- Table-driven tests for branching logic; `t.Helper()` in test helpers
|
|
25
|
+
|
|
26
|
+
## Dependencies & Config
|
|
27
|
+
- `go.mod`/`go.sum` committed; no replace directives left without a comment why
|
|
28
|
+
- No global mutable state — config passed explicitly or via struct fields
|
|
29
|
+
|
|
30
|
+
## Performance
|
|
31
|
+
- No string concatenation in hot loops — `strings.Builder`
|
|
32
|
+
- Slice/map capacity preallocated when size is known
|
|
33
|
+
- No N+1 DB calls — batch or join at the repository layer
|