# Ql Plan

> Part of the quantum-loop autonomous development pipeline (brainstorm \u2192 spec \u2192 plan \u2192 execute \u2192 review \u2192 verify). Convert a PRD into machine-readable quantum.json with dependency DAG, granular 2-5 minute tasks, and execution metadata. Use after creating a spec with /quantum-loop:spec. Triggers on: create plan, convert to json, plan tasks, generate quantum json, ql-plan.

- **Type:** Skill
- **Install:** `agentstack add skill-andyzengmath-quantum-loop-ql-plan`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [andyzengmath](https://agentstack.voostack.com/s/andyzengmath)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [andyzengmath](https://github.com/andyzengmath)
- **Source:** https://github.com/andyzengmath/quantum-loop/tree/master/skills/ql-plan

## Install

```sh
agentstack add skill-andyzengmath-quantum-loop-ql-plan
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Quantum-Loop: Plan

You are converting a Product Requirements Document (PRD) into a machine-readable `quantum.json` file that will drive autonomous execution. Every decision you make here determines whether the execution loop succeeds or fails.

## Phase 0: Phase-skip check (Phase 18 / P2.4)

Before reading the PRD, check whether a prior `/ql-plan` run already converted the same PRD + spec handoff into quantum.json:

```bash
PRD=$(ls -t tasks/prd-*.md 2>/dev/null | head -1)
SPEC_HANDOFF=".handoffs/spec.md"
ARGS=()
[[ -n "$PRD" ]]             && ARGS+=("$PRD")
[[ -f "$SPEC_HANDOFF" ]]    && ARGS+=("$SPEC_HANDOFF")

if bash lib/phase-skip.sh skip plan . "${ARGS[@]}"; then
  echo "[SKIP] plan is up-to-date — PRD + spec handoff unchanged."
  bash lib/handoff.sh read plan | jq '.'
  exit 0
fi
```

After writing quantum.json and `.handoffs/plan.md`, record the fingerprint:

```bash
PRD_H=$(bash lib/phase-skip.sh hash "$PRD")
SPEC_H=$(bash lib/phase-skip.sh hash "$SPEC_HANDOFF")
FP=$(jq -cn --arg pp "$PRD" --arg ph "$PRD_H" --arg sp "$SPEC_HANDOFF" --arg sh "$SPEC_H" \
  '{artifacts: [{path: $pp, sha256: $ph}, {path: $sp, sha256: $sh}]}')
bash lib/phase-skip.sh record plan "$FP" . >/dev/null
```

## Prerequisite: read prior-stage handoffs (Phase 15 / P2.3)

Before reading the PRD, ingest every prior-stage handoff so decisions, rejected alternatives, and risks carry forward across context compaction:

```bash
bash lib/handoff.sh all | jq '.'
bash lib/handoff.sh read brainstorm | jq '.'
bash lib/handoff.sh read spec | jq '.'
```

Treat `spec.decided` as binding (these are the ACs you MUST plan for), `spec.rejected` as closed (don't re-introduce), `spec.remaining` as explicit gaps you should surface to the user before finalizing the DAG, and the union of `brainstorm.risks ∪ spec.risks` as mandatory inputs to every story's risk consideration.

At the end of `/ql-plan`, write `.handoffs/plan.md`:

```bash
bash lib/handoff.sh write plan "$(cat ", ""],
  "rejected":  [""],
  "risks":     [""],
  "files":     ["quantum.json"],
  "remaining": [""],
  "notes":     ""
}
JSON
)"
```

## Step 1: Read the PRD

1. Look for the most recent PRD in `tasks/prd-*.md`
2. If multiple PRDs exist, ask the user which one to convert
3. Read the entire PRD, extracting:
   - User stories (US-NNN) with acceptance criteria
   - Functional requirements (FR-N)
   - Technical considerations and constraints
   - Non-goals (to prevent scope creep during execution)

Also read:
- Project files (package.json, pyproject.toml, etc.) for project name and tech stack
- Existing code structure to determine correct file paths for tasks

## Step 2: Analyze Dependencies

Build a dependency graph between stories. Dependencies follow natural layering:

```
1. Schema / Database changes (foundation)
2. Type definitions / Models (depends on schema)
3. Backend logic / API endpoints (depends on types)
4. UI components (depends on API)
5. Integration / Aggregate views (depends on components)
```

### Dependency Rules
- A story that reads from a table DEPENDS ON the story that creates that table
- A story that renders data DEPENDS ON the story that provides the API
- A story that tests integration DEPENDS ON all component stories
- If two stories touch unrelated parts of the codebase, they are INDEPENDENT (no dependency)

### Cycle Detection
After building the dependency graph, verify there are no cycles. If you detect a cycle:
1. STOP and inform the user
2. Explain which stories form the cycle
3. Ask how to break the cycle (usually by splitting a story)

### Contracts Generation (after dependency DAG)

After building the dependency graph, scan for values that appear in 2+ stories' acceptance criteria or task descriptions. These are **contract candidates** — shared constants that parallel agents must agree on.

1. **Identify candidates:** Look for repeated references to the same entity across stories — secret key names, environment variable names, type/class names, API route paths, event names, CSS class names
2. **Group by category:** Organize candidates into logical categories:
   - `secret_keys` — shared secret/config key names
   - `env_vars` — environment variable names
   - `shared_types` — type names, class names, enum values
   - `api_routes` — API endpoint paths
   - `event_names` — event/signal names
   - `css_classes` — shared CSS class names or design tokens
3. **Rule: When in doubt, add it** — an unused contract entry costs nothing; a missing contract causes cross-story mismatches that require manual fixes
4. **Optional `pattern` field:** For values with a naming convention, add a `pattern` regex so the implementer can validate at runtime (e.g., `"pattern": "^[a-z][a-z0-9-]*$"`)

Example contracts block:
```json
"contracts": {
  "secret_keys": {
    "openai": { "value": "openai-api-key", "pattern": "^[a-z][a-z0-9-]*$" },
    "db_password": { "value": "DATABASE_PASSWORD" }
  },
  "shared_types": {
    "priority_enum": { "value": "Priority" }
  }
}
```

Add the `contracts` object to quantum.json at the top level, after `codebasePatterns`.

For language-specific shape and definition examples, read `references/contract-shapes.md` when generating structural contracts for shared types.

### Structural Contract Generation (Enhanced)

After building the basic contracts block above, enhance `shared_types` entries with structural information so that downstream layers (materialization, type audit) can generate real code files.

#### Step 1: Detect Shared Types

Scan all stories' descriptions, acceptance criteria, and task descriptions for type names (classes, interfaces, structs, enums) that appear in **2 or more stories**. These are structural contract candidates.

For each shared type candidate:
1. **`shape`** — A structured representation of the type's interface:
   - `properties`: Array of `{name, type, readonly?}` entries
   - `methods`: Array of `{name, params: [{name, type}], returns}` entries
2. **`definition`** — A verbatim code string in the project's language (see Step 2 for language detection)
3. **`owner`** — The story ID that primarily implements/defines the type (usually the story that creates it as an output)
4. **`consumers`** — Array of story IDs that reference or depend on the type (all stories except the owner)
5. **`definitionFile`** — The file path where the type definition should live (see "Inferring `definitionFile` Paths" below)

**Anti-rationalization:** If 2+ stories reference a type by name, you MUST generate `shape` and `definition` fields. "It's only used lightly" or "the shape is obvious" are not valid reasons to skip structural contracts. The downstream materializer cannot generate a file without a `definition` or `shape`.

#### Step 2: Detect Project Language

Determine the project's primary language by checking for config files in the project root:

| Config File | Language | `definition` Style |
|---|---|---|
| `tsconfig.json` | TypeScript | `export interface X { ... }` or `export type X = { ... }` |
| `pyproject.toml` or `setup.py` | Python | `class X(Protocol): ...` or `@dataclass class X: ...` |
| `go.mod` | Go | `type X interface { ... }` or `type X struct { ... }` |

Detection priority: check in the order listed above. If multiple config files exist, use the `definitionFile` extension as a tiebreaker.

#### Step 3: Generate Language-Specific Definitions

Based on the detected language, generate the `definition` string:

**TypeScript:**
```
export interface TaskResult {
  id: string;
  status: "pending" | "passed" | "failed";
  output: string;
  errorMessage?: string;
}
```

**Python:**
```
from dataclasses import dataclass
from typing import Optional

