AGENTS.md · git:20261010.eacda27 · 2026-10-10 · sha256 18a496f2121270ea
AGENTS.md git:20261010.eacda27A
Immutable. This exact content never changes and is served at /api/v1/blob/18a496f2121270ea.
# AUV Agent Guide
Concise but detailed reference for contributors working on AUV. Improve code
when you touch it; avoid one-off patterns and keep the shared runtime model in
view.
## Project Mission
- AUV turns application UI workflows into command-like, inspectable,
replayable, and eventually shortcut-like operations.
- AUV is not only a CLI wrapper and not a generic LLM agent.
- Design around reusable typed operation APIs, first-party drivers, implicit run
recording, artifact capture, replay, and inspection.
- Keep CLI, MCP, library calls, and future UI surfaces on the same execution
model.
- Prefer explicit boundaries between operation execution, drivers, Rust command
frontends, run storage, and reference documentation.
- Use `docs/TERMS_AND_CONCEPTS.md` as the shared vocabulary for run recording,
inspection, trace data, artifacts, and viewer-facing APIs.
- When a design introduces or changes a core term, update
`docs/TERMS_AND_CONCEPTS.md` instead of defining the term only inside a
transient spec.
> Many project details are still undecided. During design and implementation,
> communicate with users frequently and clearly to avoid misunderstandings,
> premature naming decisions, and avoidable rework.
## Project Phase: Restore The AUV Core Lane
AUV is currently pulling its active roadmap back to the Application Use Via
core: invoke, run recording, artifacts, inspection, app-local Rust commands,
and distill/compile/run reuse across frontends. The former SkillBundle surface
has been retired; do not reintroduce bundle execution, export, or verification
as compatibility. The important work is to make the remaining execution surfaces
agree on one shared execution model. Prefer changes that tighten or reconnect
the existing core responsibilities over polishing one archived vertical proof.
There is no `auv-runtime` package or root Cargo package. Runtime is an
architectural responsibility distributed across typed operation modules,
frontend roots, drivers, and `auv-tracing`; do not recreate a catch-all runtime
crate without an owner-approved producer/consumer need.
The macOS AX copilot work remains valuable, but it is no longer the active
product lane. Treat `candidate-action` as a frozen archived vertical proof. Do
not present it as AUV itself, do not expand it with new action classes or
product polish, and do not route new roadmap work through TextEdit-only proof
paths.
Good convergence work usually has one of these shapes:
- Defines or tightens a shared contract in `docs/TERMS_AND_CONCEPTS.md`,
its owning domain crate, run records, artifacts, or typed command facts.
- Reconnects invoke and typed Rust command surfaces so CLI, library, MCP, and future UI
frontends share the same typed execution path.
- Connects an existing producer to an existing consumer with typed evidence,
for example `RecognitionResult -> CandidateRef -> action -> app-owned result`.
- Aligns typed driver results with tracing evidence, for example
`InputActionResult -> app-owned result -> tracing events/artifacts`.
- Fixes a reproduced bug in a narrow path and adds a regression test.
- Turns a known boundary into explicit metadata, failure layers, fallback
reasons, or validation errors.
- Finishes an owner-approved slice without expanding it into adjacent roadmap
work.
Poor convergence work looks like broad cleanup, TODO chasing, opportunistic
helper extraction, speculative backends, or implementing future APIs just
because a doc mentions them. It also includes continuing to deepen the archived
AX copilot vertical and then calling that AUV progress. If the change adds new
surface area, it needs an explicit reason tied to the current contract.
## Scope Discipline
Public capability claims must name an evidence level and link to current
evidence. A live probe is not a support claim, and compilation is not behavior.
Before editing, classify the change as one of: bug fix, test-only, docs-only,
narrow refactor, or approved feature. If none fits, ask for a smaller slice.
Some missing pieces are intentional deferrals, some are incomplete work, and
some are real bugs. Do not guess which one you are looking at. Classify the
gap from evidence, failing tests, owner instructions, or existing reference
docs before implementing anything.
Scope rules:
- Do not implement TODOs, roadmap notes, or future-phase designs unless the
owner names that slice.
- Do not run broad repository scans and turn the findings into drive-by
changes. Search only to understand the assigned slice.
- Do not mix unrelated cleanup into behavior changes. Mention cleanup
opportunities as follow-up candidates instead.
- Cross-layer changes are allowed when they are the approved contract slice,
but the dependency direction must be clear. Example: contract type -> driver
artifact -> read-side inspector test.
- Avoid ad-hoc compatibility shims. Versioned read compatibility for existing
run artifacts or public records is allowed when the migration
boundary and tests are explicit.
Owner approval means the owner named the function/module/behavior, accepted a
concrete proposal, or asked for a specific next slice. A doc mentioning a
future feature, a TODO marker, or a change that feels like "the obvious next
thing" is not approval.
When a good idea appears mid-task, do not implement it inline. Record it as a
candidate next slice with one sentence explaining why it matters, then finish
the current slice.
When you decide *not* to implement something that a reader could plausibly
expect — a field, an enum variant, a branch, an algorithm stage, an API
surface, a fallback path, or any other surface that has been considered and
intentionally left out for the current slice — leave a `TODO:` or `NOTICE:`
marker at the type or call site where the deferral lives. The goal is to
make intent visible: a future reader (Codex, Claude, the owner, a reviewer)
must be able to tell *not yet, on purpose* apart from *forgot to write it*.
A missing marker forces the next reader to guess and frequently produces
unwanted scope expansion when an agent treats the absence as a gap.
A useful deferral marker names three things in one short comment: the gap
(what was considered but omitted), the reason it is deferred (why it does
not belong in this slice), and the trigger that would unlock it (what
condition or owner approval would re-open the decision). When the deferral
is already covered by a reference doc, the inline marker may simply cite
that doc instead of restating the rationale — for example,
`// TODO(view-memory-v1): persistence deferred, see view-parser-view-memory-v0.md`.
The rule is that *something at the code site* must point a reader to the
intentional gap.
Apply this discipline to:
- Enum variants you considered but chose not to add.
- Struct fields you considered but did not add.
- Algorithm stages, fallback paths, or recovery branches you reserved but
did not implement.
- API surfaces you chose to keep private, omit, or stub for the current
slice.
- Reader-side checks that mirror a producer-side guarantee (such as
version rejection on a wire-shape field) when only the producer side
has landed.
A deferral marker is not approval to implement the deferred work later
without owner involvement. It is documentation of an existing decision so
the decision survives the next read of the code.
## Current Contract Seam
The active input-delivery seam is:
```text
typed command or app-owned operation
-> auv-driver capability
-> InputActionResult
-> direct app-owned result + tracing event/artifact
-> separate verification when semantic success is required
```
Keep visual presentation separate from input delivery:
- `auv-driver-overlay-macos` is a visual trust/debug adapter. It may show an AUV cursor,
a user cursor, movement, or click ripples, but it does not prove semantic
success and must not be treated as the input backend.
- `auv-driver` / `auv-driver-macos` owns typed input delivery such as
`WindowTargetedMouse`, `WindowTargetedKeyboard`, foreground fallback,
disturbance metadata, attempts, and fallback reasons.
- Command and app modules should consume or map typed driver results. Do not
grow a parallel action-result schema unless a concrete gap is first
documented.
- Verification remains separate from activation. A successful click, AX press,
or overlay animation is not semantic success without a verification result or
an explicit `activation_only` boundary.
This seam stays in AUV core because multiple command and app paths depend on
the shared driver result and tracing artifact.
The `RecognitionResult -> Candidate` promotion gate (`candidate_promotion` +
`stability`) was retired on 2026-07-23 (branch
`refactor/retire-candidate-promotion-seam`). The archived `candidate-action`
removal (#88, 2026-07-07) had already deleted its recording, read-side, and
execution consumers, leaving both modules with zero production callers and used
only by their own `#[cfg(test)]` blocks. Do not reintroduce this
promotion/stability seam without an owner-approved slice that names a concrete
production consumer.
## Image Payloads
Captured pixels are large. One Retina window capture is about 25 MB of RGBA,
and a display capture about 80 MB. Treat image bytes as a resource that the
Runner owns. Do not treat them as ordinary response data.
- An API response must not carry full image pixels unless the caller
explicitly asked for them. Return a reference plus metadata instead:
bounds, origin, pixel size and scale. Add an explicit fetch for pixels, with
bounded size and encoding.
- A client must never have to send pixels back that AUV produced. An
operation on a capture that AUV made, such as OCR, detection or crop, must
accept a reference to that capture.
- Results and streams, such as find-text evidence, scroll-until steps
and recent frames, return references, metadata or bounded thumbnails by
default. Full frames are opt-in.
- Run recording persists evidence on the AUV side from the same references.
Do not route evidence through the client.
- Only caller-owned images may be uploaded as pixels. An example is an image
the user supplies.
Captures, find-text evidence, scroll-until updates and OCR already
follow this rule: they use `CaptureRef`, and `GetCaptureImage` is the explicit
pixel fetch (see "Capture Frame" in `docs/TERMS_AND_CONCEPTS.md`). One existing
API predates it: `GetRecentFramesResponse` frames
(`TODO(recent-frames-capture-refs)`). Do not copy its shape into new APIs.
## Architecture Surfaces
- **Runtime responsibility**: Typed operation modules own execution semantics;
frontend roots own run-context lifecycle; `auv-tracing` owns recording and
artifact persistence. This is not represented by an aggregate runtime crate.
- **Drivers**: Expose platform or application capabilities through narrow,
capability-oriented APIs.
- **Rust operation crates**: Describe reusable app/domain workflows through
typed Rust APIs and app-local commands.
- **Command frontends**: Parse and present user-facing commands; they should
call typed command or operation interfaces rather than duplicate behavior.
- **Run storage**: Owns durable records, artifacts, trace data, and replayable
inputs.
- **Inspection/viewer APIs**: Read durable run data and artifacts; do not
depend on transient CLI-only behavior.
- **Reference docs**: Record accepted terminology, design decisions, evidence,
and implementation handoffs that should survive beyond a task thread.
## Key Path Index
- `crates/auv-cli-invoke/`: typed invoke commands, registry, direct results,
and command-local argument parsing.
- `crates/auv-cli/src/`: root CLI, built-in MCP frontend, session frontend, and
frontend-owned tracing contexts.
- `crates/auv-tracing/`: run contexts, trace dispatch, artifact persistence,
and write-side stores.
- `crates/auv-driver*/`: shared and platform-specific driver capabilities.
- `docs/README.md`: documentation layout, placement rules, and quick entry
points.
- `docs/TERMS_AND_CONCEPTS.md`: shared vocabulary for core AUV concepts.
- `docs/ai/references/INDEX.md`: responsibility-folder index for reference
notes (start here when browsing references).
- `docs/ai/references/<responsibility>/`: durable reference notes by duty
(runtime, invoke-cli, scan, apps/*, archive/*, …), plus evidence packs and
handoffs.
- `docs/ai/explanations/`: committed tutorials, explainers, walkthroughs, and
diagrams.
- `docs/notes/<owner>/`: personal or exploratory scratch material that should
not be committed unless explicitly requested.
## Commands
- **Build**
- `cargo build`: compile the workspace in debug mode.
- `cargo run`: build and run the current CLI binary locally.
- **Test**
- `cargo test`: run Rust unit and integration tests.
- **Format and lint**
- `cargo fmt`: format Rust code using `rustfmt`.
- `cargo fmt --check`: verify formatting without modifying files.
- `cargo clippy --all-targets --all-features`: run lint checks across the
workspace.
- **Development shell**
- `nix develop`: enter the repository development shell when using the
provided flake.
## Python Tooling
- Pixi is required only for Python or model work: changes to Python files,
`pixi.toml`, `pixi.lock`, Python package metadata, or model and evaluation
environments. Rust, JavaScript, Protobuf, and documentation work does not
need Pixi.
- Load `.agents/skills/use-pixi/SKILL.md` before changing Pixi manifests,
dependencies, environments, tasks, or `pixi.lock`.
- Pixi owns the Python interpreter, Ruff, ty, root Python tasks, and
`pixi.lock` through the root `pixi.toml`. Do not run bare `pip install` or
create ad-hoc virtual environments for repository Python code.
- The `default` environment carries only Ruff and ty, with no Python
interpreter, so the workspace does not pin one Python version. Each Python
package (an eval, a model tool) adds a feature that pins its own `python`
and dependencies, composed into a named environment, for example
`osworld = ["osworld"]`. Packages can then use different Python versions.
- Each Python package's `pyproject.toml` owns its runtime dependencies. Edit
it first, then run `pixi lock`. Use `pixi add` only for environment-only
tools.
- `ruff.toml` and `ty.toml` hold lint, format, and type-check policy. Python
uses Ruff's default four-space indentation, not the Rust `rustfmt.toml`
setting. A package that targets another Python version adds its own
`ruff.toml` with `extend = "../../ruff.toml"` and a `target-version`, and
runs ty in its environment with its own project configuration.
- `pixi run --locked check` runs the Ruff format check, Ruff lint, and ty.
## Development Practices
- Do not treat CLI as the only architecture surface.
- Design changes should account for library calls, CLI frontends, run
recording, replay, and inspection.
- Favor clear module boundaries; shared behavior belongs behind operation,
driver, storage, Rust operation, or inspection boundaries rather than local one-off
helpers.
- Keep frontend entrypoints lean; move reusable policy, validation, recording,
replay, and persistence behavior into the modules that own those decisions.
- Before planning or writing new utilities, commands, driver helpers, operation
helpers, or artifact builders, search for existing internal implementations
first.
- If the logic could become shared project infrastructure, propose the shared
boundary instead of adding a one-off local copy.
- When modifying code, check for small, minimal progressive refactors that make
the touched area clearer.
- Keep changes scoped to the task; do not start broad cleanup or compatibility
work unless the current change depends on it.
- Do not add backward-compatibility guards by default. If extended support is
needed, document the compatibility boundary, why it matters, and the expected
post-refactor shape before adding extra branches.
## Rust Style
- Rust code uses the 2024 edition.
- The repository `rustfmt.toml` sets two-space indentation
(`tab_spaces = 2`).
- Prefer idiomatic Rust naming:
- `snake_case` for functions, modules, and variables.
- `PascalCase` for types and traits.
- `SCREAMING_SNAKE_CASE` for constants.
- Keep public APIs small and documented.
- For design terms that are still under discussion, mark them as provisional in
docs rather than stabilizing them through code names too early.
- Avoid hardcoded Unix, macOS, or Windows path literals unless the path is
truly platform-defined.
- Prefer `Path`, `PathBuf`, component joins, and path-safe arguments over string
concatenation.
- Do not move every literal into a constant. One-time or two-time values should
remain near usage when locality is clearer.
- For retry, timeout, backoff, geometry tolerance, and limit values, avoid one
broad constant that silently governs unrelated behavior.
## Naming & Comments
- Use `observation` sparingly. Reserve it for information collected to inform
the **next action** in a perception/decision/action loop. A capture, frame,
query response, stored record, state snapshot, or streamed update is not an
observation merely because it was read or emitted. Prefer its concrete domain
name, such as `CapturedFrame`, `ParsedViewport`, `FrameItem`, `DeviceStatus`,
`ReadResult`, or `ScrollUntilUpdate`. Even in a decision loop, use the more
specific name when it communicates the payload better.
- Keep third-party names intact (for example Apple's
`VNRecognizedTextObservation`). When renaming first-party terms, migrate
producers, consumers, proto/SDK fields, tests, and current documentation
together. Add a migration notice to older design notes instead of rewriting
historical evidence. See
`docs/ai/references/runtime/2026-10-08-domain-result-naming-migration.md`.
- Prefer names that rely on the module boundary for context instead of
repeating product, platform, protocol, or transport prefixes inside every
symbol.
- A well-named module should let exported functions use short action-first
names; repeat the larger context only when the symbol crosses a boundary where
that context is no longer obvious.
- Name functions after the domain operation they perform, not after the
implementation layer that happens to contain them.
- Use nouns for resolved domain concepts and verbs for transformations or side
effects.
- When a function derives a policy, configuration, selector, or trace decision
from an event or request, name the domain result explicitly so callers
understand what decision is being made.
- Avoid names that encode multiple layers of ownership into one symbol.
- If a name needs several qualifiers to be understandable, reconsider the module
boundary or introduce a clearer local concept.
- Use dependency injection only at real external boundaries: filesystem,
process, clock, environment, OS APIs, accessibility services, window servers,
model runtimes, network, cache, and feature gates.
- Do not introduce `Dependencies` or `Deps` structs for internal functions that
only call sibling helpers or forward parameters.
- Add clear, concise comments for utilities, parsing, OS interaction,
accessibility traversal, geometry/math, FFI, scheduling, artifact persistence,
and architectural functions when the intent, invariant, or platform
constraint is not obvious from names and local context.
- Avoid comments that repeat what the code already says.
- When moving, refactoring, fixing, or updating code, keep existing comments
intact and move them with the code.
- If a comment is truly unnecessary, replace it with a clearer comment or remove
it only when the surrounding code fully preserves the original context.
- Use markers:
- `TODO:` follow-up work that is intentionally left for later.
- `REVIEW:` concerns that need another maintainer or design pass.
- `NOTICE:` magic numbers, workarounds, platform quirks, generated-code
constraints, or important external context.
- When using a workaround, add a `NOTICE:` comment explaining why it is needed,
the root cause, and the removal condition.
- If a workaround was validated through SwiftPM, SourceKit, generated bridge
output, platform documentation, or dependency source, include the relevant
file, command, issue, or URL in code-formatted text.
## Testing Practices
- Focused unit tests live next to the code they cover with `#[cfg(test)]`.
- The current repo already has Rust unit coverage for invoke, tracing,
driver, and CLI behavior.
- Add regression tests for behavior changes and keep them narrow.
- Use `cargo test` for the full suite and include regression tests for bug
fixes.
- For any investigated bug or issue, try to reproduce it first with a test-only
reproduction before changing production code.
- Prefer a unit test. If that is not possible, use the smallest higher-level
automated test or recorded fixture that can still reproduce the behavior.
- When a regression test maps to an external report, include the tracker
identifier in the test name when practical.
- Add the report link as a comment directly above the regression test.
- For local investigations without a tracker, leave a short root-cause comment
when it would help future maintainers understand why the test exists.
- Test through stable public behavior.
- Do not create new exports, dependency bags, wrapper services, or alternate
code paths only to make private implementation details mockable.
- Avoid smoke-only tests for behavior changes.
- Assert the observable output, trace record, artifact, replay input, command
result, or platform-facing call that would have caught the original failure.
- Prefer explicit assertions over overly broad table-driven tests.
- Use tables when the cases share the same behavior and the table improves
readability; keep one-off or highly distinct scenarios as separate tests with
clear names.
Use this root-cause block format in regression tests when relevant:
```rust
// ROOT CAUSE:
//
// If <condition>, <unexpected behavior> happened because <reason>.
//
// Before the fix, <old behavior>.
// The fix keeps <new invariant or behavior>.
```
## Module Design
- Prefer deep modules over shallow modules.
- A module should hide a meaningful decision: policy, persistence boundary,
protocol/schema contract, scheduling semantics, replay semantics, artifact
layout, driver capability, platform permission rule, or lifecycle concern.
- Do not split code by execution order alone.
- A module boundary should represent a stable responsibility that can be
understood without reading all sibling files.
- Keep cohesive domain flows together until there is proven pressure to split.
- A 200-400 line cohesive Rust module is preferable to several shallow modules
that pass the same context or options through each other.
- Before creating a new service, trait, context object, or dependency struct,
verify that it adds policy, validation, state, retry/error handling, IO
isolation, a reusable abstraction, or a platform boundary.
- If a new abstraction does not add those things, keep the logic as a private
helper or inline it.
- Before defining a new reusable primitive — a struct, enum, type alias,
constant, or shared helper — search the workspace (owning/domain crate and
dependencies) for one that already carries the concept. Search by name
(rg/grep) and by shape (ast-grep, else rg/grep), not exact name alone.
- Reuse an existing primitive when it fits; import a dependency's instead of
copying it. A primitive that re-expresses another's shape and meaning is a
duplicate — delete it and reuse the original.
- If one almost fits (missing a derive, method, or variant), extend it in its
owning crate; do not fork a local variant.
- Add a new primitive only for a genuinely distinct concept, never an ad-hoc
copy. Same-shape primitives are allowed only when meanings differ on purpose
(ScreenPoint vs WindowPoint) and the name shows it; place a reusable primitive
in its domain crate, and keep one private only when local and not a
shared-concept duplicate.
- Avoid pass-through services and traits that only forward arguments to another
layer with a similar signature.
- Adjacent layers should expose different abstractions:
- CLI frontends parse and present.
- Typed command and operation interfaces execute.
- Drivers expose capabilities.
- Storage owns persistence semantics.
- Inspectors read durable run data.
- Do not extract tiny one-call helper functions just to name an implementation
step, reduce line count, reduce nesting, or create a test seam.
- Extract a helper only when it is reused by multiple production call sites,
hides non-trivial branching, IO, parsing, normalization, error policy, or
lifecycle logic, or names a stable domain concept.
- Keep reusable domain contracts and rendering/building logic in the crate or
module that owns that domain.
- Frontend entrypoints should wire dependencies and call those boundaries instead
of inlining large reusable contracts.
- Prefer early returns and simple control flow when it improves readability.
- Do not introduce pass-through helpers or shallow modules solely to reduce
indentation.
## Platform-Native Interop
- Prefer capability-oriented module names for platform-native interop layers,
such as `screen`, `window`, `tree`, `keyboard`, `clipboard`, `app`, and
`permission`.
- Keep FFI and generated binding details behind narrow modules named `native`,
`binding`, or `ffi`.
- Do not make dependency names such as `swift_bridge` or broad terms such as
`bridge` into durable public namespaces.
### macOS Swift Packages
- For macOS Swift native code, prefer `swift-bridge` for typed Rust/Swift
interop unless a design explicitly chooses a different boundary.
- When adding a new Swift package or restructuring Swift sources, use Swift
tooling such as `swift package init` to create the package skeleton instead
of hand-writing the project structure from scratch.
- Adapt the generated manifest and sources to the repository layout after
SwiftPM creates the skeleton.
- The macOS Swift packages use generated `swift-bridge` types that are produced
by Cargo during the real build.
- For SourceKit or IDE indexing, run `scripts/generate-swift-bridge` to generate
ignored files under:
- `crates/auv-driver-macos/native/swift/Sources/AuvMacosNative/Generated/`
- `crates/auv-driver-overlay-macos/native/swift/Sources/AuvMacosOverlayNative/Generated/`
- After generating those files, use SwiftPM-side checks so generated bridge
types are visible to the IDE:
- `cd crates/auv-driver-macos/native/swift && swift build`
- `cd crates/auv-driver-overlay-macos/native/swift && swift build`
- Do not commit generated directories.
- Regenerate bridge files after changing:
- `crates/auv-driver-macos/src/native/binding.rs`
- `crates/auv-driver-overlay-macos/src/native/binding.rs`
- When a change touches Rust/Swift FFI declarations or Swift native source
files, rerun `scripts/generate-swift-bridge` before validating.
- Run the SwiftPM build for every touched Swift package.
- Treat SwiftPM and SourceKit errors as real compatibility issues even when
`cargo check` succeeds.
- Keep availability guards, generated bridge types, and IDE-visible imports
current.
## Documentation Workflow
- During active design or implementation, write specs, plans, and working notes
under `docs/ai/references/<responsibility>/` (see
`docs/ai/references/INDEX.md`).
- Do not create or use `docs/superpowers/specs/` or `docs/superpowers/plans/`
for this repository. If a skill suggests those default locations, treat this
repository guide as the override and place the document in the matching
responsibility folder under `docs/ai/references/` instead.
- In-progress documents are the source of truth while the work is underway.
- When an implementation is mostly complete, update durable reference material
in the owning responsibility folder and its `INDEX.md`.
- Add, merge, or revise reference docs so completed and partially completed work
is discoverable outside the original plan or spec. Prefer folding intermediate
handoffs into one durable note rather than leaving long slice-code chains.
- When editing design docs, preserve open questions and clearly label
provisional names so the team can review them before implementation.
- When a document records a finished but non-active vertical proof, move it out
of active references into an archive path and leave only a short tombstone at
the old location. Do not leave archived roadmap context sitting in
`docs/ai/references/` where agents will keep treating it as current guidance.
### Documentation Placement
- Use `docs/ai/references/<responsibility>/` for durable project reference
material: accepted design notes, implementation handoffs, evidence packs,
coverage reports, and records that should be useful to reviewers after the
original task context is gone. Do not use engineering slice codes as folder
or navigation labels.
- Content in `docs/ai/references/` should describe the current project state or
a clearly labeled historical decision.
- Use `docs/archive/verticals/` for archived proofs that should remain
recoverable but must not continue to bias active roadmap decisions.
- Use `docs/ai/explanations/` for committed explanatory material: tutorials,
interactive explainers, conceptual walkthroughs, diagrams, and documents
whose purpose is to teach or clarify an idea rather than record project
evidence.
- Prefer English for committed explanations unless the user explicitly asks for
another language.
- For explanatory HTML files, name the file with the relevant module or feature
name in kebab case as the prefix, followed by a short description, for example
`scroll-scan-visual-row-band.html`.
- Use `docs/notes/<owner>/` for personal, exploratory, or scratch material,
including rough HTML demos, temporary investigation notes, local run logs, and
drafts that are not ready to be shared as durable project references.
- Do not commit notes from `docs/notes/<owner>/` unless the user explicitly
asks for that exact material to be committed.
- If a note becomes generally useful, move or rewrite it into
`docs/ai/explanations/` or `docs/ai/references/` as appropriate before
committing.
## PR / Workflow Tips
- Run formatting and tests before submitting changes that touch Rust code.
- Use `<type>(<crate-name>): <message>` for code commit subjects and PR titles.
Use the exact crate name, for example
`feat(auv-driver-linux): add uinput support` or
`refactor(auv-driver-common): share key parsing`.
- For changes across multiple crates, use the crate that primarily owns the
changed behavior. Do not replace its name with a generic layer such as `input`.
- For primarily documentation changes, including contributor instructions and
skills, use `chore(docs): <message>`.
- For repository tooling changes with no owning crate, use the relevant tooling
scope instead of inventing a crate name.
- Pull requests should include:
- A short description.
- Relevant design or issue links.
- Verification commands run.
- Screenshots or trace artifacts when changing UI inspection, automation, or
documentation visuals.
- Summarize changes, how they were tested, and follow-ups.
- Keep changes scoped.
- Improve legacy code you touch when the improvement is local and directly
supports the task.
- Avoid one-off patterns.
## Validation Commands
- `cargo fmt --check`
- `cargo check`
- `cargo test`
- `git diff --check`
- `cargo run --quiet -- invoke --help`
- `pixi run --locked check` (only when Python files, `pixi.toml`,
`pixi.lock`, or Python package metadata change)