Install
$ agentstack add skill-andyzengmath-quantum-loop-ql-plan ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →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:
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:
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 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 lib/handoff.sh write plan "$(cat ", ""],
"rejected": [""],
"risks": [""],
"files": ["quantum.json"],
"remaining": [""],
"notes": ""
}
JSON
)"
Step 1: Read the PRD
- Look for the most recent PRD in
tasks/prd-*.md - If multiple PRDs exist, ask the user which one to convert
- 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:
- STOP and inform the user
- Explain which stories form the cycle
- 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.
- 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
- Group by category: Organize candidates into logical categories:
secret_keys— shared secret/config key namesenv_vars— environment variable namesshared_types— type names, class names, enum valuesapi_routes— API endpoint pathsevent_names— event/signal namescss_classes— shared CSS class names or design tokens
- Rule: When in doubt, add it — an unused contract entry costs nothing; a missing contract causes cross-story mismatches that require manual fixes
- Optional
patternfield: For values with a naming convention, add apatternregex so the implementer can validate at runtime (e.g.,"pattern": "^[a-z][a-z0-9-]*$")
Example contracts block:
"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:
shape— A structured representation of the type's interface:
properties: Array of{name, type, readonly?}entriesmethods: Array of{name, params: [{name, type}], returns}entries
definition— A verbatim code string in the project's language (see Step 2 for language detection)owner— The story ID that primarily implements/defines the type (usually the story that creates it as an output)consumers— Array of story IDs that reference or depend on the type (all stories except the owner)definitionFile— The file path where the type definition should live (see "InferringdefinitionFilePaths" 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:
src/shared/types/— TypeScript convention (most specific)src/types/— common alternative for TypeScript/generalsrc/interfaces/— common alternative for interface-heavy projectstypes/— project-root convention (some projects keep types at root level)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:
"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:
definitionFilewas inferred from the existingsrc/types/directory (priority item 2), not hardcodedowneris the story that creates the type as its primary outputconsumerslists every other story that references the typeshapeprovides a structured representation that downstream tools can use to generate code ifdefinitionis missingdefinitionprovides 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:
- Changes a return type of a function, method, or class consumed by another story
- Changes parameter types (adding required parameters, removing parameters, or changing parameter types) of a shared function or method
- 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
dependsOnthe contract-breaking story (consumer runs after), OR - The contract-breaking story
dependsOnthe 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.
{
"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.
{
"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.
{
"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
- Source: andyzengmath/quantum-loop
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.