@dataclass
class TaskResult:
    id: str
    status: str  # "pending" | "passed" | "failed"
    output: str
    error_message: Optional[str] = None
```

**Go:**
```
type TaskResult struct {
    ID           string `json:"id"`
    Status       string `json:"status"`
    Output       string `json:"output"`
    ErrorMessage string `json:"errorMessage,omitempty"`
}
```

#### Step 4: Reference for Examples

See `references/contract-shapes.md` for complete examples of `shape` JSON paired with `definition` strings for all three languages. Load this reference when shared types are detected — it contains guidance on when to generate `definition` (multi-consumer types) vs shape-only (advisory, single-consumer types).

#### Step 5: Inferring `definitionFile` Paths

When a contract entry does not have an explicit `definitionFile`, infer the path from the project's existing directory structure. Check directories in this priority order:

1. `src/shared/types/` — TypeScript convention (most specific)
2. `src/types/` — common alternative for TypeScript/general
3. `src/interfaces/` — common alternative for interface-heavy projects
4. `types/` — project-root convention (some projects keep types at root level)
5. `shared/` — Python and Go convention

**If a matching directory exists**, use it as the base path for the `definitionFile`. Append the type name in kebab-case with the appropriate language extension (`.ts`, `.py`, `.go`).

**If none of these directories exist**, default based on the detected language:
- **TypeScript:** `src/shared/types/.ts`
- **Python:** `src/shared/.py`
- **Go:** `internal/shared/.go`

**If `definitionFile` IS explicitly set** in a contract entry (e.g., from user input or a previous run), it takes precedence over any inference. Do not override explicit paths.

#### Complete Enhanced Contract Example

Below is a complete example of a `contracts.shared_types` entry with all enhanced fields. This demonstrates a `TaskResult` type shared between US-003 (which implements it) and US-007/US-009 (which consume it), in a TypeScript project that has an existing `src/types/` directory:

```json
"contracts": {
  "shared_types": {
    "task_result": {
      "value": "TaskResult",
      "pattern": "^[A-Z][a-zA-Z]*$",
      "definitionFile": "src/types/task-result.ts",
      "owner": "US-003",
      "consumers": ["US-007", "US-009"],
      "shape": {
        "properties": [
          { "name": "id", "type": "string" },
          { "name": "status", "type": "'pending' | 'passed' | 'failed'" },
          { "name": "output", "type": "string" },
          { "name": "errorMessage", "type": "string", "readonly": false }
        ],
        "methods": []
      },
      "definition": "export interface TaskResult {\n  id: string;\n  status: 'pending' | 'passed' | 'failed';\n  output: string;\n  errorMessage?: string;\n}"
    }
  }
}
```

Key points:
- `definitionFile` was inferred from the existing `src/types/` directory (priority item 2), not hardcoded
- `owner` is the story that creates the type as its primary output
- `consumers` lists every other story that references the type
- `shape` provides a structured representation that downstream tools can use to generate code if `definition` is missing
- `definition` provides the verbatim code string in the detected language (TypeScript in this case)

#### Stories with No Shared Types

If no type names appear in 2+ stories, do NOT generate `shape` or `definition` fields. The basic contracts block (with `value` and optional `pattern`) is sufficient. This maintains backward compatibility — entries with only `value` and `pattern` remain valid.

### Interface Change Detection

When a story modifies the return type, parameter types, or function/method signatures of code consumed by other stories, it creates a **contract-breaking change**. These changes require explicit coordination to prevent regressions in parallel execution.

#### When to Set `contractBreaking: true`

Set `contractBreaking: true` on any story that:

1. **Changes a return type** of a function, method, or class consumed by another story
2. **Changes parameter types** (adding required parameters, removing parameters, or changing parameter types) of a shared function or method
3. **Changes a class/interface signature** (renaming methods, changing method visibility, altering inheritance) that other stories depend on

When `contractBreaking` is set, the story description **MUST** include an explanation of what interface changed and why. This explanation helps the execution engine and human reviewers understand the blast radius.

#### When to Set `fixes`

Set `fixes: ["US-XXX"]` on any story that is specifically designed to resolve regressions or breakage introduced by another story. The `fixes` field is an array of story IDs whose regressions this story addresses.

#### Scheduling Constraint

Stories with `contractBreaking: true` **MUST** have explicit `dependsOn` edges that prevent them from being co-scheduled (running in the same wave) with any story that consumes the changed interface. This ensures consumers always see the final version of the interface, not an in-flight breaking change.

**Rule:** For every consumer of the changed interface, either:
- The consumer `dependsOn` the contract-breaking story (consumer runs after), OR
- The contract-breaking story `dependsOn` the consumer (breaking change runs after consumer finishes with old interface)

#### Examples

**Example 1: Breaking change to a shared interface**

US-003 changes the return type of `IParser.parse()` from `string` to `ParseResult`. US-005 and US-008 both call `IParser.parse()`. This is a contract-breaking change because consumers expect the old return type.

```json
{
  "id": "US-003",
  "title": "Refactor IParser.parse() to return ParseResult",
  "description": "Changes IParser.parse() return type from string to ParseResult. This is contractBreaking because US-005 and US-008 consume IParser.parse() and expect the old return type.",
  "contractBreaking": true,
  "dependsOn": [],
  "storyType": "logic"
}
```

US-005 and US-008 must add `"US-003"` to their `dependsOn` arrays so they run after the breaking change lands.

**Example 2: Fixing regressions from a breaking change**

US-004 is created specifically to fix async regressions introduced by US-003's interface change. It patches call sites that were missed or broke unexpectedly.

```json
{
  "id": "US-004",
  "title": "Fix async regressions from IParser refactor",
  "description": "Fixes async call sites that broke when US-003 changed IParser.parse() return type.",
  "fixes": ["US-003"],
  "dependsOn": ["US-003"],
  "storyType": "logic"
}
```

**Example 3: Non-breaking change (no flag needed)**

US-007 adds an optional `verbose` parameter with a default value to `IParser.parse()`. Existing callers continue to work without modification because the parameter is optional.

```json
{
  "id": "US-007",
  "title": "Add optional verbose parameter to IParser.parse()",
  "description": "Adds optional verbose parameter with default false. Existing callers are unaffected.",
  "dependsOn": ["US-003"],
  "storyType": "logic"
}
```

Note: `contractBreaking` is **NOT** set because adding an optional parameter with a default value does not change the interface for existing consumers.

### Story Type Tagging

After building the dependency DAG and contracts, assign a `storyType` field to every story. This field is used by the dag-validator to determine which restructuring is safe.

#### Allowed Values

| `storyType` | Description |
|---|---|
| `types-only` | Stories where ALL tasks create type definitions, interfaces, schemas, or `.d.ts` files with no runtime logic. |
| `config` | Scaffold/config-only stories: migrations, `package.json` changes, Dockerfile, CI yaml, pure markdown. |
| `test` | Stories that only add tests with no new source code. |
| `logic` | Everything else (the default). Any story with business logic, API handlers, data processing, or external API calls. |

#### Examples

**`types-only`** — `US-001: Define TaskResult interface`
Tasks only create `.ts` interface files (e.g., `src/types/task-result.ts`). No runtime logic, no function bodies, no side effects — purely structural type definitions.

**`config`** — `US-002: Set up database migration`
Tasks o

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [andyzengmath](https://github.com/andyzengmath)
- **Source:** [andyzengmath/quantum-loop](https://github.com/andyzengmath/quantum-loop)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-andyzengmath-quantum-loop-ql-plan
- Seller: https://agentstack.voostack.com/s/andyzengmath
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
