Repository navigation
Extensibility, worktree lanes, and how we handle exploratory work (design discussion) #93
atamanvega
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
How to read this
A discussion doc, not a decision record. Each topic states the current state in the repo, a proposed approach, and the open questions worth a group decision. Nothing here is built — agree on shape first, then POC and test.
Everything is grounded in the repo at 0.19.12 (branch
feat/gitlab-tracker-adapter). File references point at the canonical top-levelskills/,agents/,instructions/,commands/— not the generated copies underplugins/fullstack-dev-kit/.The through-line: the kit's agnosticism is its main asset, and the pressure on it comes from teams with opinionated workflows. Each proposal tries to absorb that pressure without moving an opinion into the core.
Topic 1 — Extensibility: how do teams add their own steps?
The pressure. The kit is deliberately agnostic, but every team has at least one opinionated step it wants in the pipeline. Concrete example: "add screenshots of the changed screens to the PR description." Today there's no way to express that short of forking. The general shape is WordPress actions/filters — a named point in the workflow a team can hang behavior on, to augment or override.
Current state.
hooks/hooks.jsonexists but wires telemetry only (SessionStart, Stop, SessionEnd →scripts/telemetry.mjs). Wrong layer to build on: (1) it's Claude Code-only — not copied intoplugins/fullstack-dev-kit/, so nothing reaches Codex/Cursor; (2) Claude Code hooks fire on tool calls, not workflow steps — the screenshot case needs to fire on "create-pr is about to compose the body", which has no tool event.Proposed approach — declared extension points, resolved at runtime. Not code hooks: prompt-level
do_action, written into the skill text, resolved from the consuming repo at run time. Each skill declares named points and carries one line per point, e.g. increate-pr:The consuming repo drops in either a prompt fragment (
.md) or a script (.sh, stdout injected). Ordering/enable live in ahooksblock in.claude/dev-kit.json, next togates.Why over alternatives: survives upstream updates (vs fork), travels to Codex/Cursor (vs Claude Code hooks), fires on workflow steps (vs tool calls only).
Candidate first points:
create-pr.body·create-pr.pre-push·work-story.post-plan·pr-review.dimensions·issue-update.comment·follow-ups.filterOpen questions: augment vs. replace must be explicit (a hook that silently drops the AI-generated badge/footer is a traceability regression);
.mdhooks are advisory (model can decline) — document honestly or restrict to.sh; does the screenshot case work end to end (image into a PR body needs a host asset uploadghlacks — spike first); discovery & trust (explicit opt-in indev-kit.jsonrather than "file exists → runs"?).Topic 2 — Worktree lanes and port collisions
Current state. Only
/launch-storycreates a worktree;/work-storyandcoding-agentare explicitly current-directory;plan-backlog/pr-review/fix-prhave no worktree concept. The port problem is a README disclaimer, not a feature. Andlaunch-storyis a command, so it doesn't travel to the portable bundle — Codex/Cursor have no parallel-worktree story at all.Proposed approach — split in two. (1) Lane allocation — host-agnostic, ~20 lines: stable index per worktree →
BASE = 3000 + lane*100. (2) Which variables the lane sets — a## Portssection perinstructions/stacks/*.md(node →PORT/VITE_PORT; react → PlaywrightwebServer.port+baseURL; dotnet →ASPNETCORE_URLS; python → runserver port; php →artisan serve --port). Ships as a## Portssection +scripts/worktree-lane.sh(precedent:scripts/watch-pr-feedback.sh) + aworktreeblock indev-kit.json— travels to Codex; a command would not.Caveats: the kit can export env vars, it can't make the repo read them (deliverable = "the kit hands you a lane and the profile names the 2–3 knobs to wire", not "collisions solved"); ports aren't the only collision (
docker composeshares container names/volumes/DB — a lane should carryCOMPOSE_PROJECT_NAME); dependencies are the bigger day-one friction (fresh worktree has nonode_modules/vendor/.venv).Open questions: base-port arithmetic too opinionated for core (given a
dev-kit.jsonoverride)?; should lanes ship as a hook (Topic 1)?; solve dependency install in the same pass or separately?Topic 3 — Worktree lanes for PR work (not just stories)
fix-pris the strongest candidate — it commits/pushes to the PR branch, so fixing #42 mid-story forces a stash.pr-reviewin a worktree is a quality win (checked out at the PR's commit it could read code around the diff, run the suite, actually execute the coverage gate it claims to check).Proposed approach — generalize the launcher to take a target:
/launch <PROJ-1234 | #42>→ story worktree + work-story, or PR worktree + pr-review/fix-pr. One mechanism, three uses; lane allocation from Topic 2 applies uniformly.Open questions: keep
/launch-storyas an alias or rename?; auto-clean PR worktrees on merge (nothing cleans story worktrees today)?; command (Claude Code-only) vs. skill (travels)?Other gaps worth discussing (observations, not proposals — ranked by value)
evals/gate-driftcovers approval gates only; the riskiest untested surface is the tracker adapters (5 trackers × fetch/update/follow-ups, all prose). Hooks would need evals too..claude/dev-kit.json. A JSON Schema + validator would catch typos, enable autocomplete, and give the new hooks/worktree blocks a home (precedent:validate-codex-plugin.mjs).samples/has php + python; the other nine are unverified prose. Mark CI-verified vs iteration-zero per profile in the README.dev-kit.jsongains blocks.work-storyfails at step 5/8 → re-running redoes fetch + plan gate. Document a resume / persist state in.claude/.stacks: []array. The hard part is scoping: which package a story touches, which gates run where.launch-story, no/plan-backlogcommand, nocoding-agent. A table would set expectations.Process (how we handle exploratory work)
We already have a lightweight RFC flow, it just isn't named: a tracking issue holds the shaping, phased PRs implement against it, and the CHANGELOG entries read like mini-ADRs (see #64 → plan-backlog → phase 2). Proposal: name it and fill the one gap, don't replace it.
plan-backlog— turn an idea/description into a well-formed backlog in the configured tracker (PO-facing) #64/feat: close the loop — offer to create tracked follow-ups from a story's loose ends #67/feat(evals): adversarial approval-gate scenarios for the gate-drift suite #71 pattern) — not seven issues off the gap list now.rfcs/directory for now — overhead that rots for one repo/org.The one exception — hooks warrants a written RFC (→ #92): a public contract others build against, hard to change once handlers ship, touches every skill; Topics 2/3 are reversible, this isn't. Governance rule it must settle: the kit ships the extension points and never the handlers. And RFC/POC aren't alternatives — the POC's acceptance criterion is an eval ("does an override actually override?"), so it isn't throwaway.
Sequencing + decisions we'd like from the discussion
Sequencing: hooks first, evals for them immediately after — it makes everything else optional instead of forked, and Topics 2/3 become hooks rather than core opinions, so we only argue the extension mechanism once.
Decisions wanted: (1) accept the extension-point model over Claude Code hooks/forking?; (2) augment-only or augment+replace (decides whether AI-traceability metadata is overridable)?; (3) lanes in core or as a hook?; (4) command vs. skill for the launcher (do parallel workflows stay Claude Code-only)?; (5) which gap jumps the queue.
POC scope (to test later): one extension point wired end to end in
create-pr(create-pr.body, both.mdand.sh); the screenshot case as the test handler; a## Portssection in two stack profiles + a--worktreepath infix-pr; an eval scenario per handler kind (gate-drift stub pattern).All reactions