Minimal operating guide for AI coding agents in this repo.
Issues and PRDs live in GitHub Issues for callstack/agent-device. See docs/agents/issue-tracker.md.
Follow the issue label workflow in docs/agents/triage-labels.md.
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.
- If the task touches tooling/builds/linting, read
package.jsonandtsconfig*.jsonbefore source files. - Prefer repo scripts over reconstructing command bundles by hand:
pnpm check:quick: lint + typecheckpnpm check:tooling: lint + typecheck + buildpnpm check:unit: unit + smokepnpm check: full non-integration validation
- Read at most 3 files first:
- owning handler/module
- one shared helper used by that handler
- one downstream platform file if needed
- Define verifiable success criteria before editing.
- Decide docs/skills impact up front.
- Solve issues with the smallest context read.
- Keep changes scoped to one command family or module group.
- Preserve daemon session semantics and platform behavior.
- Expand only when contracts cross module boundaries.
- Do not read both iOS and Android paths unless explicitly cross-platform.
- If requested fix expands beyond one command family/module group, stop and confirm before broadening scope.
- Minimum code that solves the problem. No speculative features.
- No abstractions for single-use code.
- Surgical edits only.
- Match existing style.
- Remove imports/variables YOUR changes made unused; do not clean unrelated dead code.
- Keep tests minimal: if TypeScript can enforce a contract or invalid shape, prefer a type-level check over duplicating that assertion in runtime tests.
- Keep modules small for agent context safety:
- target <= 300 LOC per implementation file when practical.
- if a file grows past 500 LOC, plan/extract focused submodules before adding new behavior.
- if a file grows past 1,000 LOC, treat it as architecture debt unless it is generated data, a fixture snapshot, or an integration test aggregation.
- long guidance/data tables should live behind focused modules instead of sharing a file with parser/runtime logic.
- 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 scoped cleanup pass over touched and directly adjacent areas.
- Drop dead or obsolete code, redundant tests, stale helpers/fixtures, and needless duplication made unnecessary by the change.
- Prefer an existing helper over a new one; add a helper only when it reduces real repetition or clarifies domain behavior.
- Simplify control flow and types when the change makes defensive branches or compatibility shims unnecessary.
- Do not expand into unrelated refactors. If cleanup is valuable but broader than the task, note it as a follow-up.
- Optimize for one-pass agent reads. A module that requires reading many siblings to understand one change is usually too shallow; a module that hides one concept behind a small interface is usually worth keeping.
- Start with the owning module, then one shared helper, then one downstream caller or adapter. Broaden only when the contract crosses that edge.
- Use targeted symbol searches before opening large files. For files over 500 LOC, search for the relevant type/function/section first, then read a bounded range.
- Do not add unrelated exports just to make tests easier. Test through the public interface when possible; if that is awkward, consider whether the module's interface is too shallow.
- 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.
- Keep
src/daemon.tsas a thin router. - Keep command names centralized in
src/command-catalog.ts; do not re-create command identity sets in handlers or request policy modules. - Keep daemon routing and request-policy traits centralized in
src/daemon/daemon-command-registry.ts; request modules should consume its predicates instead of recreating command string sets. Seedocs/adr/0003-daemon-command-registry.md. - Keep command input/output contracts in the command modules:
- command surface and shared schemas:
src/commands/command-surface.ts,src/commands/command-contract.ts,src/commands/command-input.ts - typed client command execution:
src/commands/client-command-contracts.ts - command families:
src/commands/interaction-command-contracts.ts,src/commands/batch-command.ts, with other typed client contracts insrc/commands/client-command-contracts.ts - CLI positional/flag grammar:
src/commands/cli-grammar.tsandsrc/commands/cli-grammar/* - typed input to daemon request projection:
src/commands/command-projection.ts - CLI/client/runtime output projection:
src/commands/cli-output.ts,src/commands/client-output.ts,src/commands/runtime-output.ts
- command surface and shared schemas:
- Do not reintroduce CLI-shaped command adapters or schemas as a second source of truth. CLI, Node.js, and MCP should project from command contracts.
- Keep
src/daemon/request-router.tsas request orchestration: auth, diagnostics scope, request admission, locking, handler chain, and fallback dispatch. - New daemon handler-family commands must update
src/daemon/daemon-command-registry.tswith the route and request-policy traits.src/daemon/__tests__/daemon-command-registry.test.tsguards route and policy traits; handler catalog tests keep executable handler sanity checks. - Put request policies in focused request modules:
- tenant/lease/selector/lock admission:
src/daemon/request-admission.ts - artifact/error finalization:
src/daemon/request-finalization.ts - request-scoped platform provider scoping:
src/daemon/request-platform-providers.ts - generic fallback dispatch + action recording:
src/daemon/request-generic-dispatch.ts - recording invalidation health:
src/daemon/request-recording-health.ts
- tenant/lease/selector/lock admission:
- Put command logic in handler modules:
- session/apps/appstate/open/close/replay/logs:
src/daemon/handlers/session.ts - click/fill/get/is:
src/daemon/handlers/interaction.ts - snapshot/wait/alert/settings:
src/daemon/handlers/snapshot.ts - find:
src/daemon/handlers/find.ts - record/trace:
src/daemon/handlers/record-trace.ts
- session/apps/appstate/open/close/replay/logs:
- Commands routed as generic in
src/daemon/daemon-command-registry.tsfall through to daemon fallback dispatch after specialized handlers return null.
- Package manager:
pnpmonly. Do not add or restorepackage-lock.json. - Packaged installs use
~/.agent-deviceas the implicit daemon state dir. Source checkouts default to a worktree-scoped daemon state dir under~/.agent-device/dev/<basename-slug>-<hash>so local branches do not block each other. Usepnpm daemon:state-dirto print the effective path for the current worktree;--state-dirandAGENT_DEVICE_STATE_DIRremain authoritative overrides. Daemons are isolated by worktree, but devices are not; target different devices or simulators when running multiple worktrees concurrently. After pulling the worktree-scoped daemon change for the first time, stop any legacy source-checkout daemon withAGENT_DEVICE_STATE_DIR=~/.agent-device pnpm clean:daemon. Worktree-scoped state dirs outlive deleted worktrees; runpnpm clean:daemon --prune-devoccasionally (for example after deleting worktrees) to remove dirs under~/.agent-device/dev/with no live daemon and no activity for 14 days — it prints one line per removed dir and never touches the global~/.agent-deviceroot contents. - 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
rslib, nottsc. If declaration generation fails, inspecttsconfig.lib.jsonfirst. 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 broader reads:
rg -n "<symbol|command|flag>" src testrg --files src/daemon/handlers src/platforms/ios src/platforms/androidgit diff -- <path>for active-branch context- read
.oxlintrc.jsonbefore treating lint output as source-level bugs
- 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.
logs:src/daemon/handlers/session.ts->src/daemon/app-log.ts->src/daemon/handlers/__tests__/session.test.tsopen/close/replay/apps/appstate:src/daemon/handlers/session.ts->src/daemon/session-store.ts->src/daemon/handlers/__tests__/session.test.tsclick/fill/get/is:src/daemon/handlers/interaction.ts->src/daemon/selectors.ts->src/daemon/handlers/__tests__/interaction.test.tssnapshot/wait/settings/alert:src/daemon/handlers/snapshot.ts->src/daemon/snapshot-processing.ts->src/daemon/handlers/__tests__/snapshot-handler.test.tsrecord/trace:src/daemon/handlers/record-trace.ts->src/platforms/ios/runner-client.ts->src/daemon/handlers/__tests__/record-trace.test.ts
- Keep dependency direction clean:
runner-client.ts: command execution + retry behaviorrunner-transport.ts: connection/probing/HTTP transportrunner-contract.ts: sharedRunnerCommandtype and runner connect/error helpersrunner-session.ts: session lifecycle and request/response executionrunner-xctestrun.ts: xctestrun preparation/build/cache logic
runner-transport.tsmust not import back fromrunner-client.ts.- If changing runner connect errors, retry policy, or command typing, start in
src/platforms/ios/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/utils/cli-flags.ts: add toCliFlags,FLAG_DEFINITIONS, and the relevant exported flag group (e.g.SNAPSHOT_FLAGS). Add the flag toCLI_COMMAND_OVERRIDESinsrc/utils/cli-command-overrides.tsfor each command that supports it; command names/descriptions come from command contracts unless CLI help needs a specific override.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-types.ts: update the public typed client option only when the Node.js interface exposes the option.src/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.
Command-only flags (like find --first) that do not flow to the platform layer usually stop at steps 1-3.
- 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/utils/device.ts,src/core/capabilities.ts,src/core/dispatch-resolve.ts,src/platforms/ios/devices.ts, andsrc/platforms/ios/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/utils/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 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.
- 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, check
src/__tests__/test-utils/for existing helpers:device-fixtures.ts: canonicalDeviceInfoconstants (ANDROID_EMULATOR,IOS_SIMULATOR,IOS_DEVICE,MACOS_DEVICE,LINUX_DEVICE, etc.)session-factories.ts:makeSession,makeIosSession,makeAndroidSession,makeMacOsSessionstore-factory.ts:makeSessionStore(creates tempSessionStoreinstances)snapshot-builders.ts:buildNodes,makeSnapshotStatemocked-binaries.ts:withMockedAdb,withMockedXcrun(stub CLI binaries for dispatch tests)
- Use
import { ... } from '<relative-path>/__tests__/test-utils/index.ts'for convenient barrel imports. - Prefer shared fixtures over inlining new
DeviceInfoorSessionStateobjects in tests. - Do not duplicate
makeSessionStore,makeSession, or device constants when a shared helper already exists.
- Docs/skills only: no tests required unless a more specific rule below applies.
- CLI help/guidance changes in
src/utils/cli-help.ts,src/utils/cli-command-overrides.ts, orsrc/utils/command-schema.ts: runpnpm exec vitest run src/utils/__tests__/args.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. - 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. - 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.
- Do not read unrelated files once owning module is identified.
- Do not run integration tests by default.
- Do not inspect both iOS and Android codepaths unless task requires both.
- Prefer targeted
git diff -- <paths>over broad file reads during review. - Keep long help prose in
src/utils/cli-help.ts; keep flag definitions insrc/utils/cli-flags.ts; keep CLI-specific command usage/flag metadata insrc/utils/cli-command-overrides.ts. - Prefer
snapshot -i,find, and scoped selectors over repeated full snapshot dumps when exploring Apple desktop UIs. - Keep PR summaries short and scoped.
- 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/ios/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 thantsc --noEmit.
- Versioned CLI help is the agent-facing source of truth. Put workflow guidance and help-topic prose in
src/utils/cli-help.ts, keep flag definitions insrc/utils/cli-flags.ts, keep CLI command overrides insrc/utils/cli-command-overrides.ts, and assert important copy insrc/utils/__tests__/args.test.ts. - Keep parser schema and help rendering separate:
src/utils/command-schema.tscomposes contract-derived command schemas with CLI overrides;src/utils/cli-help.tsowns help topics and usage rendering. - 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 the versioned help instructions in
src/utils/cli-help.tsor the CLI command metadata insrc/utils/cli-command-overrides.ts, then assert important help copy insrc/utils/__tests__/args.test.ts. Also updateREADME.mdand relevantwebsite/docs/**when user-facing docs need it. - For behavior/CLI surface changes and command-planning guidance changes, write or update a SkillGym case in
test/skillgym/suites/agent-device-smoke-suite.tsthat captures the expected agent command plan. - 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. - Preserve current high-value workflow guidance:
- iOS Expo Go dogfood: prefer
agent-device open "Expo Go" <url> --platform ioswhen the shell is known, thensnapshot -ito confirm the project UI rather than the runner splash. keyboard dismissis the preferred iOS keyboard-dismissal path before manually pressing visible keyboard controls such asDone; it remains best-effort and can report unsupported layouts explicitly.- Empty replacement is not a supported clear-field command; do not document or test
fill <target> ""as clearing. Prefer visible clear/reset controls or report the tool gap. - Mutating commands against one session must run serially. Parallelize only read-only commands or commands on separate sessions/devices.
- iOS Expo Go dogfood: prefer
- 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
- CLI parse + formatting:
src/bin.ts,src/cli.ts,src/utils/args.ts - CLI help + option metadata:
src/utils/cli-help.ts,src/utils/cli-flags.ts,src/utils/cli-command-overrides.ts,src/utils/command-schema.ts,src/utils/cli-option-schema.ts - Daemon client transport:
src/daemon-client.ts - Daemon state/store:
src/daemon/session-store.ts - Selector DSL and matching:
src/daemon/selectors.ts ispredicate evaluation:src/daemon/is-predicates.ts- Shared action helpers:
src/daemon/action-utils.ts - Snapshot shaping + labels:
src/daemon/snapshot-processing.ts - Handler context helpers:
src/daemon/context.ts,src/daemon/device-ready.ts - Request routing/policy:
src/daemon/daemon-command-registry.ts,src/daemon/request-router.ts,src/daemon/request-admission.ts,src/daemon/request-generic-dispatch.ts - Dispatcher + capability map:
src/core/dispatch.ts,src/core/dispatch-context.ts,src/core/dispatch-interactions.ts,src/core/capabilities.ts - Command identity + command surface:
src/command-catalog.ts,src/commands/command-surface.ts,src/commands/command-contract.ts,src/commands/client-command-contracts.ts - CLI grammar:
src/commands/cli-grammar.ts,src/commands/cli-grammar/* - Daemon request projection:
src/commands/command-projection.ts - Platform backends:
src/platforms/ios/*,ios-runner/*,src/platforms/android/*
- 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.
- Run required checks for touched scope from Testing Matrix.
- 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 -> Testing Matrix -> style/preferences.