Skip to content

Fix scaffold drift; teach the fork seam and the typed rails - #2

Merged
kahwaipd merged 1 commit into
mainfrom
fix/scaffold-drift-and-fork-seam
Sep 8, 2026
Merged

kahwaipd merged 1 commit into
mainfrom
fix/scaffold-drift-and-fork-seam

Conversation

@kahwaipd

@kahwaipd kahwaipd commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Every skill starts from this repo, so each stale line here is inherited by every skill written from now on. Four lines were stale and one thing was missing.

1. The scaffold does not validate — wrong metadata namespace

Frontmatter still declares "bevo":{...} after the rename to metadata.butler. A fresh scaffold fails with:

ERROR metadata.butler: required block missing

— an error whose fix is not in its own text. With the key corrected, a filled-in scaffold validates clean; only the deliberate _template / TODO guards remain on the unfilled template, which is the intended behaviour.

2. "Ship" described a process that is now forbidden

The README said to add your skill to the registry as a submodule under skills/<name>. The registry is now a link directory — skills.json carries name + repo + ref — and SKILL_STANDARD.md's tree rules refuse submodules outright ("Nested repositories / submodules | none"). Following the old text gets the PR rejected. Rewritten to describe the skills.json entry, and what a branch ref vs a tag ref means.

3. ## Customize scaffolded knobs only

It now also asks the author for the fork seam: what calls for a fork rather than a knob, where in duty.py such a condition goes, and which read feeds it. This is what lets a Butler serve an ask the skill's author never anticipated — the hub's whole point. Matches the companion registry PR Virtual-Protocol/butler-skills#19.

4. Dropped the pinned --from-skill _template@0.1.0

A pin rots — butler-copytrade shipped 3.0.1 while still pinning @3.0.0 — and a pin cannot name a fork. --from-skill <name>[@version] makes it optional; butler-dca does not pin.

5. duty.py taught the discouraged rails path

It used raw bevo.events() dict access and hand-rolled a state.json seen-set. The rails say plainly "Prefer the typed generators below" (bevo.trades(), bevo.messages(), bevo.transfers(), …) and ship bevo.state, a dict that saves itself across restarts. The idempotency key — not a local seen-set — is what stops a replayed event acting twice. Rewritten to the shape butler-copytrade actually uses.

Why none of this was caught

This repo's CI has never passed. Its last run failed resolving the composite action:

Can't find 'action.yml' ... for action 'Virtual-Protocol/butler-skills/.github/actions/validate@main'

That action landed on butler-skills main minutes afterwards, so the validator's real output has never been seen on this repo. And even now that it resolves, the scaffold can never go green by design — so CI is a permanently dead signal here. Worth deciding separately whether this workflow should validate a filled copy instead, or be dropped.

🤖 Generated with Claude Code

Every skill starts from this repo, so each stale line here is inherited by
every skill written from now on. Four were stale and one was missing.

- metadata namespace: the frontmatter still declared `"bevo":{...}` after the
  rename to `metadata.butler`, so `validate.py --standalone` fails a
  fresh scaffold with `metadata.butler: required block missing` — an error
  whose fix is not in its own text. With the key corrected, a filled-in
  scaffold validates clean; only the deliberate `_template`/TODO guards remain.
- README "Ship" described adding the skill to the registry as a SUBMODULE
  under `skills/<name>`. The registry is now a link directory: `skills.json`
  carries name + repo + ref, and SKILL_STANDARD.md's tree rules refuse
  submodules outright, so following the old text gets the PR rejected.
- `## Customize` scaffolded knobs only. It now also asks the author for the
  fork seam — what calls for a fork over a knob, where the condition goes in
  duty.py, which read feeds it — which is what lets a Butler serve an ask the
  author never anticipated.
- Dropped the pinned `--from-skill _template@0.1.0`. A pin rots (copytrade
  shipped 3.0.1 still pinning @3.0.0) and cannot name a fork.
- duty.py taught raw `bevo.events()` dicts and a hand-rolled state.json
  seen-set. The rails say "Prefer the typed generators below", and ship
  `bevo.state`, a dict that saves itself; the idempotency key is what actually
  stops a replayed event acting twice.

Why this went unnoticed: this repo's CI has never passed. Its last run failed
resolving the composite action (added to butler-skills main minutes later), so
the validator's real output has never been seen here — and the scaffold can
never go green anyway, by design.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: kw <kahwai@pathdao.io>
@kahwaipd
kahwaipd merged commit f02a8c6 into main Sep 8, 2026
0 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant