The plans command manages tasks and initiatives from the command line.
# Install (one-time) — the plans entrypoint is registered via pyproject.toml
uv sync --extra dev
# All commands below use `plans` (or `uv run plans` outside an activated venv)
plans task create \
--workstream infra-tooling \
--title "My new task" \
--description "What this task delivers" \
--status ready \
--dependencies sibling-task,another-task
plans task update --path tasks/workstreams/infra-tooling/tasks/my-task.md \
--status in_progress --priority p2 --pr-url https://github.com/org/repo/pull/123 --pr-number 123
Task frontmatter now supports:
ready as a first-class queueable statusdependencies as a YAML list of task slugsstarted_at when work beginspr_created_at, pr_number, and pr_url when the task reaches PR handoff--status in_progress)plans task start --path tasks/workstreams/infra-tooling/tasks/my-task.md
For manager-driven dispatch, prefer setting status: ready and then running heartbeat with
--dispatch-ready. Reserve task start for already-claimed/manual execution.
--status completed)plans task complete --path tasks/workstreams/infra-tooling/tasks/my-task.md
plans task complete also stamps completed_at and completed_by in task frontmatter.
If a completed task is moved back to another status, that completion metadata is cleared.
# All tasks across all workstreams
plans task list
# Filter by workstream
plans task list --workstream infra-tooling
# Filter by status (comma-separated)
plans task list --workstream infra-tooling --status not_started,in_progress
plans task show --path tasks/workstreams/infra-tooling/tasks/my-task.md
# By issue number
plans task find --github-issue 301
# By URL fragment
plans task find --github-issue "github.com/fivetran/dataface/issues/301"
plans initiative create \
--workstream cloud-suite \
--title "My initiative" \
--description "Objective of this initiative" \
--tasks task-slug-1 task-slug-2
plans initiative update \
--path tasks/workstreams/cloud-suite/initiatives/my-init/index.md \
--status in_progress --add-task new-task-slug
For convenience, the Justfile provides pass-through wrappers:
just mp-task create --workstream ... # same as: plans task create --workstream ...
just mp-initiative create --workstream ... # same as: plans initiative create --workstream ...
# Default owner comes from TASK_MANAGER_OWNER (fallback: current system user).
# Heartbeat loop + tasks server (reloads on tasks/ and scripts/ changes):
just tasks serve owner=dave port=8005
# Direct server only (no heartbeat):
uv run python tasks/tools/run_tasks_server.py --port 8005 --owner dave
# Hosted/container mode:
PORT=8080 TASK_MANAGER_OWNER=dave TASKS_SERVER_LIVE_SNAPSHOT=1 \
uv run python tasks/tools/run_tasks_server.py --host 0.0.0.0 --port "${PORT}" --owner "${TASK_MANAGER_OWNER}" --no-reload
The tasks server is the primary local workflow for browsing tasks and monitoring task status. It provides:
- / — tasks-root README.md (Master Plans hub). Legacy /tasks/index, /tasks/README, /tasks, and /tasks/ 308 here.
- /tasks/<path> — task plans with a left nav built from tasks/mkdocs.yml (nav config only; MkDocs is not required to read plans), plus Manager (links to /status) at the top of the sidebar. URLs omit .md and directory indexes omit index.md; non-canonical paths 308-redirect to the pretty form.
- /workstreams/... and /milestones/... — same markdown as under tasks/workstreams/ and tasks/milestones/, with shorter canonical URLs (e.g. workstreams/foo/index.md → /workstreams/foo). Requests under /tasks/workstreams/... 308-redirect here.
- /docs and /docs/<path> — legacy bookmark URLs; 308-redirect to the matching canonical path (/tasks/..., /workstreams/..., or /milestones/...).
- /status — same snapshot UI, wrapped in the docs shell and sidebar
- /status.json — raw JSON from the local task-manager heartbeat (same owner as just tasks serve owner=…): in-flight tasks, ready queue, CI hints, etc. Doc pages link to it as Heartbeat snapshot (JSON) in the top-right toolbar.
- /evals/ — eval landing page inside the tasks server, with links to rendered eval dashboards and recent run artifacts.
- /evals/faces/... — rendered pages from the existing apps/evals Dataface project (for example /evals/faces/overview/ and /evals/faces/sql-leaderboard/).
- /evals/artifacts/... — raw eval outputs served directly from apps/evals/runs/.
- /browse/ — plain directory + markdown browser under repo root (escape hatch)
- /actions/dispatch — POST (form): Build on incomplete workstream task pages for loopback clients only (127.0.0.1 / ::1). Runs uv run python tasks/tools/task_cli.py task start --path … then scripts/dispatch in the background. Non-local clients get no Build button and POST returns 404.
For hosted deployments, set TASKS_SERVER_LIVE_SNAPSHOT=1 so /status and /status.json compute a fresh read-only snapshot without requiring the separate local heartbeat loop that just tasks serve starts.
Optional POST hardening:
| Variable | Purpose |
|---|---|
TASKS_SERVER_DISPATCH_TOKEN |
When set, require header X-Tasks-Dispatch-Token on POST /actions/dispatch (browser forms cannot send it — for scripted calls). |
POST also requires a Referer that matches the server’s own origin.
The tasks server now treats apps/evals/ as the in-repo eval project.
apps/evals/runs/<family>/<run_id>/.summary.json, results.jsonl, and any optional static outputs in that run directory./evals/ and /evals/artifacts/./evals/faces/....This keeps eval browsing on the existing tasks/plans server and avoids separate hosting.
On task-plan pages (/tasks/..., /workstreams/..., /milestones/...), {% raw %}{{ ... }}{% endraw %} calls are expanded with Jinja using tasks/macros.py (same functions as the old MkDocs macros plugin). extra.current_milestone is read from tasks/mkdocs.yml.
Use scripts/task-system/* as the canonical local orchestration surface (portable boundary for reuse in other repos):
scripts/task-system/dispatch "<task-slug>" "<prompt>"
scripts/task-system/dispatch-watch "<task-slug>"
scripts/task-system/run --owner dave --interval 60
scripts/task-system/check-status <task-slug-or-path>
Legacy top-level script paths under scripts/ are transitional for compatibility only.
Target: retire direct top-level task-system entrypoints by 2026-04-30 after callers are migrated.