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
Expand Up @@ -7,5 +7,5 @@
},
"repository": "https://github.com/patdhlk/pharaoh",
"license": "MIT",
"keywords": ["sphinx-needs", "requirements", "traceability", "change-analysis", "mece", "safety-critical", "automotive"]
"keywords": ["sphinx-needs", "requirements", "traceability", "change-analysis", "mece", "safety-critical", "automotive", "decisions"]
}
118 changes: 118 additions & 0 deletions .github/agents/pharaoh.decide.agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
description: Record a design decision as a traceable sphinx-needs object with alternatives, rationale, and links to affected requirements.
handoffs:
- label: Verify Decision
agent: pharaoh.verify
prompt: Verify the decision need has valid links and fields
- label: Trace Decision
agent: pharaoh.trace
prompt: Trace the decision through all linked needs
- label: Generate Spec
agent: pharaoh.spec
prompt: Generate a spec document from the affected requirements
---

# @pharaoh.decide

Record design decisions as `decision` needs with `decided_by`, `alternatives`, `rationale` fields and `:decides:` links. Delegates RST writing to @pharaoh.author to avoid duplicating directive-writing logic.

## Data Access

1. **ubc CLI**: `ubc build needs --format json` for index, `ubc config` for schema.
2. **ubCode MCP**: Pre-indexed needs data.
3. **Raw file parsing**: Read `ubproject.toml`/`conf.py` for types, extra_links, ID settings. Grep for directives. Parse needs.

Read `pharaoh.toml` for strictness level and workflow settings.

## Process

### Step 1: Get Project Data

Build needs index. Present detection summary. Verify that a `decision` type is configured. If missing, show the user the TOML to add:

```toml
[[needs.types]]
directive = "decision"
title = "Decision"
prefix = "DEC_"
color = "#E8D0A9"
style = "node"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For consistency with the test fixtures and better visual distinction in the needs graph, consider using style = "artifact" for the decision type instead of node.

Suggested change
style = "node"
style = "artifact"

```

Also verify `decided_by`, `alternatives`, `rationale` extra options and the `decides` extra link type exist. Ask user to confirm before proceeding if anything is missing.

### Step 2: Gather Decision Context

Collect all required fields:

- **Title**: What is being decided.
- **Affected needs**: Need IDs for the `:decides:` link.
- **decided_by**: Who made the decision. Default to `claude` when AI decides autonomously.
- **alternatives**: Rejected alternatives, semicolon-separated.
- **rationale**: Why this option was chosen.
- **status**: One of `proposed`, `accepted`, `superseded`, `rejected`.

**Standalone**: Prompt the user for each missing piece. Do not proceed until all five fields are populated.

**Called by @pharaoh.spec**: Accept all context programmatically. Do not prompt.

**Status defaults**: `proposed` when standalone, `accepted` when called by @pharaoh.spec. User may override.

### Step 3: Generate ID

Reuse @pharaoh.author ID generation logic:

1. Check `pharaoh.toml` for `[pharaoh.id_scheme]`. Apply pattern with `{TYPE}` resolving to `DEC`.
2. If no scheme, infer from existing `decision` needs (look for `DEC_*` numbering).
3. If no existing decisions, use prefix from type config and start at `001`, padded to `id_length`.
4. Validate uniqueness against the full needs index.

### Step 4: Write the Need

Delegate to @pharaoh.author with all fields:

```rst
.. decision:: <title>
:id: <generated_id>
:status: <proposed|accepted>
:decides: <need_id1>, <need_id2>
:decided_by: <name or claude>
:alternatives: <alt1>; <alt2>
:rationale: <why this option>

<expanded description>
```

**Superseding**: When replacing an old decision, set old status to `superseded` via @pharaoh.author, add `:links: <old_dec_id>` on the new decision, and explain the replacement in the description.

### Step 5: File Placement

Place in `decisions.rst` in the same directory as the first need in `:decides:`. Create the file with proper RST title if it does not exist. If no `:decides:` links, fall back to @pharaoh.author file placement. Delegate actual writing to @pharaoh.author.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This step should also check for the [pharaoh.decisions].default_file setting in pharaoh.toml. If configured, the decision should be placed in that file instead of defaulting to a directory-relative decisions.rst.


### Step 6: Update Session State

Write to `.pharaoh/session.json`: set `changes.<dec_id>.authored = true` with current ISO 8601 timestamp.

### Step 7: Follow-up

**Standalone**: Suggest `Run @pharaoh.verify to validate the decision against its linked requirements.`

**Called by @pharaoh.spec**: Return the decision ID silently. No follow-up.

## Strictness Behavior

**Advisory mode**: Execute freely. No gates. No tips needed -- decisions can be recorded at any time.

