AGENTS.md is this repo's README for coding agents: project context, commands, conventions, non-obvious traps, and PR expectations in one predictable place. Keep it high-signal and living; prefer durable source-of-truth pointers over file inventories that drift.
Issues and PRDs live in GitHub Issues for callstack/agent-device; external PRs are not a triage request surface. See docs/agents/issue-tracker.md.
Follow the issue label workflow in docs/agents/triage-labels.md, including ready-for-agent and ready-for-human.
Single-context repo. Read CONTEXT.md for domain language and testing/architecture vocabulary, and docs/adr/ for accepted architecture decisions. See docs/agents/domain.md.
- Classify task type:
- Info-only (triage/review/questions/docs guidance): no code edits and no test runs unless explicitly requested.
- Code change: make minimal scoped edits and run only required checks from Testing Matrix.
- State assumptions explicitly. If uncertain, ask.
- Read required context, not the whole repo:
- tooling/build/linting:
package.jsonandtsconfig*.json - architecture, routing, command contracts, platform boundaries, diagnostics, or review: relevant
docs/adr/ - durable naming/testing vocabulary:
CONTEXT.md
- tooling/build/linting:
- Start with at most 3 files: the owning module, one shared helper, and one downstream caller/adapter if needed. Use
rgbefore opening large files. - Define verifiable success criteria before editing.
- Decide docs/skills impact up front.
- Guarantees erode at path boundaries. Any new dispatch path or fast path classifies its cells in
src/contracts/interaction-guarantees.tsfirst; the typechecker forces completeness, you supply honesty. ADR 0011. - A registry claim is not a semantic check: never mark a cell
runnerwithout reading whether the Swift code implements the guarantee's definition, not just a similar-sounding behavior. - Delegation-on-error is not success-path parity. A fast path that falls back on failure can still succeed on a candidate the shared rules would refuse.
- Do not measure before confirming the code path can fire. An A/B whose B-arm cannot execute returns two green runs masquerading as evidence.
- Typed signals over message sniffing: key on structured details (
details.timeoutMs, reason codes), never on error text. Remaining sniffs are owned debt with in-code rationale — do not copy the pattern. - Snapshot output is the token budget. Never add per-node bytes to the tree; response-level metadata rides once per response.
- Warnings compose, never clobber. Append through the shared response builder; two clobber bugs shipped before this rule.
- Unreleased API surface dies free. Before treating a field as wire-compat, check
git tag --contains <commit>; if it never shipped, delete it now. - Push only behind
&&-chained gates.format:check && typecheck && lint && vitest && git push— a push that can run after a failed gate eventually will.
- Keep changes scoped to one command family or module group unless the task explicitly crosses boundaries. If scope expands, stop and confirm.
- Preserve daemon session semantics and platform behavior.
- Do not inspect both iOS and Android paths unless the task is explicitly cross-platform.
- Ship the minimum code that solves the problem: no speculative features, no single-use abstractions, and no unrelated cleanup.
- Match existing style. Remove imports/variables your change made unused.
- Test through public interfaces when possible. Do not add unrelated exports just to make tests easier.
- Unit tests never wait real time: inject the budget, derive the cadence from it, or assert the budget is wired — the slow-test ratchet (
scripts/vitest-slow-test-reporter.ts) fails tests past 2x budget; speed rules and conversion patterns indocs/agents/testing.md. - Prefer type-level checks when TypeScript can enforce a contract or invalid shape.
- Use
unknownonly at trust boundaries: parsed JSON, daemon/runtime payloads, catch values, generic I/O, or parser callbacks. Once a value is validated or its producer has a known contract, narrow to a domain type or focused parser/helper instead of carryingunknownthrough internal helper and formatter signatures. - Keep modules small for agent context safety. The unit is not lines, it is questions: a file should answer one question, so
rg-> read-whole-file stays one cheap bounded read.- numeric tripwires: target <= 300 LOC per implementation file; past 500, extract before adding behavior; past 1,000 is architecture debt unless it is generated data or a fixture snapshot. There is no exemption for tests (see below).
- name files by the domain concept they answer (
runner-cache.ts,interaction-touch-response.ts), not by layer leftovers (utils2.ts,common.tsaccretion). - colocate machine-readable claims with the code they describe: coverage manifests beside contract tests, registry cells beside enforcement pointers, decision comments at the decision site — agents navigate by claims, not by directory listings.
- test files mirror source topology 1:1: when a source module splits, split its test file the same way in the same PR. A 3,000-line family test aggregation makes every fixture lookup a whole-file read; the worst offenders (
interaction.test.ts, platformindex.test.ts) predate this rule and shrink opportunistically — do not add to them. - shared fixtures live as named exports in a sibling fixtures module (see
test/integration/interaction-contract/fixtures.ts), never as inline literals repeated per test. - long guidance/data tables live behind focused modules instead of sharing a file with parser/runtime logic.
- barrels only at package boundaries; internal barrels add a navigation hop per read. Legacy internal barrels are gated for removal (CONTEXT.md).
- prefer deep modules over mechanical splits: extract when it improves locality for a concept callers already need, not just to reduce line count.
- Before finalizing a code change, do one tightening pass over touched and directly adjacent areas: drop obsolete code, redundant tests, stale helpers/fixtures, and needless duplication made unnecessary by the change.
- Prefer existing helpers. Add a helper only when it reduces real repetition or clarifies domain behavior.
- When adding new guidance, examples, schemas, or command metadata, decide whether it belongs in the command surface, CLI grammar, CLI help, MCP projection, or daemon runtime before editing.
- Prefer updating existing domain vocabulary in
CONTEXT.mdwhen naming a new durable module concept. Do not coin parallel names in docs, tests, and code.
Command identity, routing, capability, and request-policy traits are derived artifacts — inspect their declaration sites instead of prose maps:
- one
CommandDescriptorper command:src/core/command-descriptor/registry.ts(catalog, capabilities, MCP/CLI projection, batch policy, timeout policy — ADR 0008) - daemon route ownership + request-policy traits:
src/daemon/daemon-command-registry.ts(parity-tested) - interaction dispatch paths × guarantees:
src/contracts/interaction-guarantees.ts(ADR 0011) - command names:
src/command-catalog.ts; never re-create command string sets in handlers Keepsrc/daemon.tsa thin router andsrc/daemon/request-router.tsorchestration-only. New daemon handler-family commands update the daemon command registry; its tests guard the traits.
- Package manager:
pnpmonly. Do not add or restorepackage-lock.json. - Daemon state: packaged installs use
~/.agent-device; source checkouts use worktree-scoped dirs under~/.agent-device/dev/<basename-slug>-<hash>. Usepnpm daemon:state-dirto inspect it,--state-dir/AGENT_DEVICE_STATE_DIRto override it, andpnpm clean:daemon --prune-devto prune stale dev dirs. Daemons are isolated by worktree, but devices are not; target different devices/simulators for concurrent worktrees. - Runtime baseline is Node >= 22. Prefer built-in Node APIs such as global
fetch, Web Streams, andAbortSignal.timeoutover compatibility wrappers unless the surrounding code needs a lower-level transport. - Lint/format stack is OXC:
- config:
.oxlintrc.json,.oxfmtrc.json
- config:
- TypeScript is strict enough to surface dead code early:
strict,isolatedModules,noUnusedLocals, andnoUnusedParametersare enabled. - The repo emits with
tsdown(Rolldown) and typechecks withtsgo(native preview); thetypescriptpackage is not a dependency, so there is notscto fall back to. If declaration generation fails, inspecttsconfig.lib.jsonfirst. - Dev-loop staleness has three layers; after editing runtime or runner code:
pnpm build(dist), restart the daemon (it does not self-reload), and remembershutdowndeliberately HANDS OFF a healthy simulator runner — the adopted runner keeps serving the old Swift binary until you kill its process or the source fingerprint changes. Verifying "my change did nothing" against an adopted runner is a classic false negative. tsconfig.lib.jsonneeds an explicitrootDir: "./src"for declaration layout.- Use the aggregate scripts in
package.jsonwhen possible; they encode the expected validation bundles better than ad hoc command lists.
- Prefer these first-pass commands over broad reads:
rg -n "<symbol|command|flag>" src testrg --files src/daemon/handlers src/platforms/apple src/platforms/ios src/platforms/androidgit diff -- <path>for active-branch context- read
.oxlintrc.jsonbefore treating lint output as source-level bugs
- For files over 500 LOC, search for the relevant type/function/section first, then read a bounded range.
- Do not run integration tests by default.
- Keep long help prose in
src/cli/parser/cli-help.ts, flag definitions insrc/cli/parser/cli-flags.ts, and command-specific usage/flag metadata with the command family metadata that owns the command. - If build/type errors mention declaration generation, inspect
tsconfig.lib.jsonbefore reading platform code. - If lint failures appear after toolchain edits, check whether the rule is from
eslint/*,typescript/*,import/*, ornode/*in.oxlintrc.jsonbefore assuming source bugs.
- The OS-agnostic Apple XCTest runner lives under
src/platforms/apple/core/runner/; userg --files src/platforms/apple/core/runnerand read the seam you are changing before editing. - Keep dependency direction clean: transport stays below client/session behavior, shared command/error contracts stay in the runner contract module, and xctestrun preparation/build/cache logic stays isolated from request execution.
- If changing runner connect errors, retry policy, or command typing, start in
src/platforms/apple/core/runner/runner-contract.tsbefore touching client/transport files.
A new snapshot/command flag touches only the layers that need to understand it. Follow this checklist in order:
-
src/cli/parser/cli-flags.ts: add toCliFlags,FLAG_DEFINITIONS, and the relevant exported flag group (e.g.SNAPSHOT_FLAGS). Then update the command family metadata/schema that exposes the flag; find the owner withrg -n "<command>|supportedFlags|allowedFlags" src/commands src/cli/parser. For schema-only CLI commands (cdp,auth,connect,proxy,react-devtools,web), the flag schema owner issrc/utils/cli-command-overrides.ts(SCHEMA_ONLY_CLI_COMMAND_SCHEMAS). -
src/commands/cli-grammar/*: read the CLI flag into command input when the CLI accepts it. -
src/commands/command-projection.tsand command-family projection helpers: write the input into the daemon request only if the flag affects daemon execution. -
src/commands/*-command-contracts.ts: add or update the command input schema only if the option should be available through Node.js or MCP as structured input. -
src/client/client-types.ts: update the public typed client option only when the Node.js interface exposes the option. -
src/client/client-normalizers.ts: update daemon flag normalization only when the request still needs a public-to-internal option translation. -
src/daemon/context.tsandsrc/core/dispatch-context.ts: add the field only when it flows into platform dispatch. -
Handler/platform modules: thread the option only after the command surface, grammar, and projection prove it belongs there.
-
scripts/integration-progress-model.ts: classify the flag (device-observable vs intentionally-outside) — the architecture-progress gate fails CI on unclassified public flags. -
If the flag changes interaction semantics, revisit the affected cells in
src/contracts/interaction-guarantees.ts(command scoping viaappliesTowhen the flag exists only on some commands).
Command-only flags (like find --first) that do not flow to the platform layer usually stop at steps 1-3 (plus step 9).
This repo encodes invariants as self-declaring gates. The correct response to a gate failure is to classify/cover the new thing, never to suppress or allowlist:
- public CLI flags must be classified:
scripts/integration-progress-model.ts - interaction guarantee matrix completeness + honesty:
src/contracts/__tests__/interaction-guarantees.test.ts(gap waivers needtrackingIssue; the pin list changes only in reviewed diffs) - every enforced/delegated matrix cell needs a contract scenario:
src/contracts/__tests__/interaction-contract-coverage.test.ts+test/integration/interaction-contract/ - interaction responses build only through
buildInteractionResponseData: the construction-guard test - every command declares a timeout policy on its descriptor: the timeout-policy completeness test
- TS/Swift rule parity: golden tables under
contracts/fixtures/consumed by vitest and the gated XCTest - cross-command apple-leak guard, folder DAG/import lint, fallow (dead code, duplication, complexity)
- Use process helpers from
src/utils/exec.tsfor TypeScript process execution:runCmd,runCmdStreaming,runCmdSync,runCmdBackground, andrunCmdDetached. Do not import rawspawn/spawnSyncoutsidesrc/utils/exec.ts; add or extend an exec helper instead. Plain.mjspackaging fixtures that cannot import TypeScript helpers should keep child-process usage local and preferexecFile/execFileSyncover spawn. - Use daemon session flow for interactions (
openbefore interactions,closeafter). - Every manual
agent-device openmust have a matchingagent-device closebefore the agent finishes, using the same--session,--platform,--udid, and--state-dirflags. - Use
keyboard dismissfor iOS keyboard dismissal; it may tap safe native controls such asDonebut must not fall back to system back navigation. - Do not remove shared snapshot/session model behavior without full migration.
- Command/device support must come from
src/core/capabilities.ts. - Apple-family target changes must keep
src/kernel/device.ts,src/core/capabilities.ts,src/core/dispatch-resolve.ts,src/platforms/apple/core/devices.ts, andsrc/platforms/apple/core/runner/runner-xctestrun.tsin sync. - iOS simulator-set scoping is iOS-specific: do not let
iosSimulatorDeviceSethide the host macOS desktop target when--platform macosor--target desktopis requested. - If Swift runner code changes, run
pnpm build:xcuitest. - Use
inferFillTextanduniqueStringsfromsrc/daemon/action-utils.ts. - Use
evaluateIsPredicatefromsrc/daemon/is-predicates.tsfor assertion logic.
- Logs backend/source of truth is
src/daemon/app-log.ts. session.tsshould orchestrate only (start/stop/path/doctor/mark), not duplicate backend logic.- App logs are distinct from runner/platform output. Keep app/device log capture in
app.log; Apple runner andxcodebuildsubprocess output belongs in the session-scopedrunner.log. - Preserve external grep/tail workflow in docs/skills.
- Diagnostics source of truth:
src/utils/diagnostics.tswithDiagnosticsScope,updateDiagnosticsScope,emitDiagnostic,withDiagnosticTimer,flushDiagnosticsToSessionFile
- Request diagnostics belong in
sessions/<effective-session>/requests/<request-id>.ndjsononce the effective session is resolved. The top-level daemon log is for daemon lifecycle/startup and pre-session failures. - Session artifact paths are centralized in
src/daemon/session-store.ts; do not hand-build session log paths in handlers. - Do not add ad-hoc stderr/file logging where diagnostics helpers apply.
- Normalize user-facing failures via
src/kernel/errors.ts(normalizeError). - Failure payload contract:
code,message,hint,diagnosticId,logPath,details. - User-facing errors should be short and actionable: say what failed, why when known, and how to recover. Put recovery steps in
hintwhen the action is not obvious, for example restart/retry, use plain screenshot when AX state is unavailable, navigate with coordinates, or inspect logs. - If an interaction unexpectedly takes 5+ seconds, inspect the relevant daemon log before attributing it to the app. Check the session
--state-dirdaemon.logor the failurelogPathfor runner restart, stale session recovery, AX failure, transport retry, or command timeout evidence. - Preserve
hint,diagnosticId,logPathwhen wrapping/rethrowing errors. --debugis canonical;--verboseis backward-compatible alias.- Keep redaction centralized in diagnostics helpers.
- Treat optional optimization calls such as cache/preflight/probe requests as best-effort unless the feature contract says they are required. If an optimization fails, times out, returns non-OK, or returns an unusable shape, prefer falling back to the existing required command path.
- Keep optimization timeouts shorter than the underlying operation timeout. A preflight should not consume the full budget for a later upload or command.
- After changing runtime code exercised through
bin/agent-device.mjsor the daemon, runpnpm buildandpnpm clean:daemonbefore manual device verification so snapshots use currentdistoutput. - For repo-owned
Agent Device Testerverification, useexamples/test-app/README.mdas the source of truth for simulator, physical-device, Metro/dev-client, and app-surface verification steps. Do not treat an already installedcom.callstack.agentdevicelabas sufficient unless the README's Metro/dev-build andsnapshot -ichecks prove the expected app surface is running. - For Android RN/Expo/dev-client apps connected to any local Metro port,
adb reverse tcp:<port> tcp:<port>is harmless and should be run before opening the app or URL on the emulator/device. - In sandboxed agent environments, run manual
agent-deviceCLI verification that starts the daemon outside the sandbox with escalation. The daemon binds localhost, and sandboxed runs can fail before any product code executes withlisten EPERM: operation not permitted 127.0.0.1or repeatedFailed to start daemon/metadata cleanup messages. Do not spend time debugging those as agent-device regressions; rerun the same command with escalation. Unit tests, typecheck, lint, and build can stay sandboxed unless they need platform devices or network/listener access.
- First
nodeexec right after the dev-signed Apple runner launches can block ~19s at 0% CPU (Gatekeeper re-verification). It poisons back-to-back CLI wall-clock timing; absorb with a throwawaynode -e 0or measure in-process/daemon-side. - A leftover session holding the device fails every subsequent command instantly with
DEVICE_IN_USEnaming the owner; the hint'sclose --sessionguidance is the fix, not daemon debugging. - Contention flakes:
request-handler-catalog("specialized daemon routes...") and the doctor provider scenario time out under host load. Protocol before believing a regression: rerun in isolation AND reproduce on plainorigin/mainunder the same load. A changing failure set that passes in isolation is contention, not your change.
- Treat every manually opened
agent-devicesession as a resource that must be closed, including exploratory sessions and failed verification attempts. - For experiments, use a purpose-specific session name and, when practical, an isolated
--state-dirunder/private/tmpwhen you need cleanup isolation beyond the current worktree's default daemon. - Keep track of each opened session in the working notes. Before final response, close each one with the same flags used to open it.
- If
closeor a later command is blocked by stale daemon metadata, inspect running processes first withps -ax | rg "agent-device|xcodebuild test-without-building". Stop only exact stale PIDs that belong to the verification run, then runpnpm clean:daemon. - If cleanup cannot be completed, report the remaining session name, state dir, process IDs, and metadata paths as a blocker.
- Interaction commands (
click,fill,get,is) andwaitaccept selectors and@ref. - Pipeline: parse -> resolve -> act -> record selectorChain -> heal on replay.
- Keep selector parsing/matching in
src/daemon/selectors.ts. - Call
buildSelectorChainForNodeafter resolving target nodes. - New element-targeting interactions must support selector +
@ref, recordselectorChain, and hook replay healing (healReplayActioninsession.ts+ selector helpers insession-replay-heal.ts). - New selector keys remain centralized in
selectors.ts. - New
ispredicates belong inevaluateIsPredicate. - On macOS, snapshot rects are absolute in window space. Point-based runner interactions must translate through the interaction root frame; do not assume app-origin
(0,0)coordinates. - Prefer selector or
@refinteractions over raw x/y commands in tests and docs, especially on macOS where window position can vary across runs.
- Before writing a new test, inspect
src/__tests__/test-utils/index.tsand search for existing factories, fixtures, and mocked binaries withrg -n "export .*make|export .*DEVICE|withMocked" src/__tests__/test-utils. - Use the test-utils barrel for imports and prefer named shared fixtures over inlining new
DeviceInfo,SessionState, snapshot, store, or mocked-binary objects. - Do not duplicate session/store/device helpers when a shared helper already exists; if a helper is missing, add it near the concept it serves and export it through the barrel.
- Docs/skills only: no tests required unless a more specific rule below applies.
- CLI help/guidance changes in
src/cli/parser/cli-help.ts,src/utils/cli-command-overrides.ts, orsrc/utils/command-schema.ts: runpnpm exec vitest run src/cli/parser/__tests__ src/utils/__tests__/command-schema-guards.test.ts. - SkillGym prompt/assertion changes: run
pnpm test:skillgym:case <case-id>; the script builds local CLI help first. For broad validation, usepnpm test:skillgym; append-- --tag fixture-smokeor-- --tag skill-guidancewhen validating one suite group. - Non-TS, no behavior impact: no tests unless requested.
- Keep tests behavioral; do not assert shapes or cases TypeScript already proves.
- Any TS change:
pnpm typecheckorpnpm check:quick. - Fallow CI failures: reproduce with
pnpm check:fallow --base origin/maininstead of manually estimating complexity/dead-code impact. - Test-only DI seam CI failures: the workflow enforces this; do not add optional
typeofDI params in production code. - Tooling/config change (
package.json,tsconfig*.json,.oxlintrc.json,.oxfmtrc.json):pnpm check:tooling. - Daemon handler/shared module change:
pnpm check:unit. - Platform/device-response change (anything emitting
platform/appleOson the wire, or shaping a daemon response): also runpnpm test:integration:providerandpnpm test:coverage— both exercise theprovider-integrationproject (incl. the apple-platform-output leak guard);pnpm check:unitalone does NOT. Internalapplemust never reach a command response — project throughpublicPlatformString. - iOS runner/Swift change:
pnpm build:xcuitest. - Cross-platform behavior change: run
pnpm test:integration. - Any change in:
src/,test/,skills/:pnpm format.
- Static gates first: required checks from Testing Matrix pass,
pnpm check:fallow --base origin/mainis clean when code quality/dead-code risk is relevant, CI guards are green, and no conflict markers or unmerged paths remain. - Do not report a PR as CI-green from a local unit-only run alone: use
pnpm test:unitfor the repo unit bundle, orvitest run --project unit-core --project android-adbwhen invoking Vitest directly. The Integration Tests and Coverage jobs run theprovider-integrationproject, so verify green on the actual PR head across those jobs, not just unit. - Command-surface changes preserve CLI, Node.js, daemon, MCP, help, docs, and SkillGym coverage where that surface is affected. Do not duplicate command contracts across layers.
- Device-facing behavior is not merge-ready until it has real simulator/emulator/device evidence for the changed path. Fixture-backed tests can prove contracts, but they do not replace a live run that creates or observes the artifact/state the feature claims to handle.
- If live verification is blocked, state the blocker, exact command or device needed, and downgrade the PR to residual risk instead of calling it ready.
- Runtime output must stay agent-friendly: compact defaults, top offenders first for diagnostics/perf, bounded arrays in JSON, artifact paths for large raw data, and progressive lookup for deeper detail.
- Before final response or PR handoff, close every manual
agent-devicesession opened during verification and report any cleanup that could not be completed. - Reviewers should check sibling PR ordering, hidden behavior changes, docs/help impact, and whether the tightening pass removed obsolete code/tests introduced or made unnecessary by the change.
- Review against the linked issue, not only the diff. State the issue's motivating behavior and verify the PR fixes that behavior directly.
- Check relevant ADRs before reviewing architecture, routing, command-surface, platform-boundary, diagnostics, or testing-strategy changes. Treat ADR conflicts as review findings unless the PR updates/supersedes the ADR explicitly.
- Read issue dependency notes such as
Blocked by: ..., linked PRs, and sibling branches before judging correctness. If a PR should be stacked on another branch, call out the base/sequence problem before reviewing details. - Trace the real production route from command surface through daemon/request routing to the platform backend. Tests that mock away the router or exercise only a helper do not prove the shipped path.
- For each key regression test, identify what deletion, revert, or old implementation would make it fail. If reverting the implementation still passes, the test is vacuous and must be fixed.
- Check for hidden behavior changes separately from intended refactors, especially output shape, warning/error propagation, artifact paths, and fallback/retry tiers.
- Verify that tests cover the issue's motivating failure, not just the new abstraction or shared helper. Prefer before/after evidence when an external reviewer or issue reports a concrete divergence.
- Treat green CI as necessary but insufficient for device-facing or routing-sensitive work. Require live simulator/emulator/device evidence where the changed path depends on platform behavior.
- Adding command logic to
src/daemon.tsinstead of handlers. - Adding capability checks outside
src/core/capabilities.ts. - Inlining
ispredicate logic in handlers. - Returning non-normalized user-facing errors.
- Duplicating logs backend logic in handlers instead of
src/daemon/app-log.ts. - Growing
src/daemon/handlers/session.tsorsrc/platforms/apple/core/apps.tsfurther without extracting Apple-family/macOS-specific helpers first. - Reintroducing an npm lockfile or assuming ESLint/Prettier still exist in this repo.
- Changing
tsconfig.lib.json/build tooling without runningpnpm check:tooling; declaration generation is stricter than a plain typecheck.
- Versioned CLI help is the agent-facing source of truth. Put workflow guidance/help topics in
src/cli/parser/cli-help.ts, flags insrc/cli/parser/cli-flags.ts, command-specific schema/help metadata with the owning command family, and assertions near the focused CLI parser/help tests. - Keep parser schema and help rendering separate: parser/help rendering lives in
src/cli/parser/, while command schema metadata is derived from command metadata, command family declarations, and the schema-only merge path insrc/utils/cli-command-overrides.ts. - Before planning device automation commands, read
agent-device help workflow; then read topic help such asdebugging,react-native,react-devtools,physical-device,macos, ordogfoodwhen relevant. This is required even when local agent skills are unavailable. - Skills are thin routers. Keep
skills/**/SKILL.mdfocused on when to use the skill, version gating, whichagent-device help <topic>page to read, and a short default loop. Do not duplicate full CLI manuals in skills. - For behavior/CLI surface changes, update help/metadata, README or
website/docs/**when user-facing, and a SkillGym case intest/skillgym/suites/agent-device-smoke-suite.tswhen command-planning guidance changes. - Do not update
skills/**/SKILL.mdfor command behavior or workflow guidance unless the user explicitly asks; skills must route to versioned CLI help instead of carrying behavior details. - Keep SkillGym cases behavioral and command-planning oriented. Prefer prompts that assert the user-visible contract and expected command family over brittle exact output, but forbid known bad patterns.
- Use
pnpm test:skillgym:case <case-id>for focused SkillGym validation; it runs the environment guard and builds local CLI help beforeskillgym run. - Run SkillGym broad validation with
pnpm test:skillgym; append v0.8 filters such as-- --tag fixture-smokefor focused suite groups. - In final summaries, state whether docs/skills were updated; if not, explain why.
- If blocked by network/device/auth/permissions, stop and report:
- blocker
- why it blocks completion
- exact next command/action needed to unblock
- Do not turn this file into a source tree map. For implementation work, identify owner modules from the durable registries and then follow imports/tests from there.
- Command identity and projection: search command descriptors and command contracts first with
rg -n "<command>|CommandDescriptor|defineCommand" src/core/command-descriptor src/command-catalog.ts src/commands. - Daemon routing and policy: start with
src/daemon/daemon-command-registry.ts, then trace to the named handler/request module withrg -n "<command>|route|policy" src/daemon. - Platform behavior and capabilities: start with
src/core/capabilities.tsand the relevant platform undersrc/platforms/; userg, not broad directory reads. - CLI help and command-planning guidance: start with
src/cli/parser/cli-help.tsandsrc/cli/parser/cli-flags.ts; for command-specific schema, searchrg -n "helpDescription|summary|supportedFlags|allowedFlags" src/commands src/cli/parser src/utils/cli-command-overrides.ts, and checkSCHEMA_ONLY_CLI_COMMAND_SCHEMASfor schema-only CLI commands (cdp,auth,connect,proxy,react-devtools,web).
- Before opening PR: ensure no conflict markers/unmerged paths.
- Commit messages and PR titles should use conventional prefixes such as
feat:,fix:,chore:,perf:,refactor:,docs:,test:,build:, orci:as appropriate. - Do not use bracketed automation prefixes such as
[codex]or similar bot tags in commit messages or PR titles. - Open a ready-for-review PR by default. Use a draft PR only when the user explicitly asks for one or the work is intentionally incomplete.
- PR body must be short and include:
## Summary: lead with benefits and reviewer-relevant outcomes. Prefer a compact before/after when it makes the improvement clearer. Include the issue closed by the PR usingCloses #123when applicable.## Validation: answer this prompt in concise prose: "How did you verify the change, and what passed or changed on screen?" Prefer evidence over command dumps; mention the relevant check category or scenario, and include screenshots when visual/UI behavior is relevant.
- Call out real tradeoffs, known gaps, or follow-ups explicitly; omit boilerplate when there are none.
- Include touched-file count and note if scope expanded beyond initial command family.
- When guidance conflicts, apply in this order: Hard Rules -> Scope & Changes -> Testing Matrix -> style/preferences.