Releases: technomaton/edpa
v2.3.0 — Robust git-hook registration + lefthook support
Fixes git hooks silently not firing after a plugin update or under lefthook — the post-commit local_evidence.py emitter never ran, so contribution evidence stopped landing on items.
Fixed
install_hooksno longer skips a slot with a bluntnot dst.exists()guard. EDPA marks hooks with anEDPA-MANAGED-HOOKsentinel and decides per slot: install if missing, refresh if EDPA-owned, never clobber a foreign hook.update_engine.sh(SessionStart auto-update) now re-registers EDPA hooks after a version bump when the project already uses them.
Added
- lefthook support — detects
lefthook.ymland prints a paste-ready snippet (use_stdin: trueonpre-push, required or lefthook hangs) instead of writing.git/hooks/. project_setup.py --check-hooks(read-only hooks doctor) and--refresh-hooks(register/refresh only).
Changed
scripts/hooks/install.sh→ thin delegator to--refresh-hooks; dropped the conflictingcore.hooksPathmechanism.- ANSI is TTY-aware (no escape-code leak in captured output).
- Removed the dead generic
pre-commithook and the dead V1 GitHub-Projects sync workflows (referenced async.pyremoved in 2.0.0).
Docs / web
RUNBOOK §1+§6, quick-start, skills/setup/SKILL.md, playbook, README ×2; website setup/guide/playbook/methodology (CZ + EN). Live at https://edpa.technomaton.com (v2.3.0).
Tracked as D-1. Full test suite: 618 passed.
v2.2.1
2.2.1 — 2026-06-01 — Skill names: drop the redundant edpa- prefix; server + create-pi are command-only
Plugin skill invocations were doubly namespaced — /edpa:edpa-setup,
/edpa:edpa-engine, … — because Claude Code derives a skill's slug from its
directory name (skills/edpa-setup/ → /edpa:edpa-setup), not the SKILL.md
name: field. The frontmatter name: and plugin/README.md already advertised
the clean /edpa:setup form, so the picker showed /edpa:setup but inserted
/edpa:edpa-setup — a half-finished rename. This completes it.
refactor(skills): rename 5 skill dirs to drop the prefix
skills/edpa-{setup,add,engine,reports,autocalib} → skills/{setup,add,engine,reports,autocalib},
and each SKILL.md name: is now the bare slug matching its directory.
Invocations are now /edpa:setup, /edpa:add, /edpa:engine, /edpa:reports,
/edpa:autocalib. plugin.json skills[] paths updated.
refactor(server,create-pi): collapse the command+skill pairs to command-only
Two capabilities shipped as both a command and a same-named skill; the prefix
was the only thing keeping them from colliding (/edpa:server command vs
/edpa:edpa-server skill). Dropping the prefix would collide, so the redundant
skills are removed in favour of the commands:
skills/edpa-serverremoved — its workflow (start/stop/status, scoped
allowed-tools, the "what NOT to do" rails) folded intocommands/server.md.skills/edpa-create-piremoved —commands/create-pi.mdalready carried the
full workflow; theedpa_pi_createMCP tool remains the model-facing path.
plugin.json skills[] drops both; commands[] is unchanged (still 5).
Breaking — invocation surface
/edpa:edpa-setup/-add/-engine/-reports/-autocalib→ use
/edpa:setup…/edpa:autocalib.- The
edpa:edpa-serverandedpa:edpa-create-piskills are gone — use the
/edpa:serverand/edpa:create-picommands (and theedpa_pi_createMCP
tool). Run/reload-pluginsafter updating.
docs + web + tooling
Swept every active reference: plugin/README.md tree + table, docs/ (RUNBOOK,
playbook, faq, mcp, dev-collisions, auto-calibration, E2E plans), tests, and the
CZ+EN website (presentation, kashealth, playbook). Fixed pre-existing
double-prefix typos (/edpa:edpa-engine in capacity.md, /edpa:edpa-setup in
faq.md). scripts/bump_version.py literal-reference paths updated to the new
skill dirs.
v2.2.0 — Create PI (edpa_pi_create + /edpa:create-pi)
First-class PI-level metadata file creation (.edpa/iterations/<PI-YYYY-N>.yaml, the pi: block) — until now only per-iteration files had tooling, and the PI parent had to be hand-written (and a .yml extension was silently ignored by the loader).
Built script-first, like the rest of EDPA: behavior lives in one script and every interface delegates to it.
create_pi.py— single source of behavior: importablecreate_pi()core (validate PI-level id, refuse overwrite, atomic write) + CLI (validate + auto-commit). Self-contained, no MCP dependency.edpa_pi_createMCP tool — thin delegate (write only, no commit). Tool surface now 7 read + 8 write./edpa:create-picommand +edpa:create-piskill — shell out to the script (like/edpa:capacity→capacity_override.py).
Rejects iteration-level ids (PI-YYYY-N.M) and duplicates. Does not scaffold child iterations (use edpa_iteration_create).
Tests: tests/test_create_pi.py (core + CLI + loader round-trip) + edpa_pi_create in the MCP write/idempotency/advertised-tool suites — pytest tests/ 600 passed. Docs: docs/mcp.md (write-tools note + corrected "read-only" claim), docs/playbook.md §1.5, docs/RUNBOOK.md, plugin/README.md.
🤖 Generated with Claude Code
v2.1.9 — Windows onboarding fixes (filelock, UTF-8 console + file I/O)
Windows onboarding fixes — /edpa:edpa-setup crashed on a fresh Windows box (surfaced by colleagues on 2.1.8). Two reported failures, plus two more that would have hit immediately after (masked by the first crash). All four are fixed; the engine now behaves identically on Linux, macOS, and Windows.
fix(setup): bootstrap no longer crashes on ModuleNotFoundError: filelock
id_counter.py imported filelock unconditionally, but the SessionStart dep hook (install_deps.sh) skipped pip install whenever its cheap import probe passed — and the probe never listed filelock. On a machine that already had PyYAML/mcp/openpyxl system-wide, the hook marked deps "installed" while filelock was absent, so the bootstrap died.
- The probe now includes
filelock(a newtest_install_deps_probe.pycross-checks it againstrequirements.txtso the drift can't recur). id_counter.pyfalls back to a pure-stdlib lock (_fallback_lock.py,O_CREAT|O_EXCL+ stale-lock sweep) whenfilelockcan't be imported, keeping the cross-process mutual-exclusion contract even without the package.
fix(cli): UTF-8 console output
25 CLI entry points print progress glyphs (✓ ✗ → ·); print("✓") raises UnicodeEncodeError on a cp1250/cp1252 console and aborts the command (the reported failure). A shared _console.py reconfigures stdout/stderr to UTF-8; each entry point opts in with a guarded import _console (try/except ImportError, so a partially-vendored engine degrades to plain output rather than crashing). mcp_server.py is excluded — its glyphs ride the MCP SDK's UTF-8 JSON-RPC framing.
fix(io): all text-mode file I/O pins encoding="utf-8"
open()/read_text()/write_text()/os.fdopen() defaulted to the locale encoding — cp1250 on a Czech/German Windows box. After the console fix the next crash would have been _stamp_methodology reading the seeded UTF-8 edpa.yaml (←, ×) → UnicodeDecodeError; diacritic item titles would corrupt or crash on write too. All 28 text-mode handles now pin UTF-8. A new test_encoding_hygiene.py AST guard fails CI if any text handle drops the kwarg.
Tests
New: test_install_deps_probe.py, test_fallback_lock.py, test_console.py, test_encoding_hygiene.py. Full suite 565 → 577 (+12); 0 failures.
🤖 Generated with Claude Code
v2.1.8 — Fresh-install onboarding fixes
Three fresh-install onboarding friction points on the Claude-Code-only path (install the plugin, run /edpa:setup on a bare repo), found via a new deterministic E2E onboarding harness (tests/onboarding/).
fix(setup): /edpa:setup now vendors the engine into .edpa/engine/
project_setup.py vendors scripts+schemas+templates+rules+VERSION as step 1 of main() (mirrors install.sh). The Claude Code path had silently lost vendoring when the engine moved from .claude/edpa/ to .edpa/engine/ (only install.sh was rewired), so /edpa:setup produced a project referencing a .edpa/engine/scripts/ that never existed — the --with-ci workflow it installs plus the documented CLI broke, masked by the MCP server running from the plugin cache. Rules are now vendored from plugin/rules (fixes a parallel --with-rules failure).
fix(install): V2 local-first "Next steps" + stamped methodology version
install.sh no longer prints stale V1 guidance ("provision GitHub Project … push to GitHub Projects") or the removed --org/--repo/--project-title args; it shows the correct --with-ci/--with-hooks/--with-rules flow with filelock in the dependency hint. Both install.sh and project_setup.py stamp governance.methodology in a freshly seeded edpa.yaml to the live plugin version.
Tests
New tests/onboarding/ harness (pexpect + tmux) + test_project_setup_vendor.py + test_install_sh_hygiene.py. Full suite 553 → 564 (+11); 0 failures.
Fixes from #51. Full changelog: https://github.com/technomaton/edpa/blob/main/CHANGELOG.md
docs: V1→V2 docs + website sweep (PR #52)
Swept the user-facing docs and the Astro website of the removed V1 GitHub-Project flow (project_setup.py --org/--repo/--project-title, org Issue Types, project_views.py, bidirectional sync.py, issue_map.yaml, .claude/edpa/ paths, project.yaml/heuristics.yaml, .yaml backlog) → V2 local-first throughout. 31 files (repo docs + Astro pages incl. landing/pitch decks reframed to "EDPA needs only git, GitHub optional"). Live on https://edpa.technomaton.com (astro build green, 28 pages).
Merged to
mainafter this tag — supplementary documentation/website work; the installable plugin payload above (PR #51) is unchanged.
v2.1.7 — E2E findings fixes + /contribute @id + /edpa:capacity
End-to-end re-validation of v2 against a real GitHub repo (2 PIs × 5 iterations, 24 PRs, 24/24 real CI runs, 560h derived, all invariants green) surfaced a set of cross-layer fixes and conveniences.
Fixes
- Iteration close now sets the top-level lifecycle
status(not just nestediteration.status), sopi_close, the board, and tooling see an iteration closed via the MCP tool. (#48) backlog.py addno longer leaks ANSI color codes into machine-readable ID output — honorsNO_COLOR/ non-TTY. (#48)- Story-point rollup (
velocity.py,pi_close.py) is now derived from itemjs— velocity and PI predictability populate instead of0/None. (#48)
Features
/contribute @<id>targets a specific contract for multi-contract people who share a GitHub handle (R-2); unknown tokens now warn instead of silently earning 0h. (#49)- New
/edpa:capacitycommand wrapping per-iteration per-person capacity overrides (--list/--add/--remove); new RUNBOOK §3b + web playbook/methodology docs (CZ + EN). (#50)
Tests
- Full suite 546 → 553 (+7 regression tests), 0 failures.
Full report: docs/v2/e2e-real-github-run-2026-05-31.md · PRs: #48, #49, #50.
v2.1.6 — Full collision documentation + methodology page section
Documentation-only release expanding collision handling coverage across all developer-facing surfaces.
No code changes. Engine, schema, hooks, scripts all unchanged from v2.1.5.
What's new
docs/dev-collisions.md — comprehensive guide (108 → 290 lines)
- ASCII timeline diagram showing how a collision happens (T+0 → T+5)
- ASCII flow diagram of the 4 defense layers (cumulative)
- Decision tree — "I got a conflict, what do I do?"
- Recovery flow with annotated comments for each step
- 5 common collision shapes (single / multi / parent chain / cross-type / cascading)
- Installation section (hooks + CI workflow)
- Troubleshooting (3 common gotchas)
- Bypass disclaimer
Integration into existing docs
docs/RUNBOOK.md— new "ID collision handling" section with operator reference table + setup checklist + recovery commandsdocs/quick-start.md— new "Multi-developer setup" section in "What's Next?"docs/github-setup.md— fixed outdated "IDs are immutable" claimplugin/README.md— new "Multi-developer setup" sectionplugin/skills/edpa-add/SKILL.md— new "Parallel ID allocation" sectionplugin/skills/edpa-setup/SKILL.md—--with-hookscross-references layer numbers + explicit Layer 7 manual step
Web — methodology page section 9b (CZ + EN)
methodology.astro(CZ): "9b. ID kolize a renumbering (multi-developer setup)"en/methodology.astro(EN): "9b. ID collisions and renumbering (multi-developer setup)"- Both: full 4-layer table + recovery flow + setup commands + link to GitHub guide
Dashboard improvement (E2E reporting)
/tmp/edpa-e2e-recovered/dashboard.html regenerator adds effective capacity bar — 3 bars per iteration:
- Blue — planning capacity (deklarovaná, statická)
- Yellow — effective capacity (jen aktivní lidé)
- Green — derived (signal-based allocation)
Tooltip shows utilization % (vs both planning and effective) plus "X/Y active people" count. Resolves user feedback about confusing "Capacity vs Derived" gap when some team members were idle in an iteration.
Web: https://edpa.technomaton.com — already on v2.1.6
Install: curl -fsSL https://edpa.technomaton.com/install.sh | bash
Read first if multi-developer setup: docs/dev-collisions.md
v2.1.5 — Collision detection fix + CI workflow + dev docs
Bug fix release for EDPA ID collision detection in feature-branch + PR workflow, plus new defense layer (CI workflow) and developer documentation.
What was broken
renumber_collisions.py and validate_ids.py --pre-push both compared local backlog state against the matching remote branch instead of the integration target (origin/main). In the standard feature-branch + PR workflow — once you push your branch — origin/<your-branch> matches HEAD, so no diff was detected. Collisions with main were invisible to both tools.
End-to-end reproduction in tests/e2e_collision/scenario_a.sh (real GitHub sandbox, two devs both allocate S-5).
Fixes
renumber_collisions.find_collisions()— new optionaltarget_branchargument, defaults to remote's default branch viarefs/remotes/<remote>/HEAD. New CLI flags--target <branch>(for Git Flow projects integrating todevelop) and--check(CI mode — detect + report, no prompt, exit 1 if collisions).validate_ids.cmd_pre_push()— lists upstream items at the integration target tip, not at the merge-base. Items merged tomainafter your branch forked are now visible to the pre-push check.
New: defense layer 7 — CI workflow
plugin/edpa/templates/github-workflows/edpa-collision-check.yml runs on every PR touching .edpa/backlog/ or id_counters.yaml. Detects collisions via renumber_collisions.py --check; on detection, posts a comment with fix instructions and fails the check (PR merge button stays disabled).
New tests
- 5 new unit tests in
test_renumber_collisions.py:test_multi_collision_both_renumbered_sequentially— two Story collisions get sequential IDs (S-5 + S-6), no duplicatestest_parent_chain_renumber_propagates_to_children_only— F-3 → F-4 updates direct children'sparent:refs; grandchildren untouchedtest_three_dev_cascading_collisions— 3-dev sequential renumberingtest_collision_detected_when_on_feature_branch_against_main— regression test for the--targetfixtest_collision_target_branch_arg_overrides_default— Git Flow scenario
tests/e2e_collision/scenario_a.sh— real GitHub sandbox script reproducing the full Alice + Bob workflow end-to-end (init → 2 PRs → Alice merge → Bob conflict → renumber → merge → bob's PR mergeable → squash → verify).
New docs
docs/dev-collisions.md — full developer guide covering all 4 defense layers (pre-commit, pre-push, CI workflow, manual recovery), recovery flow with exact commands, common collision shapes (single / multi / parent-chain / cascading), id_counters.yaml merge resolution trick.
Migration
Existing projects pick up the fix on next bash install.sh or /edpa:setup --update-engine. The CI workflow template needs to be copied manually:
cp .edpa/engine/templates/github-workflows/edpa-collision-check.yml .github/workflows/
git add .github/workflows/edpa-collision-check.yml && git commit -m "ci: add EDPA collision check"Web: https://edpa.technomaton.com — already on v2.1.5
Install: curl -fsSL https://edpa.technomaton.com/install.sh | bash
v2.1.4 — V2.1 local-first parity in plugin metadata
Patch release sweeping the last 4 customer-facing texts still mentioning "bidirectional sync" or "GitHub-native" as headline — aligning with the V2.1 local-first narrative the 2.1.2 release set elsewhere.
No engine, schema, or behavior changes.
Changes
plugin/.claude-plugin/plugin.jsondescription (visible in Claude Code plugin marketplace).claude-plugin/marketplace.jsonplugins[] description (visible when users run/plugin marketplace add technomaton/edpa)plugin/README.mdfile tree —sync.pynow flagged as optional UIweb/src/pages/en/index.astro— "GitHub-native" card → "Git-native, GitHub-friendly" (parity with CZ version fixed in 2.1.2)
Web: https://edpa.technomaton.com — already on v2.1.4
Install: curl -fsSL https://edpa.technomaton.com/install.sh | bash
v2.1.3 — E2E findings + verify scripts parameterized
Patch release applying the 5 actionable findings surfaced by the V2 full end-to-end test, plus a verification run that exercised every fix against a fresh GitHub sandbox. The verification itself uncovered 4 more bugs in the verify + cleanup scripts (stale hard-coded constants from the previous run); those are fixed in the same release.
No engine math or schema changes. Engine behavior is unchanged; only CLI surface, close-iteration workflow, fixture, and test-infrastructure tweaks.
Highlights
fix(backlog)—backlog.py add --typeaccepts all 7 types (Defect/Event/Risk added). Mirrorsedpa_item_createMCP surface; no more manual YAML fallback for those types.fix(close-iteration)— Stage 2b (detect_contributors.py --all-items) explicitly mandatory, with a warning about the silent 0h failure mode if skipped.fix(e2e fixture)—work_plan.yamlInitiative/Epic gate transitions now use portfolio ladder (Implementing, not delivery-onlyValidating).docs(mcp)— Documents that the EDPA MCP server is single-project per session (resolves.edpa/from host project root, not agent cwd).docs(e2e)— Skill-tool subagent gotcha (returns instruction text instead of executing) captured as limitation #4.
Verification (hybrid E2E run, 2026-05-27)
Ran the full 2 PI × 5 iter E2E in hybrid mode (PI-1 real GitHub Actions, PI-2 synthetic injection) against technomaton/edpa-e2e-20260527-181051-2c56a6a0 (archived). Every fix verified live:
| Verification | Result |
|---|---|
| PRs merged | 14/14 |
| CI workflow runs (success) | 14/14 |
Iterations closed (all_invariants_passed=true on first engine pass) |
10/10 |
Frozen snapshots (no _rev2/_rev3) |
10 |
| Per-person timesheets + team rollups | 50 + 10 |
| XLSX exports | 10 |
| Backlog items in expected end-states | 33/33 |
backlog.py validate exit |
0 (previously 3 errors) |
Side fixes: verify/cleanup scripts parameterized
The verification exposed 4 stale-constant bugs in tests/e2e_v2_full/phases/{10,11,12}_*.py + 99_cleanup.sh:
- Hard-coded paths from the previous run
EXPECTED_MERGED_PRS=24assumed full-real CI modeEXPECTED_COUNTSpredated the portfolio ladder fix- Wrong YAML key for iteration lifecycle status (
iteration.statusvs rootstatus)
All four scripts are now parameterized via env vars + /tmp/edpa-e2e-current-run-tag fallback + EDPA_E2E_CI_MODE-aware constants (EXPECTED_MERGED_PRS returns 24/14/0 for real/hybrid/synthetic mode).
Phase run logs refreshed
tests/e2e_v2_full/phases/01..12_*.md refreshed with the hybrid-mode results, timestamps, sandbox SHAs, and script-fix findings.
Full CHANGELOG: CHANGELOG.md
Web: https://edpa.technomaton.com — already on v2.1.3
Install: curl -fsSL https://edpa.technomaton.com/install.sh | bash