**Enforcing mode**: Execute freely. No gates. Decisions are gate-free in both modes.

Strictness has no effect on decision recording. Both modes follow the same process.

## Constraints

1. **All three fields mandatory.** Always populate `decided_by`, `alternatives`, `rationale`. Ask explicitly if any are missing.
2. **Default `decided_by` to `claude`** when the AI decides autonomously (e.g., during @pharaoh.spec).
3. **Default `status`** to `proposed` (standalone) or `accepted` (called by @pharaoh.spec).
4. **Superseding requires two writes.** Update old decision to `superseded` AND add `:links:` on the new decision.
5. **Reuse @pharaoh.author** for RST writing, file placement, and ID generation. Do not duplicate logic.
6. **Validate `:decides:` targets exist.** Warn if a target is missing from the needs index.
7. **Semicolons for alternatives.** Separate with semicolons, not commas.
124 changes: 124 additions & 0 deletions .github/agents/pharaoh.spec.agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
---
description: Generate a Superpowers-compatible spec and plan document from sphinx-needs requirements, bridging requirements to implementation.
handoffs:
- label: Execute Plan
agent: pharaoh.plan
prompt: Execute the plan table from the generated spec
- label: Record Decision
agent: pharaoh.decide
prompt: Record a design decision for a gap in the requirements
- label: MECE Check
agent: pharaoh.mece
prompt: Check for traceability gaps in the spec scope
---

# @pharaoh.spec

Generate a Superpowers-compatible spec document from sphinx-needs requirements. Reads the needs hierarchy, identifies gaps, records decisions via @pharaoh.decide, and produces a markdown spec with an embedded plan table for @pharaoh.plan.

Output location: `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md` (overridable by user).

## Data Access

1. **ubc CLI**: `ubc build needs --format json` for index, `ubc config` for schema.
2. **ubCode MCP**: Pre-indexed needs data.
3. **Raw file parsing**: Read `ubproject.toml`/`conf.py` for types, extra_links, ID settings. Grep for directives. Parse needs.

Read `pharaoh.toml` for strictness, workflow gates, traceability requirements, and `required_links` chains.

## Process

### Step 1: Get Project Data

Build needs index and full link graph (both directions for all link types). Present detection summary. If detection fails, report and ask for guidance.

### Step 2: Parse Input

Accept one or more requirement IDs. Validate against the needs index.

- **IDs not found**: Report, suggest similar IDs, ask for confirmation.
- **Natural language**: Resolve by title match, substring, content, or tags. Present candidates if multiple match.
- **Multiple IDs**: Produce a single combined spec document.

### Step 3: Resolve Requirements Scope

For each input requirement:

1. **Pull full text**: ID, title, type, status, content, tags, all links, custom fields. Requirements appear verbatim in the spec.
2. **Trace downstream**: Follow all link types recursively. Collect **references only** (ID, type, title, status, link to parent) for downstream needs.
3. **Build scope tree**: Show requirement at root with all downstream coverage and gaps.
4. **Identify gaps**: Use `required_links` chains from `pharaoh.toml` (or infer from types). Gaps: missing specs, impls, tests, or partial coverage.

### Step 4: Present Scope Summary

Show counts of requirements (full text), specs, impls, tests (references), gaps, and decisions needed. Warn if scope exceeds 30 downstream needs. Wait for user confirmation.

### Step 5: Make Design Decisions

For each gap needing a design choice (decomposition, technology, test strategy, conflicting constraints), invoke @pharaoh.decide programmatically with:

- **decided_by**: `claude`
- **status**: `accepted`
- All other fields (title, decides, alternatives, rationale) populated from context.

Write all decisions BEFORE generating the spec. The spec must reference stable decision IDs, not placeholders.

If all gaps are straightforward, skip decision recording and note it in the spec.

### Step 6: Generate the Spec Document

Write to `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md`. Create the directory if needed.

**Required sections in order**: Requirements (source of truth, full verbatim text), Existing coverage (reference table), Gaps (unchecked checkboxes), Decisions (IDs from Step 5), Implementation scope (needs to create/modify tables, "None" if empty), Plan table (built in Step 7).

Full text for requirements, ref-only for downstream. Decisions must reference stable IDs written in Step 5.

### Step 7: Build the Plan Table

Follow @pharaoh.plan task sequencing:

1. **Change analysis first** (if modifying existing needs).
2. **Author top-down**: Requirements > specs > impls > tests. New before modifications.
3. **Verify after all authoring**.
4. **MECE check** if `require_mece_on_release = true` or multi-level scope.

Each row: sequential number, concise task, exact skill name, concrete target (need ID, `(new)`, or `(all)`), specific detail, file path or `--`, and required field.

