diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 761f9a2..871dba7 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -2,7 +2,7 @@ "name": "pharaoh-dev", "description": "Development marketplace for Pharaoh sphinx-needs AI assistant", "owner": { - "name": "patdhlk" + "name": "useblocks" }, "plugins": [ { @@ -11,7 +11,7 @@ "version": "0.1.0", "source": "./", "author": { - "name": "patdhlk" + "name": "useblocks" } } ] diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index f71dd1b..7876b29 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -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"] } diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..fbcc7d4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -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:** +- **AI Platform:** +- **Config source:** +- **sphinx-needs version:** +- **ubc CLI version:** + +## Description + + + +## Expected Behavior + + + +## Steps to Reproduce + +1. +2. +3. + +## Additional Context + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..cd229bf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,23 @@ +--- +name: Feature Request +about: Suggest an improvement or new capability +title: "[Feature] " +labels: enhancement +assignees: "" +--- + +## Skill + + + +## Use Case + + + +## Proposed Behavior + + + +## Alternatives Considered + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..772c328 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ +## Summary + + + +## 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 + + diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..5eca926 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,148 @@ +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 + shell: bash + run: | + status=0 + shopt -s globstar nullglob + for md_file in *.md docs/**/*.md; do + [ -f "$md_file" ] || continue + dir=$(dirname "$md_file") + links=$(grep -oP '\[.*?\]\(\K[^)]+' "$md_file" | grep -v '^http' | grep -v '^mailto:' | grep -v '^#' | grep -v '^?' || true) + for link in $links; do + path="${link%%#*}" + [ -z "$path" ] && continue + target="${dir}/${path}" + if [ ! -e "$target" ]; then + echo "ERROR: $md_file links to '$link' but $target does not exist" + echo "FAILED" >> /tmp/link_check_failed + fi + done + done + if [ -f /tmp/link_check_failed ]; then + exit 1 + fi diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..757903d --- /dev/null +++ b/.github/workflows/release.yaml @@ -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 }} diff --git a/.gitignore b/.gitignore index 2f9d482..f892327 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.pyc __pycache__/ .DS_Store +.worktrees/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..61c1ed0 --- /dev/null +++ b/CHANGELOG.md @@ -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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7d376d0..68e08e0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing to Pharaoh -Thank you for your interest in contributing to Pharaoh! This guide covers how the project is structured, how to make changes, and how to submit contributions. +Pharaoh is maintained by [useblocks](https://useblocks.com) and welcomes contributions from the community. This guide covers how the project is structured, how to make changes, and how to submit contributions. ## Project Structure @@ -105,6 +105,22 @@ Test fixtures live in `tests/fixtures/`. Each fixture is a minimal sphinx-needs - First line: brief summary (under 72 characters). - Group related changes in a single commit. +## Developer Certificate of Origin + +This project uses the [Developer Certificate of Origin](https://developercertificate.org/) (DCO). By contributing, you certify that you wrote or have the right to submit the code under the project's MIT license. + +Sign off your commits with: + +```bash +git commit -s -m "Your commit message" +``` + +All commits in a PR must be signed off. If you forget, you can amend: + +```bash +git commit --amend -s +``` + ## Pull Request Process 1. Fork the repository and create a branch from `main`. @@ -118,12 +134,12 @@ Test fixtures live in `tests/fixtures/`. Each fixture is a minimal sphinx-needs ## Reporting Issues -When reporting an issue, include: +Use the GitHub issue templates: + +- **[Bug Report](?template=bug_report.md)** -- for problems with skills or agents +- **[Feature Request](?template=feature_request.md)** -- for improvements or new capabilities -- Which skill/agent was involved. -- The sphinx-needs project structure (types, link types, config source). -- What you expected to happen vs what actually happened. -- The AI platform used (Claude Code or GitHub Copilot). +The templates include fields for the skill/agent involved, AI platform, and project configuration. ## Questions? diff --git a/LICENSE b/LICENSE index f28f175..c331725 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026 patdhlk +Copyright (c) 2026 useblocks GmbH, originally by patdhlk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 4324bd7..eafb3f1 100644 --- a/README.md +++ b/README.md @@ -115,10 +115,6 @@ Pharaoh never re-defines these settings. `pharaoh.toml` only controls Pharaoh's When a project uses [sphinx-codelinks](https://sphinx-codelinks.useblocks.com/), Pharaoh follows codelink references in change analysis and traceability. A change to a requirement surfaces affected code files, not just other requirements. -## Design - -See the [design document](docs/plans/2026-02-11-pharaoh-design.md) for architecture details, platform support, and the full data access model. - ## License MIT diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..53cedcb --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ +# Security Policy + +## About Pharaoh's Architecture + +Pharaoh is a **pure-prompt project**. It contains no executable code, no compiled binaries, and no runtime dependencies. All logic is encoded in markdown instruction files that are interpreted by AI assistants (Claude Code, GitHub Copilot). + +This means Pharaoh's attack surface is fundamentally different from traditional software. + +## What Counts as a Security Issue + +- Skill or agent instructions that could cause an AI to **delete files, leak secrets, or execute destructive commands** +- **Prompt injection vectors** in skill files that could override user intent +- Instructions that cause an AI to **bypass safety checks** or ignore user permissions +- Skill logic that could **exfiltrate data** from a user's project to external services + +## What Does NOT Count + +- Bugs in AI output quality (e.g., incorrect traceability analysis) +- sphinx-needs configuration issues +- Unexpected AI behavior not caused by Pharaoh's instructions + +## Reporting a Vulnerability + +**Email:** security@useblocks.com + +Include: +- Which skill or agent file is affected +- A description of the vulnerability +- Steps to reproduce (if possible) + +**Response time:** We will acknowledge your report within **5 business days**. + +## Disclosure Policy + +- We will work with you to understand and validate the issue +- Fixes ship as prompt updates (updated skill/agent files) — there are no versioned binaries to patch +- We will credit reporters in the changelog unless they prefer to remain anonymous + +## No CVEs + +Pure-prompt projects do not have CVE identifiers. Security fixes are tracked in git history and the changelog.