Skip to content

Latest commit

 

History

History
119 lines (88 loc) · 9.78 KB

File metadata and controls

119 lines (88 loc) · 9.78 KB

AGENTS Instructions

CRITICAL: Stay in Your Worktree

If you were started in a git worktree (check: does your working directory contain .dispatch/worktrees/?), every file path you read, write, edit, or delete MUST use the worktree path. Never cd to or reference the parent repo at the main checkout path directly — that is the main working tree and other agents or the user may be working there. Edits to the wrong tree silently land in the wrong place, cause merge conflicts, and get lost.

  • Your working directory is your worktree root. Use relative paths or the full worktree-prefixed absolute path.
  • Run git commands from your worktree — they automatically operate on the correct branch.
  • Run pnpm, vitest, and other tools from the worktree root so they pick up your changes.
  • If you need to verify which tree you are in: git rev-parse --show-toplevel.

CRITICAL: Dispatch Status Events (Mandatory)

  • You MUST call the dispatch_event MCP tool throughout every task turn. These events drive the agent status indicator in the Dispatch UI — the more frequently and accurately you report, the more useful the dashboard becomes.
  • Event types and when to use them:
    • working — You are actively making progress: reading files, writing code, running commands, researching. Use a short message describing the current activity (e.g., "Reading agent-sidebar.tsx", "Running E2E tests", "Refactoring auth middleware").
    • blocked — You hit an error, a failing test, a missing dependency, or any obstacle you are actively trying to resolve. Message should describe the blocker (e.g., "Type error in agent-type-icon.tsx", "E2E test 'sidebar toggle' failing").
    • waiting_user — You need a decision, clarification, or approval before continuing. Message should describe what you need (e.g., "Should I delete the legacy endpoint?", "Need confirmation on color palette").
    • done — The task is complete and all checks pass. Message should summarize what was accomplished.
    • idle — No meaningful action was taken this turn (e.g., an informational question was answered).
  • Required checkpoints (minimum):
    1. Start of turn: working with what you are about to do.
    2. Phase transitions: Call working again with an updated message whenever your activity shifts to a distinct phase (e.g., moving from research → implementation → testing → validation). This keeps the UI status current.
    3. On error or obstacle: Switch to blocked immediately. When you unblock yourself, switch back to working.
    4. Before final response: Emit a terminal event — done, idle, waiting_user, or blocked.
  • Hard requirements:
    • Do not send a final response unless done, waiting_user, blocked, or idle has been emitted in the same turn.
    • If dispatch_event fails, report that failure explicitly in the response.
    • Keep messages short (under ~80 chars) — they are displayed in a narrow sidebar.

UI Validation

  • For any UI/layout/style interaction change, validate behavior in Playwright before marking the task complete.
  • Include at least one Playwright interaction that covers the changed UI path (for example: open/close panes, modal flow, or action button state changes).
  • For pages with SSE/WebSocket activity, do not use Playwright waitUntil: "networkidle" for readiness checks.
  • Use waitUntil: "domcontentloaded" (or "load") and wait for concrete UI-ready signals (visible control/text/state) instead.

Component Preference

  • Prefer shadcn/ui components over hand-rolled UI when an equivalent shadcn option exists.
  • Only hand-roll when there is no suitable shadcn primitive or composition path.

Frontend State Ownership

  • Default to colocating state with the smallest component that fully owns the UI and behavior.
  • Do not lift state to a route, layout, or app root unless multiple siblings must coordinate through a shared owner.
  • Treat route/layout-level state as a fallback, not a default. Those layers should not become new dumping grounds.
  • Treat global client state (including Jotai atoms) as rare and justified only for truly cross-cutting concerns.
  • If a piece of state only drives one feature subtree, keep it in that subtree even if persistence is needed. Prefer a small local persistence helper over promoting the whole state domain to global state.
  • Prefer URL state over in-memory UI state for shareable/navigation state such as selected entity, active detail pane, or tab when that state should survive reloads, deep links, or back/forward navigation.
  • Prefer React Query for server state, request lifecycle state, caching, invalidation, optimistic updates, and background refetching. Do not mirror API state into local UI state unless there is a specific UI-only derivation that cannot be computed from query data.
  • Before adding a new atom, first ask:
    1. Is this server state? Use React Query.
    2. Is this only used by one component or feature cluster? Keep it local.
    3. Is this shareable navigation state? Put it in the URL.
    4. Is this truly app-wide and cross-cutting? Only then consider Jotai.
  • App.tsx is a composition root, not a feature implementation file. Do not add feature-specific dialog state, selection state, or view toggles there when they can live lower in the tree.

