Spec-driven, BDD-shaped project management for AI agents — author once in OpenSpec, sync to GitHub Issues, Azure DevOps Boards, Jira, Linear, or GitLab.
OpenSpecPM turns natural-language intent ("plan X", "sync the X epic", "what's blocked", "ship X") into a disciplined flow:
flowchart LR
Idea["💡 **Idea**"]
Proposal["📝 **proposal.md**<br/>(OpenSpec)"]
BDD["📋 **BDD specs**<br/>Given / When / Then"]
Tasks["✅ **tasks**"]
Tracked["🎯 **Tracked work items**<br/>GitHub · ADO · Jira · Linear · GitLab"]
Shipped["🚀 **Shipped code**"]
Idea --> Proposal --> BDD --> Tasks --> Tracked --> Shipped
classDef ideaC fill:#FFF9C4,stroke:#F9A825,color:#000
classDef artifactC fill:#D5E8D4,stroke:#82B366,color:#000
classDef extC fill:#DAE8FC,stroke:#6C8EBF,color:#000
classDef doneC fill:#C8E6C9,stroke:#2E7D32,color:#000
class Idea ideaC
class Proposal,BDD,Tasks artifactC
class Tracked extC
class Shipped doneC
It is a sibling of CCPM, with five differences:
- OpenSpec drives spec authoring + BDD scenarios become enforceable. Every feature gets
proposal.md,design.md,tasks.md, and aspecs/folder of Given/When/Then scenarios. A heuristic linter blocks vague Thens atsynctime. An optional LLM judge (Claude Haiku 4.5, opt-in via--llm) catches cross-spec contradictions and missing-coverage gaps the regex linter can't see. - Five pluggable PM backends — an interactive wizard at
inittime picks GitHub Issues/Projects, Azure DevOps Boards, Jira, Linear, or GitLab. New backends register without forking viaregisterAdapter(). - Built for non-engineers too — PMs/BAs/PgMs can drive the flow. A
doctorcommand owns auth-setup pain (with--installand--setup-authflags for OS-specific install hints and PAT-creation URLs). Worktrees are hidden by default. - Audit-logged by default. Every command appends a JSONL entry (secrets scrubbed) to
.openspecpm/audit.log. Useful for regulated industries that need a paper trail; useful for the rest of us when something looks weird. - Cross-feature task graphs.
depends_on:can reach across changes (<feature>/<task-title>or<feature>/<external-id>), sonextandblockedreflect the whole project rather than one feature in isolation.
flowchart TD
PM([👤 Project Manager / BA])
Dev([👤 Developer])
Agent([🤖 AI Agent · Claude Code])
Skill["**Agent Skill**<br/>skill/openspecpm/SKILL.md<br/><br/>Routes natural-language intent"]
CLI["**Node CLI**<br/>cli/bin/openspecpm.js<br/><br/>Commander dispatch + audit"]
subgraph CMDS["📋 Commands · cli/src/commands/"]
direction LR
Setup["**① Setup**<br/>init • doctor"]
Plan["**② Plan**<br/>propose • decompose"]
SyncCmd["**③ Sync**<br/>sync • comment • reconcile<br/>assign • bug-report"]
Track["**④ Track**<br/>status • standup • next<br/>blocked • validate • search • watch"]
Exec["**⑤ Execute / Ship**<br/>fan-out • ship • help-table"]
end
subgraph CORE["⚙️ Core services · cli/src/"]
direction LR
Bridge["**OpenSpec Bridge + BDD**<br/>openspec-bridge.js<br/>bdd/linter.js"]
TrackingS["**Tracking + Audit**<br/>tracking.js<br/>audit.js"]
HTTP["**HTTP + Rate-limit**<br/>http.js<br/>ratelimit.js"]
IO["**Config + Notify + Telemetry**<br/>config.js • notify.js<br/>telemetry.js"]
end
subgraph ADAPTERS["🔌 Adapter contract · cli/src/adapters/ · 9 methods + capabilities()"]
direction LR
GHA["**GitHub**<br/>depth 2"]
AzA["**Azure DevOps**<br/>depth 4"]
JiA["**Jira**<br/>depth 3"]
LiA["**Linear**<br/>depth 2"]
GlA["**GitLab**<br/>depth 2"]
end
subgraph EXT["☁️ External PM systems"]
direction LR
GHE[("GitHub<br/>Issues / Projects")]
AzE[("Azure DevOps<br/>Boards")]
JiE[("Jira<br/>Cloud / Server")]
LiE[("Linear")]
GlE[("GitLab<br/>Issues")]
end
subgraph PERSIST["💾 Persistence & sinks"]
direction LR
FS1["📁 **openspec/**<br/>changes/<feature>/<br/>• proposal.md<br/>• specs/*.md (BDD)<br/>• tasks.md<br/>• updates/progress.md"]
FS2["📁 **.openspecpm/**<br/>• config.json<br/>• audit.log (JSONL)<br/>• state.json"]
Sinks["🔔 **Webhooks**<br/>• Slack<br/>• Teams<br/>• Generic JSON"]
end
PM --> Skill
Dev --> CLI
Agent --> Skill
Skill -- invokes --> CLI
CLI --> CMDS
CMDS --> CORE
CORE --> ADAPTERS
GHA --> GHE
AzA --> AzE
JiA --> JiE
LiA --> LiE
GlA --> GlE
Bridge -. writes .-> FS1
TrackingS -. writes .-> FS1
IO -. writes .-> FS2
IO -. broadcast .-> Sinks
classDef user fill:#DAE8FC,stroke:#6C8EBF,color:#000
classDef agent fill:#FFE0B2,stroke:#D97757,color:#000
classDef entry fill:#C5E1A5,stroke:#558B2F,color:#000
classDef skill fill:#FFE0B2,stroke:#D97757,color:#000
classDef github fill:#222,stroke:#000,color:#fff
classDef azure fill:#0078D7,stroke:#005A9E,color:#fff
classDef jira fill:#0052CC,stroke:#003580,color:#fff
classDef linear fill:#5E6AD2,stroke:#3F47A0,color:#fff
classDef gitlab fill:#FC6D26,stroke:#C44A19,color:#fff
classDef ext fill:#fff,stroke:#333,stroke-width:3px,color:#000
classDef fs fill:#fff,stroke:#444,stroke-width:2px,color:#000
class PM,Dev user
class Agent agent
class CLI entry
class Skill skill
class GHA github
class AzA azure
class JiA jira
class LiA linear
class GlA gitlab
class GHE,AzE,JiE,LiE,GlE ext
class FS1,FS2,Sinks fs
flowchart LR
Idea["💡 **Idea**<br/>stakeholder feature,<br/>bug, or refactor"]
subgraph P1["① PLAN"]
direction TB
Propose["**openspecpm propose**<br/>Shells out to OpenSpec<br/>Soft BDD lint"]
Decompose["**openspecpm decompose**<br/>Extract tasks from<br/>proposal + BDD"]
Propose --> Decompose
end
subgraph P2["② REVIEW + SYNC"]
direction TB
Review["👀 **Human review**<br/>Sign off on BDD"]
Validate["**openspecpm validate**<br/>Schema + BDD sweep"]
SyncCmd["**openspecpm sync**<br/>Hard BDD lint<br/>Idempotent"]
Review --> Validate --> SyncCmd
end
subgraph P3["③ EXECUTE"]
direction TB
Next["**openspecpm next**"]
FanOut["**openspecpm fan-out**<br/>Parallel agent prompts"]
Build["🤖 **Implement**<br/>BDD = acceptance criteria"]
Comment["**openspecpm comment**<br/>Broadcast progress"]
Reconcile["**openspecpm reconcile**<br/>Pull remote state"]
Next --> FanOut --> Build --> Comment --> Reconcile
end
subgraph P4["④ TRACK"]
direction TB
Status["**Track commands**<br/>status • standup<br/>blocked • search<br/>watch • bug-report"]
end
subgraph P5["⑤ SHIP"]
direction TB
Ship["**openspecpm ship**<br/>Close tasks + epic<br/>Archive change"]
Shipped["🚀 **Shipped**"]
Ship --> Shipped
end
Idea --> P1
P1 --> P2
P2 --> P3
P3 --> P4
P4 --> P5
Shipped -. next feature .-> Idea
classDef ideaC fill:#FFF9C4,stroke:#F9A825,color:#000
classDef cmdC fill:#D5E8D4,stroke:#82B366,color:#000
classDef humanC fill:#FFF9C4,stroke:#F9A825,color:#000
classDef agentC fill:#FFE0B2,stroke:#D97757,color:#000
classDef shipC fill:#FFCDD2,stroke:#D32F2F,color:#000
classDef doneC fill:#C8E6C9,stroke:#2E7D32,color:#000
class Idea ideaC
class Propose,Decompose,Validate,SyncCmd,Next,FanOut,Comment,Reconcile,Status cmdC
class Review humanC
class Build agentC
class Ship shipC
class Shipped doneC
Cross-cutting on every command: audit log (
.openspecpm/audit.log, secrets scrubbed) · token-bucket rate-limiting per adapter · OpenSpec version probe · optional opt-in telemetry · optional Slack / Teams / generic-webhook broadcasts onstandup --broadcast.
# Standalone CLI (any harness)
npx openspecpm@latest init
# Claude Code Agent Skill
# Copy skill/openspecpm/ into your Claude Code skills directory.
# SKILL.md handles routing — just talk to Claude.OpenSpecPM shells out to OpenSpec; install it first:
npm install -g @fission-ai/openspecA walkthrough of OpenSpecPM running against two sample features (
dark-mode,auth-rate-limit). Source images live indocs/screenshots/; regenerate withpwsh docs/screenshots/render.ps1after CLI output changes — the renderer sets up its own sample data and cleans up after itself.
1 · Phase-grouped command reference — help-table shows every command grouped by workflow phase (Setup → Plan → Sync → Track → Execute/Ship):
2 · Health check across every adapter — doctor diagnoses auth + tooling for all five backends (GitHub, Azure DevOps, Jira, Linear, GitLab) with an English remediation hint on every failure. The [judge] section reports ANTHROPIC_API_KEY for the optional LLM BDD judge:
3 · Author a proposal — propose --offline scaffolds proposal.md, tasks.md, and specs/main.md from templates without calling the OpenSpec CLI. Soft BDD lint runs immediately so placeholder Then-clauses are flagged before you keep editing:
4 · Optional LLM BDD judge — pass --llm (or set judge.enabled: true in .openspecpm/config.json) to augment the heuristic linter with Claude Haiku 4.5. The judge catches what regex can't: cross-spec contradictions (bdd/llm-contradiction), success criteria with no scenario (bdd/llm-missing-coverage), and Then-clauses that pass the verb check but state no observable outcome (bdd/llm-vague-then). Findings merge into the same lint stream and respect --force the same way. Prompt-cached on the proposal so re-runs across multiple specs stay cheap. Sample output below — real findings vary per scenario set; the judge can't be regenerated by render.ps1 because it requires a live ANTHROPIC_API_KEY:
5 · Decompose into tasks — decompose walks proposal headings, GitHub-style checklists, a Tasks section, and BDD scenarios under specs/ and writes a structured tasks.md with sync_state frontmatter:
6 · Multi-feature status — status shows the configured adapter and per-change task counts (synced / pending / failed / done) at a glance:
7 · "What can I work on right now?" — next lists tasks with no unmet dependencies, marking parallel-safe ones so multiple agents can pick them up:
8 · "What's waiting on what?" — blocked lists every task held up by a dependency and names the blocker, so the path to unblocking is one read away:
9 · Parallel-agent dispatch — fan-out emits ready-to-paste prompts for parallel: true tasks with no unmet deps. Each prompt embeds the proposal summary, design notes, and BDD spec as acceptance criteria so subagents can work in isolation:
10 · Cross-file search — search is a case-insensitive grep across every proposal, spec, tasks file, and progress note. Useful for tracing back from a keyword to the change that owns it:
11 · Project-wide validation — validate runs the schema check and BDD linter across every change and reports per-feature error + warning counts:
# 1. One-time setup. The wizard asks which PM tool your team uses.
npx openspecpm init
# 2. Verify auth before doing anything remote.
npx openspecpm doctor
# 3. Author a proposal. OpenSpec generates proposal.md, design.md, tasks.md,
# and BDD scenarios in specs/. Soft BDD-lint runs after authoring.
npx openspecpm propose dark-mode --prompt "Per-user dark theme with persistence."
# 4. Review the generated files. Refine BDD scenarios until lint is clean.
# 5. Sync to the PM tool. Hard BDD lint runs first; pass --force to override.
npx openspecpm sync dark-mode
# 6. Pick up where you left off.
npx openspecpm next # tasks ready to start
npx openspecpm blocked # tasks waiting on dependencies
npx openspecpm standup # progress updates in the last 24h
# 7. When the feature is verified, close + archive.
npx openspecpm ship dark-mode| Command | What it does |
|---|---|
init |
Interactive wizard. Picks the PM tool. Writes .openspecpm/config.json. |
doctor [adapter] |
Auth/tooling health check. English remediation hints on every failure. |
propose <feature> [--llm] |
Shell out to OpenSpec; create openspec/changes/<feature>/. Soft-lint BDD scenarios; --llm adds the LLM judge. |
decompose <feature> |
Extract tasks from proposal headings/checklists + BDD scenarios into tasks.md. |
sync <feature> [--llm] |
Hard-lint BDD, then create/update work items in the PM tool. Idempotent; --llm adds the LLM judge as a hard gate. |
comment <feature> <task> |
Broadcast local progress.md (or -m) to the PM tool with <!-- SYNCED --> marker. |
reconcile <feature> |
Pull remote work-item state into local frontmatter. Detects out-of-band closes. |
bug-report <feature> <task> --title "…" |
File a linked regression against a shipped task. |
status |
Per-change task counts: pending / created / failed / done. |
standup [--since 24h] |
Recent progress.md updates, newest first. |
next [-l 5] |
Tasks with no unmet dependencies. |
blocked |
Tasks waiting on unmet dependencies (with reasons). |
validate [--llm] |
Schema + dependency + BDD-lint sweep across every change; --llm adds the LLM judge per change. |
search <query> |
Grep across proposals, specs, tasks, progress notes. |
fan-out <feature> |
Emit ready-to-paste agent prompts for parallel: true tasks. |
ship <feature> [-y] |
Close all task work items + close the epic + archive the OpenSpec change. |
help-table [topic] |
Context-aware command reference grouped by workflow phase. |
Every command appends a JSONL entry (secrets scrubbed) to .openspecpm/audit.log.
OpenSpecPM is organized into five phases, each with a reference doc under skill/openspecpm/references/:
- Plan (
plan.md) — Capture requirements through an OpenSpec proposal + BDD scenarios. - Structure (
structure.md) — Decompose into tasks with explicit dependencies and parallelism hints. - Sync (
sync.md) — Push to the PM tool. Capabilities-driven hierarchy collapse for flatter backends. - Execute (
execute.md) — Start work on a tracked item. Optional worktrees, parallel-agent dispatch. - Track (
track.md) — Status, standup, next, blocked, ship.
- Adapter contract. Every backend implements the same 9-method interface plus
capabilities()reporting hierarchy depth (GitHub=2, Linear=2, GitLab=2, Jira=3, ADO=4). The sync layer collapses levels gracefully. - OpenSpec anti-corruption layer. Version-pinned probe on every CLI invocation. One constant absorbs upstream path moves.
- Idempotent sync. Each task carries
sync_state+external_idin frontmatter. Re-runningsyncskips created items and retries failures. Comments use<!-- SYNCED: <ts> -->markers to prevent duplication. - Token-bucket rate-limiting. Per-adapter presets tuned for each backend's published limits.
- BDD linter. Heuristic checks: one Given/When/Then per scenario, observable verbs in Then, deny-list for vague phrases ("should work"), tautology detection via word-bigram similarity.
- Optional LLM judge.
--llm(orjudge.enabled: truein.openspecpm/config.json) augments the heuristic linter with Claude Haiku 4.5 to catch cross-spec contradictions, missing success-criteria coverage, and vague Then predicates the regex linter misses. Uses prompt caching on the proposal so re-runs across multiple specs stay cheap. RequiresANTHROPIC_API_KEY—openspecpm doctorreports its presence.
Active v2 work is tracked as OpenSpec changes under openspec/changes/. The first scaffolded feature — bdd-llm-reviewer — shipped in v1.0.0. Five remain: dependency-graph visualization, spec → test scaffolding, compliance traceability export, three new adapters (Notion / ClickUp / Asana), and a real agent orchestrator that graduates fan-out from prompt-emitter to dispatcher.
OpenSpecPM dogfoods itself: anyone can openspecpm next to see what's ready to start, or openspecpm sync <change> to push any of the five into a tracked PM tool.
openspecpm/
├── README.md this file
├── LICENSE MIT
├── CHANGELOG.md
├── CONTRIBUTING.md
├── SECURITY.md
├── package.json
├── .github/
│ ├── workflows/ test.yml · auto-approve.yml · release.yml · publish.yml
│ ├── ISSUE_TEMPLATE/
│ └── PULL_REQUEST_TEMPLATE.md
├── docs/screenshots/ README captures + render.ps1 renderer
├── openspec/changes/ v2 roadmap (each subdir is a tracked change)
├── skill/openspecpm/ Claude Code Agent Skill
│ ├── SKILL.md
│ └── references/ conventions · plan · structure · sync · execute · track
└── cli/
├── bin/openspecpm.js Commander entrypoint
├── src/
│ ├── commands/ init · doctor · propose · decompose · sync · comment · reconcile ·
│ │ status · standup · next · blocked · validate · search · fan-out ·
│ │ bug-report · ship · assign · watch · help · bulk
│ ├── adapters/ base · github · azure · jira · linear · gitlab · index
│ ├── bdd/ linter · judge · templates
│ ├── audit.js JSONL audit log + secret scrubber
│ ├── http.js REST helper for ADO / Jira / Linear / GitLab
│ ├── tracking.js listChanges · findNext · findBlocked · findRecent
│ ├── notify.js Slack / Teams / generic-webhook envelopes
│ ├── telemetry.js opt-in, audit-log-only at alpha
│ ├── install-hints.js
│ ├── openspec-bridge.js
│ ├── config.js
│ ├── frontmatter.js
│ └── ratelimit.js
└── tests/ unit + contract tests (count badge is auto-updated by CI)










