Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions mcp-server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,29 @@ def claim_task(tag: str = "") -> dict:


@mcp.tool()
def set_task_status(id: str, status: str, tag: str = "") -> dict:
"""Set a task or subtask status without terminating the MCP host."""
def set_task_status(
id: str,
status: str,
tag: str = "",
evidence_ref: str | None = None,
reachability: dict | None = None,
) -> dict:
"""Set a task or subtask status without terminating the MCP host.

For status != "done": evidence_ref and reachability are ignored.
For status == "done" on a wired/live task: reachability must be provided
with verdict in {WIRED, EXEMPT}. Pass the dict returned by the
reachability sweep (mcp__atlas-engine__check_gate / sweep_task).
Evidence is persisted on the task when provided (any tier).
"""
try:
return TS.run_set_status(id_str=id, status=status, tag=tag or None)
return TS.run_set_status(
id_str=id,
status=status,
tag=tag or None,
evidence_ref=evidence_ref,
reachability=reachability,
)
except LIB.CommandError as exc:
return {"ok": False, "error": exc.message, **exc.extra}

Expand Down
15 changes: 13 additions & 2 deletions prd_taskmaster/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ def rate(self, tag=None, research=True) -> dict: ...
"status": "pending",
"dependencies": [],
"priority": "high",
"tier": "domain-model",
"reachableVia": "",
"subtasks": [
{
"id": 1,
Expand All @@ -66,7 +68,12 @@ def rate(self, tag=None, research=True) -> dict: ...
task must include id, title, description, details, testStrategy, status,
dependencies, priority, and at least 2 subtasks; dependencies must reference
existing task or sibling subtask IDs; use only priority high, medium, or low;
do not include placeholders, generic tasks, or empty testStrategy fields."""
do not include placeholders, generic tasks, or empty testStrategy fields;
tier ∈ {spike|domain-model|wired|live}: the altitude of the claim — spike=research,
domain-model=pure logic, wired=integration, live=user-visible; wired/live require
reachability evidence (the deterministic enrich step will set this if omitted);
reachableVia names the existing route/component/CLI/tool/API the new code wires into;
required for wired/live tasks (a task naming no consumer is an orphan by design)."""


PARALLEL_RESULT_SCHEMA_HINT = """{
Expand Down Expand Up @@ -237,6 +244,7 @@ def _task_summaries(tasks: list[dict]) -> list[dict]:
"dependencies": task.get("dependencies") or [],
"status": task.get("status", "pending"),
"subtask_count": len(task.get("subtasks") or []),
"reachableVia": task.get("reachableVia", ""),
})
return summaries

Expand Down Expand Up @@ -360,7 +368,10 @@ def parse_prd(self, prd_path, num_tasks, tag=None) -> dict:
prompt = (
f"Parse this PRD into exactly {num_tasks} TaskMaster-compatible tasks.\n"
f"Target tag: {tag or parallel.current_tag(None)}.\n"
"Return only the tasks JSON object.\n\n"
"Return only the tasks JSON object.\n"
"For wired/live tier tasks, set reachableVia to the existing route, component, CLI, "
"tool, or API that this task's code wires into (e.g. 'route:/api/v1/orders', "
"'cli:prd-taskmaster', 'component:OrdersTable').\n\n"
f"PRD PATH: {path}\n"
f"PRD:\n{prd_text}"
)
Expand Down
33 changes: 33 additions & 0 deletions prd_taskmaster/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from prd_taskmaster.feedback import HARNESS_CHOICES, cmd_feedback_add, cmd_feedback_report
from prd_taskmaster.context_pack import build_context_pack
from prd_taskmaster import fleet, parallel, task_state, tm_parallel
from prd_taskmaster.reachability_cmd import cmd_reachability_sweep


def _backend_source() -> str:
Expand Down Expand Up @@ -322,6 +323,37 @@ def build_parser() -> argparse.ArgumentParser:
p.add_argument("--id", required=True)
p.add_argument("--status", required=True)
p.add_argument("--tag")
p.add_argument(
"--evidence-ref",
default=None,
help="Path or ref to the CDD evidence card for this task",
)
p.add_argument(
"--reachability",
default=None,
help=(
"Reachability verdict: bare string (WIRED|EXEMPT|ORPHAN) or a JSON dict. "
"When omitted and marking done, the verdict is auto-read from the task's "
"CDD card .atlas-ai/cdd/task-<id>.json if present."
),
)

# reachability-sweep
p = sub.add_parser(
"reachability-sweep",
help="Run the reachability sweep for a task and write the verdict into its CDD card",
)
p.add_argument("--task", required=True, help="Task id (e.g. 1 or 1.2)")
p.add_argument(
"--start-commit",
required=True,
help="Git SHA recorded when work on this task began (git rev-parse HEAD at task start)",
)
p.add_argument(
"--cwd",
default=None,
help="Explicit repo root (defaults to the current working directory)",
)

# status — render progress panels
p = sub.add_parser("status", help="Render Atlas progress panels for the current phase")
Expand Down Expand Up @@ -379,6 +411,7 @@ def cmd_status(args) -> None:
"next-task": task_state.cmd_next_task,
"claim-task": task_state.cmd_claim_task,
"set-status": task_state.cmd_set_status,
"reachability-sweep": cmd_reachability_sweep,
"economy-report": cmd_economy_report,
"context-pack": cmd_context_pack,
"feedback-add": cmd_feedback_add,
Expand Down
2 changes: 2 additions & 0 deletions prd_taskmaster/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,12 @@ def _tag_task_lists(tasks: dict) -> dict[str, list[dict]]:
def _count_tasks(items: list[dict]) -> dict[str, int]:
total = len(items)
done = sum(1 for item in items if item.get("status") == "done")
scaffold = sum(1 for item in items if item.get("status") == "scaffold")
return {
"total": total,
"pending": total - done,
"done": done,
"scaffold": scaffold,
}


Expand Down
Loading
Loading