Sprint Skill — Generic Sprint Management for bkit Users
Sprint = meta-container above bkit's PDCA 9-phase. A sprint groups one or
more features under a shared scope, budget, and timeline. Each sprint runs
its own 8-phase lifecycle: prd -> plan -> design -> do -> iterate -> qa
-> report -> archived.
The skill handler routes through <bkit-root>/scripts/sprint-handler.js
(bkit convention — handlers live at the bkit repo root scripts/ directory,
NOT inside skills//scripts/). The handler composes
Sprint 3 adapters (state-store + telemetry + doc-scanner + matrix-sync)
into Sprint 2 use cases (start / advance / iterate / qa / report / archive).
Sprint 1 entities (createSprint / SprintEvents / typedefs) are produced
and consumed transparently along the way.
Resolving scripts/sprint-handler.js in this document: throughout
this SKILL.md, references to scripts/sprint-handler.js mean
<bkit-root>/scripts/sprint-handler.js (the canonical location).
LLM dispatchers MUST NOT compose skills/sprint/scripts/sprint-handler.js
— that path does not exist (Issue #107, fixed v2.1.19 S2 F2-1).
Arguments
Argument
Description
Example
init <id>
Create a sprint with default config
/sprint init my-launch
start <id>
Run auto-run loop bounded by Trust Level scope
/sprint start my-launch --trust L3
status <id>
Show current sprint state from disk
/sprint status my-launch
list
Union of state-store entries and master-plan discoveries
/sprint list
phase <id> --to <phase>
Advance to a specific phase
/sprint phase my-launch --to qa
iterate <id>
Run matchRate-100 loop (max 5 cycles)
/sprint iterate my-launch
qa <id> --feature <name>
Run 7-Layer data-flow check on one feature
/sprint qa my-launch --feature auth
report <id>
Generate KPI + lessons + carry-items report
/sprint report my-launch
archive <id>
Move to terminal archived status
/sprint archive my-launch
pause <id>
Manually pause a running sprint
/sprint pause my-launch
resume <id>
Re-evaluate triggers and resume
/sprint resume my-launch
watch <id>
Live dashboard (Sprint 5 — current returns snapshot)
/sprint watch my-launch
feature <id>
Per-feature operations (Sprint 5)
/sprint feature my-launch --feature auth
fork <id>
Fork into a new sprint (Sprint 5)
/sprint fork my-launch --new my-launch-v2
help
Print sub-action help
/sprint help
master-plan <project>
Generate multi-sprint Master Plan (agent isolated spawn)
Pause writes an audit log entry and a SprintPaused event. Resume
re-evaluates the triggers and refuses if any are still firing.
Cross-Sprint Architecture (Sprint 1+2+3+4)
USER COMMAND
v
skills/sprint/SKILL.md (this file — frontmatter triggers in 8 languages)
v
scripts/sprint-handler.js (English dispatcher)
v
Sprint 3: lib/infra/sprint -> { stateStore, eventEmitter, docScanner, matrixSync }
v
Sprint 2: lib/application/sprint-lifecycle -> startSprint / advancePhase / ...
v
Sprint 1: lib/domain/sprint -> createSprint / SprintEvents / typedefs
v
DISK: .bkit/state/sprints/<id>.json + .bkit/audit/<date>.jsonl
Examples
See:
examples/basic-sprint.md
examples/multi-feature-sprint.md
examples/archive-and-carry.md
When NOT to Use
Single-feature PDCA work — use bkit:pdca instead
Starter level projects — sprint overhead exceeds value
One-off bug fixes that do not warrant a master plan
Delegation notes
Extended trigger keywords, moved here from the frontmatter description
(issue #129 token diet) — one anchor per language stays in the description;
the full multilingual list is preserved below:
This contract specifies how an LLM dispatcher should construct the args
object for each of the 16 sub-actions when invoking the underlying handler
via scripts/sprint-handler.js.
/sprint measure <id> is the user-invokable partial-gate measurement command
added in v2.1.16. It routes the requested gate(s) through
lib/application/quality-gates/measure-router.js (single SoT shared with
sprint-orchestrator self-assessment) and persists results into
sprint.qualityGates subject to Trust Level scope.
ENH-292 alignment: multi-gate / phase batch dispatches measurements
sequentially (no Promise.all) to avoid #56293 sub-agent caching 10x.
Dispatcher requirement: the LLM dispatcher (main session) must inject
deps.agentTaskRunner wrapping Claude Code's Task tool. Without it the use
case returns reason: 'no_agent_runner' per gate (deterministic, not silent
fail). The handler layer exposes createTaskToolRunner({ invokeTaskTool })
(in scripts/lib/sprint-handler-shared.js, re-exported from
scripts/sprint-handler.js) to build this wrapper:
const { createTaskToolRunner } = require('<bkit-root>/scripts/lib/sprint-handler-shared');
const runner = createTaskToolRunner({
invokeTaskTool: async ({ subagent_type, prompt }) => {
// delegate to Claude Code's Task tool in the main sessionreturn { text: awaitcallTaskTool({ subagent_type, prompt }) };
},
});
awaithandleSprintAction('measure', { id, gate }, { agentTaskRunner: runner });
Two invocation paths:
In-process (primary, main session): the LLM dispatcher calls
handleSprintAction(...) directly with deps.agentTaskRunner injected.
Gate measurement works end-to-end.
Subprocess CLI (node scripts/sprint-handler.js ...): runs in a
separate Node process that cannot see the Task tool, so it passes {}
and gate measurement returns no_agent_runner. Use this path only for
non-measurement actions (status, list, help) or when the in-process path
is unavailable; for any action that measures gates, use the in-process
dispatcher call with an injected runner.
When a sprint is at Trust Level L2 (scope.stopAfter = "design") or any other
level whose scope.requireApproval blocks a forward transition, the user can
re-issue the phase action with --approve (and optional --reason) to
cross the scope boundary for this single call only:
Single-use: sprint.autoRun.scope is NOT mutated. The next transition
faces the same scope check. To advance through multiple scope-blocking
transitions, re-issue --approve each time (or escalate Trust Level via
/bkit:control level <N>).
No trust escalation: sprint.autoRun.trustLevelAtStart and the global
automation level (/bkit:control) are unchanged. The approval is recorded
per-call.
Audit-logged: every --approve boundary crossing emits an
audit-logger.writeAuditLog({ action: 'scope_boundary_approved', details: { sprintId, from, to, trustLevel, stopAfter, approvedBy, reason } }) entry.
The --reason "..." value is the recorded rationale (null when omitted).
Without --approve the legacy deadlock behavior is preserved: handler
returns { ok: false, reason: 'requires_user_approval', stopAfter, hint }.
Use this when you want to advance past the scope boundary for one specific
transition (e.g., L2 design → do after design review) without permanently
relaxing the trust level.
10.1.1.1 --approve does NOT bypass Quality Gate failures (v2.1.19 S1, CO-S0-6)
Critical semantic clarification (added v2.1.19 S1 in response to S0
discovery of ambiguity — master plan carry-over CO-S0-6):
--approve is the Trust Level scope-boundary escape hatch ONLY.
It is NOT a Quality Gate override mechanism.
Run /sprint measure <id> --gate <key> first, then re-issue phase
Both scope + gate fail
❌ Gate wins
Measure gate, then --approve if scope still blocks
Why this matters: in v2.1.19 S0 (master plan §23 step 0) we attempted
/sprint phase s0-sqm-baseline --to plan --approve and observed
{ ok: false, reason: 'gate_fail', ... } despite --approve. This is
expected behavior — --approve does not satisfy M8 designCompleteness.
Future work (deferred to v2.1.20+): --allowGateOverride flag may be
introduced as a gate override (with stronger audit + alarm trail than
--approve). Until then, gate failures must be resolved via /sprint measure.
Mutate the storedsprint.autoRun.trustLevelAtStart for a specific
sprint. Unlike --approve (single-use scope boundary override, §10.1.2) or
--trustLevel L<N> (per-call volatile override), this command persists
the trust level across all subsequent operations on the sprint.
Use cases:
L1 sprint started conservatively, ready to escalate after design review.
Demoting L4 sprint to L2 mid-flight after security concern.
Recovering from L1 "preview-mode lockout" (#101 v2.1.16 root cause — @pruge
dandi-village-ledger s1-foundation scenario).
--force flag (explicit override + forced: true audit + blastRadius: 'high'
for Defense Layer 6 alarm).
Minor downgrades (1-level diff, e.g. L3 → L2) are not blocked.
Idempotent Path:
from === to (e.g. --to L3 when sprint already at L3) returns
{ ok: true, noop: true } and also emits audit with noop: true field
(CTO §C3 review: monitoring blind-spot prevention — surfaces automation
patterns hitting idempotent paths).
Actor Auto-Detection (CTO §E6 spoofing mitigation):
Precedence: trustLevel > trust > trustLevelAtStart. Defaults to L2
when none provided or value is invalid (case-insensitive match against L0-L4).
v2.1.19 S1 F1-4 default change: default lowered from L3 to L2 per
Safe Defaults principle (master plan §3.2 Controllable AI Principles). The
handler now aligns with lib/domain/sprint/entity.js createSprint which
already defaulted to L2 — eliminates the v2.1.16~v2.1.18 drift between
handler default (L3) and entity default (L2).
--trust L1 explicit warning: when the user explicitly requests L1 at
/sprint init, the handler emits a stderr warning + audit
sprint_trust_warning event re: preview-mode lockout risk
(v2.1.18 #101 follow-up). The warning is education-only — L1 sprint init
still succeeds.
10.3 Natural Language Mapping Rules
When the user invokes the skill with mixed slash command + natural language
(e.g., /sprint start S1-UX Phase 1 PRD please proceed thoroughly), the
LLM dispatcher SHOULD:
Extract action: first non-flag token after /sprint → action.
Extract id (kebab-case): scan remaining tokens for the first kebab-case
identifier (matches /^[a-z][a-z0-9-]{1,62}[a-z0-9]$/). Lowercase if
needed. Example: S1-UX → s1-ux.
Disambiguate via AskUserQuestion: if multiple kebab-case candidates
or none, prompt the user to confirm the intended sprint id.
Load name from state: for start action on an existing sprint, the
name field can be resolved by handleStatus({ id }) first; otherwise
fall back to the id itself.
User: /sprint start S1-UX Phase 1 PRD proceed thoroughly
LLM dispatch:
1. action = "start"
2. Candidates: ["s1-ux"] (kebab-case extracted from "S1-UX")
3. AskUserQuestion: "Did you mean to start sprint 's1-ux' and continue
with Phase 1 (PRD)?" → user confirms
4. await handleSprintAction("start", { id: "s1-ux", ... })
10.6 Error Handling
Handler returns { ok: false, error: <string>, ... } on failure. LLM
dispatcher SHOULD surface the error verbatim to the user and offer
remediation (e.g., for error: 'Sprint not found', suggest /sprint list).
10.7 CLI Mode (P1 fix)
The same handler is invokable as a standalone CLI when run as
node scripts/sprint-handler.js <action> [id] [--flags]. Useful for
headless tests, debugging, and CI integration. The CLI parser accepts
--key value and --key=value forms, with the first positional argument
after action treated as id if no --id flag is provided.
The master-plan action generates a multi-sprint roadmap via the
bkit:sprint-master-planner agent (isolated subagent spawn) and persists
both markdown documentation and state JSON.
11.1 Workflow
USER: /sprint master-plan q2-launch --name "Q2 Launch" --features auth,payment
|
SKILL.md dispatches -> scripts/sprint-handler.js handleMasterPlan
|
handleMasterPlan calls lib/application/sprint-lifecycle/master-plan.usecase.js generateMasterPlan
|
generateMasterPlan validates input + loads existing state (idempotent check)
|
If deps.agentSpawner provided: spawn bkit:sprint-master-planner agent -> markdown
If not: dry-run via templates/sprint/master-plan.template.md substitution
|
Atomic write: .bkit/state/master-plans/<projectId>.json (state first)
|
File write: docs/01-plan/features/<projectId>.master-plan.md (markdown)
|
Audit: lib/audit/audit-logger.js writeAuditLog({ action: 'master_plan_created' })
|
Optional Task wiring: deps.taskCreator called N times for N sprint tasks
11.2 Idempotency + Force Overwrite
Default: idempotent. Second call with same projectId returns existing plan.
--force flag: overwrites both state JSON and markdown. Audit entry has
details.forceOverwrite: true.
Audit ACTION_TYPE remains 'master_plan_created' for both cases (PM-S2G).
11.3 Dry-Run vs Agent-Backed Generation
When the caller (LLM dispatcher at main session) does NOT inject
deps.agentSpawner, the use case generates a minimal valid markdown by
substituting variables in templates/sprint/master-plan.template.md. The
output is a skeleton — header, context anchor placeholders, empty features
table, empty sprints array. This dry-run mode is useful for unit tests and
when the user wants a starting template to fill manually.
When deps.agentSpawner is injected, the use case calls it with
{ subagent_type: 'bkit:sprint-master-planner', prompt: <built> } and uses
the returned output field as the markdown content.
11.4 State Schema v1.0
The state JSON at .bkit/state/master-plans/<projectId>.json:
The sprints array is populated by the S3-UX context-sizer.js use case.
S2-UX leaves it as an empty stub.
11.5 Task Management Integration (Optional)
When the caller injects deps.taskCreator, the use case iterates
plan.sprints sequentially (ENH-292 caching alignment) and calls
deps.taskCreator(...) once per planned sprint with addBlockedBy populated
from the previous sprint's task ID. This enables automatic Task list creation
for multi-sprint roadmaps.
When deps.taskCreator is undefined or plan.sprints.length === 0, Task
creation is silently skipped (no error).