Persisted UI state (localStorage)

  • For UI state that needs to survive reloads, prefer jotai's atomWithLocalStorage helper in apps/web/src/lib/store.ts over a hand-rolled useState + useEffect pattern. The helper handles SSR-safety, JSON serialization, read-on-mount, and write-on-change in one place — and it sidesteps the read/write effect-ordering races that come up when persistence keys change at runtime.
  • When the persisted value needs to be keyed by another value (cwd, agent ID, route segment, etc.), use jotai's atomFamily to produce one atom per key rather than building a custom prefix scheme on top of plain atoms. Example: atomFamily((cwd: string) => atomWithLocalStorage(\dispatch:foo:${cwd}`, default))`.
  • This is the one place where Jotai is preferred over local state even for feature-specific UI — the persistence machinery belongs in a shared spot, and the atom's identity stays stable across mounts so the value reads back correctly when the dialog/component remounts.

Pre-Completion Checks (Mandatory)

Before marking any task as done, run the following checks and fix any failures:

  1. Type checking: pnpm run check (runs tsc --noEmit for backend + web).
  2. Web finalization: If any files under apps/web/ changed, run pnpm run finalize:web (type check + production build).
  3. E2E tests: pnpm run test:e2e (Playwright). Always spins up its own isolated DB and server — safe to run alongside other agents.
  4. Unit tests: pnpm run test (Vitest) if backend logic changed.
  • Do not consider a task complete until all applicable checks pass.
  • If a pre-existing test is flaky (fails before your changes too), note it in your response but do not skip the rest of the suite.

Web Finalization

  • If any files under apps/web/ changed, run pnpm run finalize:web before marking the task complete.
  • After running pnpm run finalize:web, verify the served app via an explicitly started local dev stack when the task affects UI/theme/rendering behavior.
  • After UI/theme/rendering validation on an isolated dev stack, leave that stack running for the user to inspect unless they explicitly ask you to tear it down.
  • In the final response, include the exact local URLs/ports for the running validation stack and the cleanup command(s) needed to stop it later.

Temporary Files

  • Never write temporary files (screenshots, test scripts, scratch files) to the repo root.
  • Use /tmp/ or $DISPATCH_MEDIA_DIR for ephemeral files.
  • Playwright screenshots should be published via the dispatch_share MCP tool, not saved locally.

Dev Server Management (CRITICAL)

  • NEVER run pnpm run dev directly in your terminal — it will block your session and killing it can kill your agent process.
  • NEVER use pkill, killall, or lsof | xargs kill to manage dev servers — these can kill your own agent process.
  • Use the repo MCP tools to manage dev environments: repo_dev_up, repo_dev_restart, repo_dev_down, repo_dev_status, and repo_dev_logs. They spin up an isolated DB, API server, and Vite frontend on auto-selected free ports.
  • If you start a validation stack for user review, do not tear it down automatically at the end of the turn unless the user explicitly asks.
  • repo_dev_up auto-selects free ports and prints the URLs — just use the printed URLs.

Backend Testing Safety

  • Treat 127.0.0.1:6767 as production by default; do not stop or kill the existing production server for ad-hoc testing.
  • When backend changes need local validation, use repo_dev_up and point validation tooling to the printed URL.
  • Only operate on production (:6767) when explicitly requested by the user.

Development Database

  • Production uses the dispatch database. Never connect to it from dev servers.
  • repo_dev_up creates an isolated Postgres container with its own port — no manual DATABASE_URL setup needed.
  • Migrations run automatically on API server start.

Assisted Update Release Notes

  • When the user indicates that a release should require or recommend assisted update handling, create or update release-notes/next-assisted-update.json.

  • Follow release-notes/AUTHORING.md for the schema, merge rules, and authoring guidance. Do not invent a parallel format.

  • If release-notes/next-assisted-update.json already exists, merge your change into that file instead of creating a second metadata file.

  • Validate the file before finishing with:

    pnpm tsx bin/embed-assisted-update.ts --check-only --metadata release-notes/next-assisted-update.json