A spec-kit extension that turns
tasks.mdinto parallel rounds for subagents — provably optimal (Google OR-Tools CP-SAT), critical-path aware, safe against file conflicts — and then runs those rounds with your AI assistant's subagents. Zero configuration.
specify extension add schedule --from https://github.com/jfranc38/spec-kit-schedule/archive/refs/tags/v0.7.4.zip
/speckit.tasks # spec-kit generates tasks.md as usual
/speckit-schedule-run # plan: 25 tasks → 4 rounds × 3 subagents, 2.6× faster
/speckit-schedule-implement # run: one subagent per lane per round, tasks.md ticks itself
That is the whole workflow. No YAML, no agent portfolio, no model strings. The first run bootstraps a private Python environment under the extension directory (about a minute); every later run takes seconds.
Claude Code registers extension commands as skills, so the commands are spelled with hyphens:
/speckit-schedule-run,/speckit-schedule-implement,/speckit-schedule-status. Other assistants may accept the dotted form.
/speckit-schedule-run prints a summary like this and writes
schedule.md + schedule.json next to tasks.md:
═══ Schedule — 004-team-notes ═══
Status: OPTIMAL
Tasks: 25
Rounds: 4 parallel rounds × 3 workers
Speedup: 2.6× (sequential 118 → 45 time units with barriers)
Critical path (7 tasks, 38% of total effort):
T001 → T004 → T007 → T011 → T013 → T014 → T015
T004 Setup database schema and migrations framework in src/db/base.py
...
Next: /speckit-schedule-implement to run the rounds with parallel subagents
schedule.md holds the round tables (lane → ordered tasks → files), the
critical path with descriptions, a Mermaid Gantt and the dependency
DAG. schedule.json is the machine-readable plan the implement command
follows.
/speckit-schedule-implement then loops: get the next round → launch
one subagent per lane in parallel, each with a self-contained brief
(its ordered tasks, the files they name, the files other lanes own
this round, the spec/plan to read, the report format) → collect the
DONE / FAILED / TOUCHED reports → tick the finished tasks in
tasks.md → run the project's tests → next round. Progress lives only
in the [x] checkboxes, so you can stop and resume at any time, and a
failed lane never advances the round.
- Parse
tasks.mdexactly as/speckit.taskswrites it (bare file paths,(Priority: P1),### Tests for User Story Nsub-sections). Dependencies come from phase barriers (Setup → Foundational → stories → Polish),[P]markers, same-file write order, tests-before-implementation, and optional(depends on T###)notes. Contradictory heuristic edges are dropped with a warning; only an explicit cycle is an error. - Solve a CP-SAT model over N identical subagent lanes: DAG precedence, file mutex across lanes, optional cap on tasks per lane; minimise makespan, then balance the lanes. Warm-started, anytime — there is always a plan.
- Batch into rounds. A subagent orchestrator can only "launch a
batch, wait for all, launch the next". Each lane gets the longest
prefix of its queue whose cross-lane predecessors are already done;
the same function, fed the live
[x]state, is whatnextuses at run time. The reported speedup is measured against these barriers, not the idealised solver makespan. - Brief and run. Each lane's brief is a complete instruction sheet;
tasks.mdhas a single writer (the orchestrator), so lanes never race on it.
Details: docs/execution.md (rounds, briefs,
report protocol), docs/tasks-format.md
(parser contract), docs/formulation.md
(the optimisation model), docs/architecture.md.
Nothing is required. specify extension add drops a two-knob
schedule-config.yml under .specify/extensions/schedule/ (equivalent
to the defaults; kept across updates). Edit it there, or create
.specify/schedule/schedule-config.yml, which takes precedence:
workers: 3 # parallel subagent lanes (default 3)
max_tasks_per_worker: 0 # 0 = no cap; e.g. 6 keeps every subagent's context shortBoth are also flags: /speckit-schedule-run --workers 4 --max-tasks-per-worker 6.
If the cap is too small for the task count, lanes are added
automatically (never silently infeasible).
The original portfolio schema still works for teams that route tasks
to different models: an agents: list with skills, kappa (max
tasks), context_budget (kilotokens), speed_factor,
price_per_1k_tokens, plus skill_rules, token_estimates and the
solver: block (objective: lexicographic | weighted | cost_aware,
time_limit, …). See docs/example-config.yml
and config-template.yml. When agents: is
present the workers knobs are ignored. Replanning a partially
executed run (python -m solver.replan) and calibration from run logs
(python -m solver.calibrate) remain available as CLI tools.
| Command | What it does |
|---|---|
/speckit-schedule-run (aliases plan, solve) |
Plan tasks.md into rounds → schedule.md + schedule.json + inline summary |
/speckit-schedule-implement |
Run the rounds with parallel subagents; resumable; single writer of tasks.md |
/speckit-schedule-status |
Diagnose the installation (files, hook, solver env, optional config, run history) |
The extension registers an optional hook after /speckit.tasks ("Plan
these tasks into parallel subagent rounds?") and after
/speckit.converge (re-plan when tasks were appended). Hooks never
auto-execute.
Every command calls bin/speckit-schedule, a wrapper that bootstraps
the environment and runs python -m solver <verb>:
python -m solver plan .specify/specs/004-x/tasks.md [--workers N] [--max-tasks-per-worker M] [--images]
python -m solver next .specify/specs/004-x/schedule.json # next round: briefs per lane (or DONE)
python -m solver mark .specify/specs/004-x/tasks.md T001 T002 # tick checkboxes (--undo to untick)
python -m solver statusExit codes: 0 ok / DONE, 1 no schedule, 2 input error (message
names the fix), 3 blocked (every pending task waits on another).
The individual stages (solver.parse_tasks, solver.scheduler,
solver.render_schedule, solver.render_html, solver.visualize,
solver.replan, solver.calibrate, solver.wave_executor) are still
invocable with python -m for pipelines.
# From a tagged release (recommended)
specify extension add schedule --from https://github.com/jfranc38/spec-kit-schedule/archive/refs/tags/v0.7.4.zip
# Local development checkout
git clone https://github.com/jfranc38/spec-kit-schedule
cd spec-kit-schedule && make install
specify extension add schedule --dev .Requirements: Python 3.10–3.12 and uv (installed automatically by
the bootstrap if missing; SKIP_UV=1 falls back to pip). See
INSTALL.md.
| Resource | Path |
|---|---|
| Extension code + private venv | .specify/extensions/schedule/ (+ .venv/) |
| Optional config | .specify/extensions/schedule/schedule-config.yml (scaffolded) or .specify/schedule/schedule-config.yml (wins) |
| Plan snapshots (calibration) | .specify/schedule/runs/ |
| Plan outputs | .specify/specs/<feature>/schedule.md, schedule.json |
| Message | Cause | Fix |
|---|---|---|
Duplicate task id … |
Two - [ ] T### lines share an id |
Renumber one |
Unresolved dependencies |
(depends on T###) names a missing task |
Fix the id |
Dependency cycle detected: … origins: ['explicit', …] |
Explicit depends on notes contradict each other or the phase order |
Remove one note |
Dropped the same-file edge … (warning) |
Declaration order and an explicit note disagreed; the note won | Nothing — informational |
tasks.md changed since the plan was made |
Tasks were added/removed after planning | /speckit-schedule-run again |
BLOCKED — no lane can start |
A pending task's predecessor is pending too, but not in any lane | Check which tasks are really done; mark them |
INFEASIBLE |
Only with an advanced agents: portfolio whose caps are too tight |
Raise kappa / context_budget or add agents |
make install # uv bootstrap + sync (dev+viz) + smoke test
make test # pytest
make lint # ruff
make typecheck # mypy
make smoke # end-to-end: legacy pipeline + `python -m solver plan/next/mark`
make examples # run examples/ end-to-end
make package # dist/spec-kit-schedule.zipMIT — Julio César Franco Ardila