AGENTS.md
For impeccable commands: root = storefront, IMPECCABLE_CONTEXT_DIR=apps/admin = dashboard. Infer from user keywords. Ask if unclear.
Agent skills
Issue tracker
Issues and PRDs are tracked in GitHub Issues for darjss/vit-store; external PRs are not a triage surface. See docs/agents/issue-tracker.md.
Triage labels
Use the default five-label vocabulary: needs-triage, needs-info, ready-for-agent, ready-for-human, and wontfix. See docs/agents/triage-labels.md.
Domain docs
Single-context layout: root CONTEXT.md plus root docs/adr/. See docs/agents/domain.md.
PostHog funnels
Funnel, conversion, revenue and attribution questions: read docs/agents/posthog-funnels.md first. It has the event spine, the Executor query path and the known data gaps.
vit-playground
Maintenance scripts, product JSON dumps, QA/dogfood reports, and scratch notes live in the sibling repo darjss/vit-playground at ../vit-playground (or ~/dev/vit-playground). Keep vit-store for app source, ADRs, docs/problems/, and plans/.
| Path in vit-playground | Use |
|---|---|
scripts/ | Catalog ops, cache maintenance, slugs, revenue reports, messenger explore |
api-scripts/ | DB/product maintenance; imports @vit/api from the sibling vit-store checkout |
data/ | Product JSON, seed.sql, sample images |
reports/ | Dogfood output, production QA snapshots |
scratch/ | Temp notes and one-off drafts |
vit-stock-review/ | Catalogue audits, stock sheets, generated creatives |
apps/messenger/scripts/ stays in vit-store (wired into worker dev/deploy). Do not move those back into vit-store root scripts/. Run playground scripts from vit-playground or via bun ../vit-playground/scripts/... from vit-store; see vit-playground README.md.
Lint & check
All lint and typecheck cleanup (anti-slop, nkzw, CI gates) follows the same bar. The rules below apply to every lint phase.
Hard rejects
oxlint-disable/eslint-disable(any form)- New rule overrides in
oxlint.config.tsto make CI green as any, chainedas unknown as, or vacuous// SAFETY:comments- Schemas or types that accept everything just to satisfy a rule
Fix order
- Design first — parse at I/O boundaries (valibot or existing wire schemas), name domain types, fix data flow. Internal code takes parsed types, not
unknown. - Contracts —
satisfies, named metadata types; noRecord<string, unknown>without an owner contract. - Assertions last — only when a real invariant remains after step 1. The
// SAFETY:comment must state the concrete invariant that proves the assertion (e.g. "parsed byfooSchemaon the prior line", "Drizzle row fromorderstable"). - Complexity / framework rules — refactor first. A single-line
complexitydisable with aponytail:comment is allowed only on legacy UI hotspots named in the plan; never blanket-off a rule category.
Verify before PASS
| 1 | bunx vp lint <path> |
| 2 | bunx vp fmt --check |
Do not merge a lint PR whose only diff is config overrides or comment spam.
- Use caveman-style output for worker/reviewer agents: terse chat only, details in summary/report files.
- Use the
btca-localskill whenever work depends on third-party/local repo internals, especially Flue. Inspect source/examples before assuming APIs. Cite local paths in summaries when decisions depend on those internals. - Use the
karpathy-guidelinesskill when writing, reviewing, or refactoring code: surgical changes, simple direct design, explicit assumptions, and verifiable success criteria. - For reviews, use
thermo-nuclear-code-quality-reviewonly. Do one review pass; if the author fixes first-pass findings and checks/proof are green, push/PR/merge without a second review unless risk is high or the maintainer asks. - After an issue branch is approved/fixed, proactively push it, open a PR, watch Macroscope only unless told otherwise, merge when safe, clean up worktrees, then start the next unblocked
ready-for-agentissue. - In isolated worktrees, copy or reference local
.env*only when needed for testing and safe. Never commit secrets/private exports. Do not shell-source.envblindly; it may be malformed for shell. - Keep
messenger-chat-history/private and untracked. Do not commit it or derived private payloads.
Messenger agent implementation notes
- Both bots are
apps/messenger(ADR 0012, plan 029): Agents SDK Durable Objects, Chat SDK with@zernio/chat-sdk-adapterfor customer Messenger, a plainPOST /telegram/webhookhandler plus theAdminDO for the Telegram admin bot.apps/agentandpackages/assistantare gone. src/admit.tsowns the Zernio boundary before Chat SDK sees anything: signature check, incoming Facebook DMs for configured accounts, three-minute stale filter. Check Zernio shapes against its OpenAPI spec or the Zernio MCPdocs_searchtool before changing them.- Taps, orders and payments are code paths in
src/conversation.ts. The model never creates orders or writes totals. Customer-facing fixed text lives insrc/copy.tsand is owner-approved; do not reword it without asking. - Every send goes through
send()with a deterministic<turnId>:<part>idempotency key and theoutboxtable. - Local runs:
scripts/capture.tsstands in for Zernio,scripts/store-stub.tsstands in for order and payment writes (never point local runs at production mutations),scripts/send-event.tssends signed events.scripts/eval/is the eval harness (TypeScript, runs against the localwrangler devstack). All eval data lives outside every checkout in~/dev/scratchpad/vit-store/messenger-eval/(override withMESSENGER_EVAL_DIR): Zernio dumps, photos, cases and results. Fresh cases from real traffic:bun --env-file=<main checkout>/.env.prod scripts/eval/pull-zernio.ts(defaults to the main page, since yesterday 00:00 UB), thenbun scripts/eval/build-cases.ts, thenbun scripts/eval/run.ts --cases <EVAL_DIR>/cases-zernio-<date>.jsonl. The pull is slow (about 10 min for 160 conversations), so run it in the background. Production transcripts with tool calls: themessenger-transcriptsskill.