Imported from f0rbit/devpad (
packages/cli/tests/golden/anthropic-search/AGENTS.md). Install upstream withnpx skills add f0rbit/devpad --skill anthropic-search. Copyright stays with the author.
anthropic-search
Pipeline-managed Cloudflare Worker. The deployment lifecycle is owned by
the devpad pipelines orchestrator — this repo's pipeline.ts declares
how runs roll out, but does not deploy directly.
Hard rules
- Don't deploy manually. No
wrangler deploy, nowrangler versions deploy. The orchestrator promotes between stages based onpipeline.ts. Usedevpad pipelines run anthropic-searchto trigger a run; usedevpad pipelines approve <run-id> <stage>if a transition needs human gating. - All Anthropic calls go through
env.ANTHROPIC. This Worker holds no Anthropic API key. The vault Worker (separate Cloudflare account, separate repo at~/dev/vault) is the only system that does. Directfetch('https://api.anthropic.com/...')calls will be rejected at build time by the lint rule and at runtime by network egress. - All observability goes through
env.PULSE. Don'tconsole.logfor anything you'd want to query later — emit a structured pulse event instead. - Grants registry is the source of truth. Adding a scope to
grants.tsdoes NOT auto-approve it. Rundevpad pipelines runand watch the grants UI for the approval prompt.
Layout
anthropic-search/
├── src/
│ ├── index.ts # WorkerEntrypoint with /health and /version
│ └── env.ts # Typed bindings (ANTHROPIC, PULSE)
├── infra.ts # Alchemy declaration — Worker + service bindings
├── pipeline.ts # Rollout + gate overrides via extendTemplate
├── grants.ts # Upstream scopes per stage
├── wrangler.jsonc # Wrangler-local dev only; CI uses infra.ts
├── e2e/ # Playwright tests against the live Worker URL
└── .github/workflows/ # CI: build → upload artifacts → start pipeline run
Local dev
bun install
bun dev # wrangler dev on :8787
bun test # bun test
bun e2e # playwright against http://127.0.0.1:8787
Lint & format
This package ships @f0rbit/lint — the same two-layer toolchain every
f0rbit repo uses: oxlint is the fast syntactic gate, a thin typed ESLint
layer (eslint.config.ts) catches the rest, and oxfmt owns all
formatting.
bun run lint # oxlint . && eslint .
bun run lint:fix # oxlint --fix . && eslint --fix .
bun run fmt # oxfmt .
bun run fmt:check # oxfmt --check . (CI gate)
- oxfmt owns formatting. Don't hand-format — run
bun run fmtbefore committing. - Repo-specific exceptions go in
eslint.config.ts'soverridesarray, scoped byfiles, with a comment explaining why — never an inlineeslint-disablewithout one. .oxlintrc.jsonand.oxfmtrc.jsonare byte-copies of the canonical@f0rbit/oxlint-config/@f0rbit/oxfmt-configshapes. Don't hand-edit.oxfmtrc.json— oxfmt has noextends, so drift is only fixable by re-copying the canonical file.
CI flow (set up by .github/workflows/deploy.yml)
bun install, typecheck, unit testsbun build→ bundle todist/- Upload bundle +
d1-plan.json+env.json+infra-plan.json+grants.jsonto corpus (version-set manifest) wrangler versions uploadrecords a version ID against the manifest- POST to the orchestrator's
/runsendpoint with the manifest ID
Promotion past staging is the orchestrator's job, not the YAML's.
Rollout
This scaffold defaulted to atomic rollout, gated by auto
on every transition. Edit pipeline.ts to override per-stage —
extendTemplate returns a typed Result, so a typo in a stage name or
transition key is a compile error rather than a silent no-op.