Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "pharaoh-dev",
"description": "Development marketplace for Pharaoh sphinx-needs AI assistant",
"owner": {
"name": "patdhlk"
"name": "useblocks"
},
"plugins": [
{
Expand All @@ -11,7 +11,7 @@
"version": "0.1.0",
"source": "./",
"author": {
"name": "patdhlk"
"name": "useblocks"
}
}
]
Expand Down
6 changes: 3 additions & 3 deletions .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
"description": "AI assistant framework for sphinx-needs projects: change analysis, traceability, MECE, authoring, verification, and release management",
"version": "0.1.0",
"author": {
"name": "patdhlk"
"name": "useblocks"
},
"repository": "https://github.com/patdhlk/pharaoh",
"repository": "https://github.com/useblocks/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"]
}
33 changes: 33 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
name: Bug Report
about: Report a problem with a Pharaoh skill or agent
title: "[Bug] "
labels: bug
assignees: ""
---

## Environment

- **Skill/Agent:** <!-- e.g., pharaoh:change / @pharaoh.change -->
- **AI Platform:** <!-- Claude Code / GitHub Copilot -->
- **Config source:** <!-- ubproject.toml / conf.py -->
- **sphinx-needs version:** <!-- if known -->
- **ubc CLI version:** <!-- if installed, run: ubc --version -->

## Description

<!-- What happened? -->

## Expected Behavior

<!-- What did you expect to happen? -->

## Steps to Reproduce

1. <!-- Step 1 -->
2. <!-- Step 2 -->
3. <!-- Step 3 -->

## Additional Context

<!-- Relevant config snippets, error messages, or screenshots -->
23 changes: 23 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
name: Feature Request
about: Suggest an improvement or new capability
title: "[Feature] "
labels: enhancement
assignees: ""
---

## Skill

<!-- Which skill does this affect? (e.g., pharaoh:author) or "new skill" -->

## Use Case

<!-- What are you trying to accomplish? -->

## Proposed Behavior

<!-- How should it work? -->

## Alternatives Considered

<!-- Have you considered other approaches? -->
15 changes: 15 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Summary

<!-- Brief description of what this PR does -->

## Checklist

- [ ] Both Claude Code skill and Copilot agent updated (if applicable)
- [ ] Tested against `tests/fixtures/basic-project/`
- [ ] README skill table updated (if new/renamed skill)
- [ ] `copilot-instructions.md` updated (if new/renamed agent)
- [ ] Commit messages use imperative mood

## Testing

<!-- How did you test these changes? -->
157 changes: 157 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_call:

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Validate skill frontmatter
run: |
status=0
for skill_dir in skills/*/; do
# Skip shared directory
if [ "$(basename "$skill_dir")" = "shared" ]; then
continue
fi

skill_file="${skill_dir}SKILL.md"
if [ ! -f "$skill_file" ]; then
echo "ERROR: Missing SKILL.md in $skill_dir"
status=1
continue
fi

# Check for YAML frontmatter delimiters
first_line=$(head -1 "$skill_file")
if [ "$first_line" != "---" ]; then
echo "ERROR: $skill_file missing YAML frontmatter (no opening ---)"
status=1
continue
fi

# Extract frontmatter (between first and second ---)
frontmatter=$(sed -n '2,/^---$/p' "$skill_file" | sed '$d')

# Check for name field (must be lowercase with hyphens)
if ! echo "$frontmatter" | grep -qE '^name: [a-z0-9-]+$'; then
echo "ERROR: $skill_file 'name' missing or not lowercase-with-hyphens"
status=1
fi

# Check for description field (must start with "Use when")
if ! echo "$frontmatter" | grep -qE '^description: "?Use when'; then
echo "ERROR: $skill_file 'description' missing or does not start with 'Use when'"
status=1
fi

echo "OK: $skill_file"
done
exit $status

- name: Validate agent frontmatter
run: |
status=0
for agent_file in .github/agents/*.agent.md; do
[ -f "$agent_file" ] || continue

first_line=$(head -1 "$agent_file")
if [ "$first_line" != "---" ]; then
echo "ERROR: $agent_file missing YAML frontmatter"
status=1
continue
fi

frontmatter=$(sed -n '2,/^---$/p' "$agent_file" | sed '$d')

if ! echo "$frontmatter" | grep -qE '^description:'; then
echo "ERROR: $agent_file missing 'description' in frontmatter"
status=1
fi

if ! echo "$frontmatter" | grep -qE '^handoffs:'; then
echo "ERROR: $agent_file missing 'handoffs' in frontmatter"
status=1
fi

echo "OK: $agent_file"
done
exit $status

- name: Cross-reference skills and agents
run: |
status=0

# Check every pharaoh skill has a matching agent
for skill_dir in skills/pharaoh-*/; do
skill_name=$(basename "$skill_dir")
# Convert pharaoh-change -> pharaoh.change
agent_name=$(echo "$skill_name" | sed 's/-/./')
agent_file=".github/agents/${agent_name}.agent.md"

if [ ! -f "$agent_file" ]; then
echo "ERROR: Skill $skill_name has no matching agent at $agent_file"
status=1
else
echo "OK: $skill_name <-> $agent_file"
fi
done

# Check every pharaoh agent has a matching skill
for agent_file in .github/agents/pharaoh.*.agent.md; do
[ -f "$agent_file" ] || continue
agent_basename=$(basename "$agent_file" .agent.md)
# Convert pharaoh.change -> pharaoh-change
skill_name=$(echo "$agent_basename" | sed 's/\./-/')
skill_dir="skills/${skill_name}/"

if [ ! -d "$skill_dir" ]; then
echo "ERROR: Agent $agent_basename has no matching skill at $skill_dir"
status=1
fi
done

exit $status

- name: Check internal links
run: |
status=0
shopt -s globstar

# Check relative links in markdown files (top-level and docs/)
for md_file in *.md docs/**/*.md; do
[ -f "$md_file" ] || continue
dir=$(dirname "$md_file")

# Extract markdown links: [text](path) — skip URLs, anchors, and template links
while read -r link; do
# Skip URLs
case "$link" in
http://*|https://*|mailto:*|#*|\?*) continue ;;
esac

# Strip anchor from link
path="${link%%#*}"
[ -z "$path" ] && continue

# Resolve relative to the markdown file's directory
target="${dir}/${path}"
if [ ! -e "$target" ]; then
echo "ERROR: $md_file links to '$link' but $target does not exist"
status=1
fi
done < <(grep -oP '\[.*?\]\(\K[^)]+' "$md_file" || true)
done

exit $status
78 changes: 78 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Release

on:
push:
tags:
- "v*"

permissions:
contents: write

jobs:
validate:
uses: ./.github/workflows/ci.yaml

release:
needs: validate
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Get version from tag
id: version
run: echo "version=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"

- name: Generate changelog
id: changelog
run: |
# Find the previous tag
prev_tag=$(git tag --sort=-v:refname | sed -n '2p')

if [ -z "$prev_tag" ]; then
# First release — log from the beginning
log=$(git log --pretty=format:"- %s (%h)" "$GITHUB_REF")
else
log=$(git log --pretty=format:"- %s (%h)" "${prev_tag}..${GITHUB_REF}")
fi

# Write to file for body_path
echo "$log" > RELEASE_NOTES.md

- name: Create release archive
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
archive="pharaoh-${VERSION}.zip"

# Collect paths that exist
paths=""
for p in \
skills/ \
.github/agents/ \
.github/prompts/ \
.claude-plugin/ \
agents/ \
tests/fixtures/ \
pharaoh.toml.example \
README.md \
LICENSE \
CHANGELOG.md \
CONTRIBUTING.md \
SECURITY.md
do
[ -e "$p" ] && paths="$paths $p"
done

zip -r "$archive" $paths

echo "archive=${archive}" >> "$GITHUB_ENV"

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
name: ${{ steps.version.outputs.version }}
body_path: RELEASE_NOTES.md
files: ${{ env.archive }}
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/
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/),
and this project adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

## [0.1.0] - 2026-04-10

### Added

- **Skills (Claude Code):** pharaoh:setup, pharaoh:change, pharaoh:trace, pharaoh:mece, pharaoh:author, pharaoh:verify, pharaoh:release, pharaoh:plan, pharaoh:spec, pharaoh:decide
- **Agents (GitHub Copilot):** matching agents for all skills with handoff support
- **Prompts (GitHub Copilot):** quick-invoke prompts for common workflows
- **Shared modules:** data-access (3-tier detection) and strictness (advisory/enforcing mode)
- **Test fixtures:** basic-project with requirements, specifications, implementations, tests, and decisions
- **Configuration:** pharaoh.toml.example with all supported options
- **Subagent:** sphinx-needs-expert for deep sphinx-needs domain knowledge
Loading
Loading