Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "prd",
"version": "5.2.1",
"version": "5.2.2",
"description": "Zero-config goal-to-tasks engine for Claude Code (the Atlas engine). Graded PRD validation, dependency-ordered task graph, and CDD-verified execution.",
"author": {
"name": "Atlas AI",
Expand Down
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,35 @@ All notable changes to this project are documented here. Format based on
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [5.2.2] — 2026-06-14

Front-door UX flow fixes (a UX-flow audit found the *journey* still broke before a
new user reached the 5.2.1 backend fixes). See `docs/audit/UX-FLOW-AUDIT.md`. Also
syncs the version source-of-truth (`prd_taskmaster/__init__.py`), which 5.2.1 missed.

### Fixed
- **UX-P0-1 — the README's first command now resolves.** `README` led with `/atlas`,
which a fresh `/plugin install prd` does not provide (plugin commands are namespaced
`/prd:*`). Added a brand-name `atlas` entrypoint skill (→ `/prd:atlas`, a thin alias
that dispatches to the `go` orchestrator) and updated the README first-run to
`/prd:atlas` (or `/prd:go`, or natural language).
- **UX-P0-2 — phase gates no longer document a self-contradicting STOP.** `setup`/
`discover`/`generate`/`handoff` opened with "if the gate fails, stop" immediately
followed by "it WILL fail on first entry, proceed past it (see morning brief)" — a
compliant autonomous agent would halt. Rewritten to explain `check_gate` is an EXIT
gate (evidence to advance, not to enter), so a first-entry `false` is expected; the
gate is enforced on advance. Removed leaked internal references ("morning brief",
"Mum dogfood feedback").
- **UX-P0-3 — `token_economy` set via `/customise-workflow` is now honored.** It writes
`.atlas-ai/config/atlas.json`, but the engine read economy only from
`.atlas-ai/fleet.json`. `load_fleet_config` now reads `token_economy` from `atlas.json`
when `fleet.json` doesn't set one (fleet.json wins if it does); the config schema doc
adds the key.

### Fixed (version hygiene)
- `prd_taskmaster/__init__.py` version bumped (5.2.1 set `package.json`/`plugin.json` but
missed the `__init__.py` source-of-truth the manifest tests check).

## [5.2.1] — 2026-06-14

Pre-relaunch hardening — fixes the first-run failures a multi-agent audit found
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ npm install -g task-master-ai
Open any project in Claude Code and type:

```
/atlas (or /prd:go, or just say: "I want to build …")
/prd:atlas (or /prd:go, or just say: "I want to build …")
```

Requires Python 3.11+ and Linux / macOS / WSL. The free engine needs **no paid API key** — it
Expand Down
401 changes: 401 additions & 0 deletions docs/audit/UX-FLOW-AUDIT.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "prd-taskmaster",
"version": "5.2.1",
"version": "5.2.2",
"description": "Zero-config goal-to-tasks engine for Claude Code (the Atlas engine)",
"author": {
"name": "Atlas AI",
Expand Down
2 changes: 1 addition & 1 deletion prd_taskmaster/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""prd-taskmaster: zero-config goal-to-tasks engine (deterministic CLI core)."""

__version__ = "5.2.0"
__version__ = "5.2.2"
25 changes: 24 additions & 1 deletion prd_taskmaster/fleet.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,40 @@
BACKEND_CHOICES = {"auto", "taskmaster", "native"}


ATLAS_CONFIG_PATH = Path(".atlas-ai") / "config" / "atlas.json"


def _atlas_config_economy() -> str | None:
"""token_economy set via /customise-workflow (.atlas-ai/config/atlas.json).

/customise-workflow is the discoverable customization tool; the economy a user
sets there must take effect even though the lower-level routing file is fleet.json.
"""
if not ATLAS_CONFIG_PATH.is_file():
return None
try:
raw = json.loads(ATLAS_CONFIG_PATH.read_text())
except (json.JSONDecodeError, OSError):
return None
if not isinstance(raw, dict):
return None
val = raw.get("token_economy")
return val if isinstance(val, str) else None


def load_fleet_config(path=None):
"""Load .atlas-ai/fleet.json merged over defaults.

Malformed files and invalid values fall back to defaults silently —
a broken optional config must never block a fleet run.

Economy precedence: fleet.json (explicit) > atlas.json (/customise-workflow) > default.
"""
cfg = {
"max_concurrency": DEFAULT_FLEET_CONFIG["max_concurrency"],
"routing": dict(DEFAULT_ROUTING),
"experimental_backends": DEFAULT_FLEET_CONFIG["experimental_backends"],
"token_economy": DEFAULT_FLEET_CONFIG["token_economy"],
"token_economy": _atlas_config_economy() or DEFAULT_FLEET_CONFIG["token_economy"],
"backend": DEFAULT_FLEET_CONFIG["backend"],
}
p = Path(path) if path else FLEET_CONFIG_PATH
Expand Down
18 changes: 18 additions & 0 deletions skills/atlas/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
name: atlas
description: >-
The Atlas engine — turn any goal into a validated PRD and an executable, verified
task graph. Brand-name entrypoint; a thin alias for the `go` orchestrator. Use when
the user types /prd:atlas, says "I want to build", or asks for a PRD / task-driven build.
user-invocable: true
allowed-tools:
- Skill
---

# atlas (entrypoint alias)

This is the brand-name entrypoint for the Atlas engine. It holds no procedure of its
own — **immediately invoke the `go` orchestrator** via the Skill tool (`/prd:go`).

`go` reads pipeline state and dispatches to the correct phase
(SETUP → DISCOVER → GENERATE → HANDOFF → EXECUTE). Do not duplicate that routing here.
7 changes: 6 additions & 1 deletion skills/customise-workflow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,11 @@ just that key, re-validate, and re-write.

## Config Schema

`.atlas-ai/config/atlas.json` has 6 top-level keys:
`.atlas-ai/config/atlas.json` has 7 top-level keys:

```json
{
"token_economy": "conservative|balanced|performance",
"provider": {
"main": "gemini-cli|claude-code|anthropic|openai|openrouter|ollama|...",
"model_main": "gemini-3-pro-preview|sonnet|gpt-4o|...",
Expand Down Expand Up @@ -184,6 +185,10 @@ Phase files (`skills/setup`, `skills/discover`, `skills/generate`,
`skills/handoff`, `skills/execute-task`) read this config at runtime and apply
user preferences before falling back to documented defaults.

`token_economy` here is honored by the engine itself: `load_fleet_config` reads it
from this file when `.atlas-ai/fleet.json` does not set one (fleet.json wins if it
does), so the economy you pick via this skill actually drives model-tier routing.

## Customizations directory

For tweaks that go beyond the curated questions — custom template overrides,
Expand Down
23 changes: 11 additions & 12 deletions skills/discover/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,17 @@ skill.**

## Entry gate

1. Call `mcp__plugin_prd_go__check_gate(phase="DISCOVER", evidence={})`.
If the call returns `{gate_passed: false, violations: [...]}`, report the
violations and stop. The gate protects against re-entering a completed
phase or skipping ahead from SETUP.

**Known issue (Mum dogfood feedback [4]):** check_gate is structurally
an EXIT gate. On first DISCOVER entry, evidence=`{}` will fail the
`user_approved=true OR auto_classification=CLEAR with assumptions_documented`
requirement (which the User Approval Gate / Self-Approval Gate below
produces). State machine LEGAL_TRANSITIONS already prevents illegal
entry — proceed past this gate on first entry. Semantic fix in flight
(see morning brief).
1. Call `mcp__plugin_prd_go__check_gate(phase="DISCOVER", evidence={})` for diagnostics.

`check_gate` is an EXIT gate: it verifies the evidence to *advance*, not to *enter*.
On first DISCOVER entry you have no evidence yet (the User Approval / Self-Approval
Gate below produces `user_approved=true` OR `auto_classification=CLEAR with
assumptions_documented`), so a `gate_passed: false` here is EXPECTED — the state
machine's legal transitions already guarantee only legal entry.

- **First entry** (no evidence yet): note the result and continue with the Procedure.
- **Re-entry**: if the gate reports violations, report them and stop — it protects
against re-running a completed phase or skipping ahead from SETUP.
2. Detect execution context. If any of the following signals are present,
switch to Autonomous Mode:
- `.claude/ralph-loop.local.md` exists in the project root
Expand Down
22 changes: 11 additions & 11 deletions skills/generate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ into tasks, expand every task into subtasks. Quality over speed.**

## Entry gate

1. Call `mcp__plugin_prd_go__check_gate(phase="GENERATE", evidence={})`.
If the call returns `{gate_passed: false, violations: [...]}`, report the
violations and stop. The gate protects against re-entering a completed
phase or skipping ahead from DISCOVER.

**Known issue (Mum dogfood feedback [10] — WORST):** check_gate(GENERATE)
currently checks `task_count > 0`, `subtask_coverage >= 1.0`, and
`validation_grade in (EXCELLENT, GOOD)` — all of which are GENERATE's
OWN OUTPUTS, not entry preconditions. First-time entry deadlocks. State
machine LEGAL_TRANSITIONS already prevents illegal entry — proceed past
this gate on first entry. Semantic fix in flight (see morning brief).
1. Call `mcp__plugin_prd_go__check_gate(phase="GENERATE", evidence={})` for diagnostics.

`check_gate` is an EXIT gate: it checks `task_count > 0`, `subtask_coverage >= 1.0`,
and `validation_grade in (EXCELLENT, GOOD)` — all of which are GENERATE's OWN OUTPUTS,
i.e. evidence to *advance*, not preconditions to *enter*. On first entry none exist
yet, so a `gate_passed: false` here is EXPECTED — the state machine's legal
transitions already guarantee only legal entry.

- **First entry** (no evidence yet): note the result and continue with the Procedure.
- **Re-entry**: if the gate reports violations, report them and stop — it protects
against re-running a completed phase or skipping ahead from DISCOVER.
2. Read the DISCOVER output (discovery summary + `CONSTRAINTS CAPTURED` block
+ scale classification). If any of these are missing, report and stop — the
gate should have caught this, but belt-and-braces.
Expand Down
20 changes: 10 additions & 10 deletions skills/handoff/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@ structured choice, dispatch the chosen mode. Mode D executes only on tier=premiu

## Entry gate

1. Call `mcp__plugin_prd_go__check_gate(phase="HANDOFF", evidence={})`.
If the call returns `{gate_passed: false, violations: [...]}`, report the
violations and stop. The gate protects against re-entering a completed
phase or skipping ahead from GENERATE.

**Known issue (Mum dogfood feedback [4]/[10]):** check_gate(HANDOFF)
requires `user_mode_choice` and `plan_file_exists` — both produced by
HANDOFF itself. On first entry, evidence=`{}` will fail. State machine
LEGAL_TRANSITIONS already prevents illegal entry — proceed past this
gate on first entry. Semantic fix in flight (see morning brief).
1. Call `mcp__plugin_prd_go__check_gate(phase="HANDOFF", evidence={})` for diagnostics.

`check_gate` is an EXIT gate: it requires `user_mode_choice` and `plan_file_exists` —
both produced by HANDOFF itself, i.e. evidence to *advance*, not to *enter*. On first
entry neither exists yet, so a `gate_passed: false` here is EXPECTED — the state
machine's legal transitions already guarantee only legal entry.

- **First entry** (no evidence yet): note the result and continue with the Procedure.
- **Re-entry**: if the gate reports violations, report them and stop — it protects
against re-running a completed phase or skipping ahead from GENERATE.
2. Read the GENERATE outputs — `.taskmaster/docs/prd.md`, `.taskmaster/tasks/tasks.json`,
`.taskmaster/reports/task-complexity-report.json`. If any are missing,
report and stop. The gate should have caught this, but belt-and-braces.
Expand Down
25 changes: 12 additions & 13 deletions skills/setup/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,18 @@ Declarative phase skill. Invoked by the prd-taskmaster orchestrator when

## Entry gate

1. Call `mcp__plugin_prd_go__check_gate(phase="SETUP", evidence={})`.
If the call returns `{gate_passed: false, violations: [...]}`, report the
violations and stop. The gate protects against re-entering a completed
phase or skipping ahead.

**Known issue (Mum dogfood feedback [4]):** check_gate semantics are
structurally an EXIT gate (verifies evidence sufficient to advance) but
wired here as an ENTRY gate. On first entry, evidence=`{}` will fail
the SETUP gate's `validate_setup.ready=true` requirement (which Step 4
below produces). State machine LEGAL_TRANSITIONS (`None: ["SETUP"]`)
already prevents illegal entry — proceed past this gate on first entry
and rely on the exit gate for evidence verification. Semantic fix in
flight (see morning brief).
1. Call `mcp__plugin_prd_go__check_gate(phase="SETUP", evidence={})` for diagnostics.

`check_gate` is an EXIT gate: it verifies you have the evidence to *advance*, not to
*enter*. On first entry you have no evidence yet (Step 4 below produces
`validate_setup.ready=true`), so a `gate_passed: false` result here is EXPECTED — the
state machine's legal transitions (`None → SETUP`) already guarantee only legal entry.

- **First entry** (no evidence yet): note the result and continue with the Procedure.
- **Re-entry**: if the gate reports violations, report them and stop — it protects
against re-running a completed phase or skipping ahead.

Enforce the gate when you ADVANCE (after the procedure), not on entry.

## Procedure (5 steps, abort on hard failure)

Expand Down
35 changes: 35 additions & 0 deletions tests/core/test_prerelaunch_ux_fixes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""Pre-relaunch UX-flow regression tests (docs/audit/UX-FLOW-AUDIT.md, 2026-06-14).

UX-P0-3: token_economy is read only from .atlas-ai/fleet.json, but /customise-workflow
writes .atlas-ai/config/atlas.json — so the economy a user sets via the discoverable
customization tool is silently ignored. The engine must honor atlas.json's economy.
"""

import json

from prd_taskmaster.fleet import load_fleet_config


def test_load_fleet_config_reads_token_economy_from_atlas_json(tmp_path, monkeypatch):
monkeypatch.chdir(tmp_path)
cfgdir = tmp_path / ".atlas-ai" / "config"
cfgdir.mkdir(parents=True)
(cfgdir / "atlas.json").write_text(json.dumps({"token_economy": "conservative"}))

assert load_fleet_config()["token_economy"] == "conservative"


def test_fleet_json_token_economy_wins_over_atlas_json(tmp_path, monkeypatch):
"""fleet.json is the lower-level routing file — an explicit value there wins."""
monkeypatch.chdir(tmp_path)
aa = tmp_path / ".atlas-ai"
(aa / "config").mkdir(parents=True)
(aa / "config" / "atlas.json").write_text(json.dumps({"token_economy": "conservative"}))
(aa / "fleet.json").write_text(json.dumps({"token_economy": "performance"}))

assert load_fleet_config()["token_economy"] == "performance"


def test_load_fleet_config_default_economy_when_neither_set(tmp_path, monkeypatch):
monkeypatch.chdir(tmp_path)
assert load_fleet_config()["token_economy"] == "balanced"
Loading