AGENTS.md
Agent guide
Make the smallest direct change. Use inferred types and named exports. New abstractions, helpers and test files need user approval. Keep any and casting wrappers out of application code.
Read for the task
- Solid components or reactivity: .agents/skills/solidjs-v2/SKILL.md. Check installed Solid docs and types. For any reactivity change, follow "Reactivity changes" below.
- Effect workflows or layers: .agents/skills/effect/SKILL.md. Installed package types take precedence over examples.
- Writing or reviewing any code (errors, unknown data, types, tests, run edges): docs/CONVENTIONS.md.
- Local serving: .agents/skills/portless/SKILL.md, then
vp run dev. - Product scope: docs/VISION.md. Plans, prices and limits: docs/PRODUCT.md. Product judgment and tone: docs/SOUL.md.
- Upload, resume, download or cancellation: docs/RELIABILITY.md. Measured gate results: docs/BENCHMARKS.md.
- Tests, scenarios or lint guardrails: docs/TESTING.md. Remaining work: docs/plan/03-testing-and-guardrails.md.
- Tool choices: docs/STACK.md. Code placement and request scope: docs/STRUCTURE.md. Effect reads in Solid: docs/SOLID-EFFECT-BINDING.md.
- Traces, with log lines as span events: Axiom, described in the STACK.md observability lines. Never put a URL, query string, cookie, email or link token in a span attribute or log. Planned but not built: PostHog and Sentry, and other deferred tools in the STACK.md "Later" list.
- Next milestone: docs/plan/01-foundation.md. Optional follow-up: docs/plan/02-pre-upload-readiness.md.
- External precedent:
~/dev/tranzfer2-references/README.md. Those checkouts can use different prereleases; verify syntax locally.
Change and verify
- Use
vpfor package and project commands. After changes runvp check,vp run test, and the relevantvp run build. Report missing tests or blocked checks as such. - Reactivity changes (components, memos, stores, actions): dev builds run with Solid diagnostics on (
diagnostics: trueinapps/web/vite.config.ts). Treat every code as a defect and never allowlist one you haven't understood. Prove the change with acaptureArtifacttest from@solidjs/diagnosticsnext to the component (seeapps/web/src/dashboard/dashboard.test.tsxand docs/TESTING.md):toHaveNoDiagnostics()plus a re-run budget. Full repair guide:apps/web/node_modules/solid-js/skills/reactivity-diagnostics/SKILL.md(about 6k tokens, search it by code). Loop guide:apps/web/node_modules/@solidjs/diagnostics/skills/agent-loops/SKILL.md. Most codes come down to:STRICT_READ_UNTRACKED,PENDING_ASYNC_UNTRACKED_READ: a reactive read outside a tracking scope (destructured props, component body). Read it in JSX, a memo or an effect's compute half;untrack()if a one-time snapshot is the intent.REACTIVE_WRITE_IN_OWNED_SCOPE,ACTION_CALLED_IN_OWNED_SCOPE: a write,refresh()or action call during a component body or memo. Move it to an event handler or effect callback.FLUSH_IN_ACTION,FLUSH_IN_EFFECT_CALLBACK: delete theflush(). In tests, callflush()before reading the DOM.NO_OWNER_EFFECT,NO_OWNER_CLEANUP: create effects andonCleanupunder a component orcreateRoot.UNSTABLE_MEMO_OUTPUT: the memo returns fresh but equal objects. Return stable references or passequals.HOT_SCOPE_*,HUGE_FAN_OUT: a hot signal or one shared value read by many rows. Derive a slower value, or keep the answer in a store keyed by id.EFFECT_WRITES_OWN_SOURCE,EFFECT_RELAY_TEAR: an effect that writes derived state. UsecreateMemo.IMMUTABLE_UPDATE_IN_STORE,UNSTABLE_LIST_IDENTITY: mutate the store draft, orreconcile(data, "id"), and key<For>by a stable id.ASYNC_WATERFALL: read every async source before using any, so they start together.SILENT_HOLD,LONG_HOLD: add feedback withisPending,latestor an optimistic write. Never remove the hold; past 500 ms show aLoadingfallback.
- Keep lint enabled. An exception needs user approval, a file-scoped override and a one-line reason.
- Comments explain runtime quirks and non-obvious constraints.
- When a check fails, reproduce it on unchanged
origin/mainbefore blaming the current diff. - After the same step fails twice, stop and report the exact error and evidence.
- The API Worker's resources and bindings live in
apps/api(resources.ts,index.ts);infra/alchemy.run.tscomposes the stack. Each resource has one definition. - Deploy only from the main checkout, after build and plan review. Leave generated
apps/web/file-routes.d.tsunstaged. - Staging lives at staging.tranzfer.app and deploys from the
devbranch via CI;maindeploys production. Manual staging deploy:vp run --filter @tranzfer/infra deploy:staging. Sign in withPOST /api/auth/staging-login. - Each same-repo PR deploys its own stack, stage
pr-<number>, athttps://pr-<number>.tranzfer.appand runs the e2e suite against it; closing the PR destroys it (.github/workflows/preview.yml). Use it to check your work on a real deployment. Onlyproduction,staging,pr-<number>and localdev_<user>stages boot; anything else fails the deploy. - Delegate well-scoped implementation and verification to
run_subagentswe-2 profiles (subagent_generalfor write work,subagent_explorefor read-only); parallel agents get scratchpad worktrees under~/dev/scratchpad/tranzfer2. - Worker
nameprops stay unset: Alchemy derives stage-scoped names, and an explicit name makes every stage overwrite one worker.
Keep the record useful
Docs hold standing decisions. Package manifests and configuration hold versions and commands. Commits, PRs and issues hold investigation, failures and progress.
Update a rule when a decision changes and cite the PR. Plan files contain remaining work; delete finished items and empty files. Before retrying a rejected approach, search recent commits and merged PRs for the reason.