From edpa
Initialize EDPA governance for a project. Vendors the engine (scripts + schemas + templates) into `.edpa/engine/`, creates `.edpa/config/{edpa.yaml,people.yaml}`, copies CI workflows to `.github/workflows/`, provisions GitHub Project + custom fields. Use when starting a new project or onboarding EDPA.
How this skill is triggered — by the user, by Claude, or both
Slash command
/edpa:edpa-setupThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Initializes EDPA governance for a GitHub-based project with a **clean** layout that puts everything EDPA-related under `.edpa/`. The engine (scripts + schemas + templates) is vendored from `${CLAUDE_PLUGIN_ROOT}/edpa/` into `.edpa/engine/`, so:
Initializes EDPA governance for a GitHub-based project with a clean layout that puts everything EDPA-related under .edpa/. The engine (scripts + schemas + templates) is vendored from ${CLAUDE_PLUGIN_ROOT}/edpa/ into .edpa/engine/, so:
python3 .edpa/engine/scripts/X.py — no curl|sh install step per CI run, zero overhead.edpa/engine/.claude/ in the project stays clean (typically empty or just settings.json)Resulting layout:
<project>/
├── .edpa/
│ ├── engine/ ← vendored from ${CLAUDE_PLUGIN_ROOT}/edpa/
│ │ ├── scripts/ (30 .py)
│ │ ├── schemas/ (1 .json)
│ │ ├── templates/ (3 .tmpl)
│ │ └── VERSION ← plugin version pinned in this project
│ ├── config/
│ │ ├── edpa.yaml ← project metadata (from edpa.yaml.tmpl)
│ │ └── people.yaml ← capacity registry (from people.yaml.tmpl)
│ ├── backlog/{initiatives,epics,features,stories}/
│ ├── iterations/, reports/, snapshots/, data/
│ ├── changelog.jsonl
│ └── sync_state.json
└── .github/workflows/edpa-*.yml ← 11 CI workflows (call .edpa/engine/scripts/X.py)
$ARGUMENTS = project name (e.g., "Medical Platform")
If $ARGUMENTS is empty, blank, or "help":
.edpa/config/edpa.yaml exists (re-initialization scenario):
project.name and present: "EDPA is already initialized for {name}. Re-run setup? [y/N]".edpa/ does not exist (fresh setup):
git remote get-url origin → extract repo nameRun the preflight script directly from the plugin cache (engine isn't vendored yet at this point):
python3 "${CLAUDE_PLUGIN_ROOT}/edpa/scripts/project_setup.py" \
--org <org> --repo <repo> --check-only
This verifies: Python ≥ 3.10, pyyaml + openpyxl, gh auth status, scopes (admin:org, project, repo, workflow), org access, target repo, org-level Issue Types, git config user.name + user.email, and (if .edpa/config/people.yaml exists) that declared github logins are org members. Blocks on error.
mkdir -p .edpa/config \
.edpa/backlog/initiatives \
.edpa/backlog/epics \
.edpa/backlog/features \
.edpa/backlog/stories \
.edpa/iterations \
.edpa/reports \
.edpa/snapshots \
.edpa/data
touch .edpa/changelog.jsonl .edpa/sync_state.json
.edpa/engine/mkdir -p .edpa/engine
cp -R "${CLAUDE_PLUGIN_ROOT}/edpa/scripts" .edpa/engine/
cp -R "${CLAUDE_PLUGIN_ROOT}/edpa/schemas" .edpa/engine/
cp -R "${CLAUDE_PLUGIN_ROOT}/edpa/templates" .edpa/engine/
# Pin the vendored plugin version so /edpa:setup --update-engine knows what to
# diff against and CI workflows can sanity-check their script tree.
python3 -c "import json; print(json.load(open('${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json'))['version'])" > .edpa/engine/VERSION
Why .edpa/engine/ (not .claude/edpa/):
.edpa/ is the EDPA namespace owned by the project — engine code belongs inside it..claude/ is reserved for Claude Code's per-project config (e.g., settings.json); putting plugin payload there conflates two ownership boundaries.${CLAUDE_PLUGIN_ROOT} and no plugin cache, so the engine must live in the project repo somewhere — .edpa/engine/ is that somewhere.What gets vendored: scripts/ (30 .py), schemas/ (1 .json), templates/ (3 .tmpl). Skills/commands/hooks/.mcp.json from ${CLAUDE_PLUGIN_ROOT} are NOT vendored — those are for Claude Code's plugin runtime exclusively, which loads them from its cache, not from the project.
.github/workflows/mkdir -p .github/workflows
cp "${CLAUDE_PLUGIN_ROOT}"/edpa/workflows/*.yml .github/workflows/
The 11 workflows call python3 .edpa/engine/scripts/X.py directly — no install step needed per run because the engine is already vendored in the project repo from step 2.
.edpa/config/edpa.yamlcp "${CLAUDE_PLUGIN_ROOT}/edpa/templates/edpa.yaml.tmpl" .edpa/config/edpa.yaml
Then update project.name in the new file to $ARGUMENTS. Leave optional fields (funding instrument, organizations, addresses) empty for the user to fill in later if relevant.
The template carries:
project.{name, description, domain} (basic identity)project.funding.{program, registration, period_*} (grants / contracts; remove block if N/A)project.organizations[] (legal name, tax/VAT IDs, addresses; for audit + invoicing)governance.methodology (engine version pin)naming.{pi_pattern, iteration_pattern, branch_pattern, item_prefixes}issue_types.{Initiative, Epic, Feature, Story, Defect, Task}labels.EnablerMost of these can stay at defaults.
Don't merge project metadata into people.yaml — these are two separate files in the v1.11+ architecture: edpa.yaml for project-level config, people.yaml for capacity registry only.
.edpa/config/people.yamlcp "${CLAUDE_PLUGIN_ROOT}/edpa/templates/people.yaml.tmpl" .edpa/config/people.yaml
Then replace the people[] example entries with the real team. Keep the cadence: and teams: blocks (default cadence is AI-native: 1-week iterations, 5-week PI, 4 delivery + 1 IP).
For each team member, ask the user explicitly for: name, role, team, FTE, email, and GitHub username. Calculate capacity_per_iteration = fte × hours_per_week × iteration_weeks (e.g. 1.0 × 40 × 1 = 40 for 1-week iter).
Roles — use one of these exact values: Arch, Dev, DevSecOps, PM, QA. Never default to "Dev" — ask the user explicitly. If a memory profile indicates a specific role (e.g. "Lead Architect" → Arch), use that; otherwise:
"What is {name}'s role? (Arch / Dev / DevSecOps / PM / QA)"
CRITICAL — never invent the github field from email patterns or names. GitHub usernames are not derivable. If the user doesn't know someone's login, leave github: "" and tell them they can fill it in later — sync push --assignee skips people without a login. Inventing risks routing issue assignments to a stranger with the same handle.
"GitHub username for {name}? (leave blank if you don't know — fill in later via PR to people.yaml)"
python3 .edpa/engine/scripts/project_setup.py \
--org <org> --repo <repo> --project-title "<project-name> Governance" \
--skip-preflight # already ran in step 0
The script:
gh project createEnabler label and other classifications.edpa/config/issue_map.yaml mapping local IDs ↔ GitHub Issue numberscreate_project_views.py to seed kanban viewsCRITICAL — every backlog item below the Initiative level MUST declare a parent: field referencing a higher-level item. The skill must refuse to emit flat lists, and the wizard must use the backlog.py add CLI rather than writing YAML files directly or calling gh issue create by hand:
# Correct — backlog.py enforces parent + assigns the next ID
python3 .edpa/engine/scripts/backlog.py add --type Initiative --title "Platform"
python3 .edpa/engine/scripts/backlog.py add --type Epic --parent I-1 --title "Auth"
python3 .edpa/engine/scripts/backlog.py add --type Feature --parent E-1 --title "OAuth"
python3 .edpa/engine/scripts/backlog.py add --type Story --parent F-1 --title "Login UI" --js 5
# After items exist, sync push wires parent-child to GitHub sub-issues:
python3 .edpa/engine/scripts/sync.py push
Forbidden — these bypass hierarchy enforcement:
gh issue create ... directly (skips backlog.py add validation).edpa/backlog/**/*.yaml files via the editor without a parent: field on every non-Initiative entrysync push after adding items locally — without it, GitHub Issues never get linked as sub-issuesCommit .edpa/, .edpa/engine/, .github/workflows/edpa-*.yml. Print summary: project name, team count, total FTE, capacity/iteration, cadence, GH Project URL.
The project_setup.py wizard automatically prompts for optional create_project_views.py invocation. Default is yes. Failure is non-fatal — the maintainer can re-run later:
python3 .edpa/engine/scripts/create_project_views.py --url <project-url>
.claude/edpa/. Engine vendors to .edpa/engine/. The project's .claude/ stays clean (typically just settings.json). Vendoring to .claude/edpa/ was the v1.0-era pattern; v1.18.5+ uses .edpa/engine/..edpa/config/heuristics.yaml. The engine reads canonical CW weights from .edpa/engine/templates/cw_heuristics.yaml.tmpl (LOCKED, calibrated). The user-editable .edpa/config/heuristics.yaml from pre-v1.11 was a copy the engine ignored.people.yaml. v1.11+ has edpa.yaml (project) and people.yaml (capacity) as separate files. Mixing them was a pre-v1.11 footgun.role: Dev. Roles are Arch / Dev / DevSecOps / PM / QA; ask the user.gh not authenticated → print gh auth login instructionspip3 install -r "${CLAUDE_PLUGIN_ROOT}/requirements.txt" --break-system-packages${CLAUDE_PLUGIN_ROOT} not set → skill was invoked outside Claude Code's plugin runtime; fall back to curl -fsSL https://edpa.technomaton.com/install.sh | sh (which vendors to .edpa/engine/ directly) and rerun setup.edpa/engine/VERSION mismatches ${CLAUDE_PLUGIN_ROOT} plugin version → engine drift; offer /edpa:setup --update-engine to refreshnpx claudepluginhub technomaton/edpa --plugin edpaCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.