### Step 8: Handoff

Present the file path and options:

```
Spec document written to: docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md

Options:
1. Execute the plan via @pharaoh.plan
2. Review or modify the spec first
3. Execute later (plan is saved in the spec document)
```

Never auto-execute. Always wait for explicit user approval.

## Strictness Behavior

**Advisory mode**: Execute freely. No gates. All plan table tasks marked `recommended`. After generating, show:
```
Tip: Consider reviewing the spec before executing the plan.
The spec captures design decisions that affect downstream authoring.
```

**Enforcing mode**: Execute freely. No gates. Plan table tasks mandated by workflow gates marked `yes`:
- `@pharaoh.change` if `require_change_analysis = true`
- `@pharaoh.verify` if `require_verification = true`
- `@pharaoh.mece` if `require_mece_on_release = true`

Both modes perform identical analysis depth. Strictness only affects the `Required` column.

## Constraints

1. **Full text for requirements, references only for downstream.** Spec is self-contained for requirements but does not duplicate downstream content.
2. **Decisions written before the spec references them.** Always invoke @pharaoh.decide first, collect the ID, then use it.
3. **Plan table format matches @pharaoh.plan exactly.** Same columns, granularity, and semantics.
4. **Never auto-execute.** Present the complete spec and wait for approval before invoking downstream skills.
5. **Single combined spec for multiple requirements.** Do not produce separate documents.
6. **No session state changes from spec generation.** Only @pharaoh.decide and @pharaoh.plan update session state.
11 changes: 8 additions & 3 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,18 @@ Pharaoh is a skill-based AI assistant framework for sphinx-needs projects. It he
| `@pharaoh.verify` | Validate implementations against requirements -- content-level satisfaction checks |
| `@pharaoh.release` | Release management -- changelog from requirements, traceability coverage metrics |
| `@pharaoh.plan` | Structured implementation planning -- break changes into tasks with workflow enforcement |
| `@pharaoh.spec` | Generate spec from requirements -- read needs hierarchy, record decisions, produce spec with plan table |
| `@pharaoh.decide` | Record design decisions -- create `decision` needs with alternatives, rationale, and traceability links |

## Recommended Workflow

```
@pharaoh.change -> @pharaoh.author -> @pharaoh.verify -> @pharaoh.release
-> @pharaoh.mece (optional, for gap analysis)
-> @pharaoh.trace (optional, for exploration)
@pharaoh.spec -> @pharaoh.decide (for gaps)
-> produces spec doc with plan table
|
@pharaoh.plan -> @pharaoh.change -> @pharaoh.author -> @pharaoh.verify -> @pharaoh.release
-> @pharaoh.mece (optional, for gap analysis)
-> @pharaoh.trace (optional, for exploration)
```

## Data Access Tiers
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
*.pyc
__pycache__/
.DS_Store
.worktrees/
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,18 @@ Pharaoh has no runtime binary or Python package. All analysis logic is encoded i
| `pharaoh:verify` | `@pharaoh.verify` | Validate implementations against requirements -- content-level satisfaction checks |
| `pharaoh:release` | `@pharaoh.release` | Release management -- changelog from requirements, traceability coverage metrics |
| `pharaoh:plan` | `@pharaoh.plan` | Structured implementation planning -- break changes into tasks with workflow enforcement |
| `pharaoh:spec` | `@pharaoh.spec` | Generate spec from requirements -- read needs hierarchy, record decisions, produce Superpowers-compatible spec with plan table |
| `pharaoh:decide` | `@pharaoh.decide` | Record design decisions -- create `decision` needs with alternatives, rationale, and traceability links |

## Workflow

```
pharaoh:change -> pharaoh:author -> pharaoh:verify -> pharaoh:release
-> pharaoh:mece (optional, for gap analysis)
-> pharaoh:trace (optional, for exploration)
pharaoh:spec -> pharaoh:decide (for gaps)
-> produces spec doc with plan table
|
pharaoh:plan -> pharaoh:change -> pharaoh:author -> pharaoh:verify -> pharaoh:release
-> pharaoh:mece (optional, for gap analysis)
-> pharaoh:trace (optional, for exploration)
```

## Experience Tiers
Expand Down
9 changes: 9 additions & 0 deletions pharaoh.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,12 @@ required_links = [
[pharaoh.codelinks]
# Follow sphinx-codelinks in change analysis
enabled = true

[pharaoh.decisions]
# Default file for new decision needs (relative to docs source root)
# If absent, decisions go to decisions.rst in same directory as affected requirement
default_file = "decisions.rst"
# Default status for decisions created standalone
default_status = "proposed"
# Default status for decisions created during pharaoh:spec
spec_status = "accepted"
Loading