agentleFS
moeru-aimoeru-ai/auv/AGENTS.md

auv

AGENTS.md207 starsChanged 34 days agoApache-2.0View on GitHub

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. - 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…

  • Installs packages

The file

Show its rules and text

We split this AGENTS.md into the rules it gives an agent

92 rules. About 0 are common, 68 are distinctive, and 24 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈68

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 24

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Keep CLI, MCP, library calls, and future UI surfaces on the same execution model.

    line 14
  2. Distinctive:

    Prefer explicit boundaries between operation execution, drivers, Rust command frontends, run storage, and reference documentation.

    line 16
  3. Very specific:

    Use docs/TERMS_AND_CONCEPTS.md as the shared vocabulary for run recording, inspection, trace data, artifacts, and viewer-facing APIs.

    line 18
  4. Very specific:

    When a design introduces or changes a core term, update docs/TERMS_AND_CONCEPTS.md instead of defining the term only inside a transient …

    line 20
  5. Distinctive:

    Before editing, classify the change as one of: bug fix, test-only, docs-only, narrow refactor, or approved feature.

    line 76
  6. Distinctive:

    Do not implement TODOs, roadmap notes, or future-phase designs unless the owner names that slice.

    line 86
  7. Distinctive:

    Do not run broad repository scans and turn the findings into drive-by changes.

    line 88
  8. Distinctive:

    Do not mix unrelated cleanup into behavior changes.

    line 90
  9. Distinctive:

    Avoid ad-hoc compatibility shims.

    line 95
  10. Distinctive:

    When a good idea appears mid-task, do not implement it inline.

    line 104
  11. Distinctive:

    When you decide *not* to implement something that a reader could plausibly expect — a field, an enum variant, a branch, an algorithm stage, …

    line 108
  12. Distinctive:

    Keep visual presentation separate from input delivery:

    line 156
  13. Distinctive:

    Run recording persists evidence on the AUV side from the same references.

    line 199
  14. Distinctive:

    Do not route evidence through the client.

    line 200
  15. Distinctive:

    Only caller-owned images may be uploaded as pixels.

    line 201
  16. Distinctive:

    Inspection/viewer APIs: Read durable run data and artifacts.

    line 223
  17. Distinctive:

    Do not treat CLI as the only architecture surface.

    line 294
  18. Distinctive:

    Keep frontend entrypoints lean.

    line 300
  19. Distinctive:

    Before planning or writing new utilities, commands, driver helpers, operation helpers, or artifact builders, search for existing internal …

    line 302
  20. Distinctive:

    If the logic could become shared project infrastructure, propose the shared boundary instead of adding a one-off local copy.

    line 305
  21. Distinctive:

    When modifying code, check for small, minimal progressive refactors that make the touched area clearer.

    line 307
  22. Distinctive:

    Keep changes scoped to the task.

    line 309
  23. Distinctive:

    Do not add backward-compatibility guards by default.

    line 311
  24. Distinctive:

    Prefer idiomatic Rust naming:

    line 320
  25. Distinctive:

    Keep public APIs small and documented.

    line 324
  26. Distinctive:

    Avoid hardcoded Unix, macOS, or Windows path literals unless the path is truly platform-defined.

    line 327
  27. Very specific:

    Prefer Path, PathBuf, component joins, and path-safe arguments over string concatenation.

    line 329
  28. Distinctive:

    Do not move every literal into a constant.

    line 331
  29. Very specific:

    Use observation sparingly.

    line 338
  30. Very specific:

    Keep third-party names intact (for example Apple's VNRecognizedTextObservation).

    line 345
  31. Distinctive:

    Prefer names that rely on the module boundary for context instead of repeating product, platform, protocol, or transport prefixes inside …

    line 352
  32. Distinctive:

    Use nouns for resolved domain concepts and verbs for transformations or side effects.

    line 360
  33. Distinctive:

    When a function derives a policy, configuration, selector, or trace decision from an event or request, name the domain result explicitly so …

    line 362
  34. Distinctive:

    Avoid names that encode multiple layers of ownership into one symbol.

    line 365
  35. Distinctive:

    If a name needs several qualifiers to be understandable, reconsider the module boundary or introduce a clearer local concept.

    line 366
  36. Distinctive:

    Use dependency injection only at real external boundaries: filesystem, process, clock, environment, OS APIs, accessibility services, window …

    line 368
  37. Very specific:

    Do not introduce Dependencies or Deps structs for internal functions that only call sibling helpers or forward parameters.

    line 371
  38. Distinctive:

    Add clear, concise comments for utilities, parsing, OS interaction, accessibility traversal, geometry/math, FFI, scheduling, artifact …

    line 373
  39. Distinctive:

    Avoid comments that repeat what the code already says.

    line 377
  40. Distinctive:

    When moving, refactoring, fixing, or updating code, keep existing comments intact and move them with the code.

    line 378
  41. Distinctive:

    If a comment is truly unnecessary, replace it with a clearer comment or remove it only when the surrounding code fully preserves the …

    line 380
  42. Very specific:

    When using a workaround, add a NOTICE: comment explaining why it is needed, the root cause, and the removal condition.

    line 387
  43. Distinctive:

    If a workaround was validated through SwiftPM, SourceKit, generated bridge output, platform documentation, or dependency source, include …

    line 389
  44. Distinctive:

    Add regression tests for behavior changes and keep them narrow.

    line 398
  45. Very specific:

    Use cargo test for the full suite and include regression tests for bug fixes.

    line 399
  46. Distinctive:

    Prefer a unit test. If that is not possible, use the smallest higher-level automated test or recorded fixture that can still reproduce the …

    line 403
  47. Distinctive:

    When a regression test maps to an external report, include the tracker identifier in the test name when practical.

    line 405
  48. Distinctive:

    Add the report link as a comment directly above the regression test.

    line 407
  49. Distinctive:

    Test through stable public behavior.

    line 410
  50. Distinctive:

    Do not create new exports, dependency bags, wrapper services, or alternate code paths only to make private implementation details mockable.

    line 411
  51. Distinctive:

    Avoid smoke-only tests for behavior changes.

    line 413
  52. Distinctive:

    Prefer explicit assertions over overly broad table-driven tests.

    line 416
  53. Distinctive:

    Use tables when the cases share the same behavior and the table improves readability.

    line 417
  54. Distinctive:

    Use this root-cause block format in regression tests when relevant:

    line 421
  55. Distinctive:

    Prefer deep modules over shallow modules.

    line 434
  56. Distinctive:

    Do not split code by execution order alone.

    line 438
  57. Distinctive:

    Keep cohesive domain flows together until there is proven pressure to split.

    line 441
  58. Distinctive:

    Before creating a new service, trait, context object, or dependency struct, verify that it adds policy, validation, state, retry/error …

    line 444
  59. Distinctive:

    If a new abstraction does not add those things, keep the logic as a private helper or inline it.

    line 447
  60. Distinctive:

    Before defining a new reusable primitive — a struct, enum, type alias, constant, or shared helper — search the workspace (owning/domain …

    line 449
  61. Distinctive:

    If one almost fits (missing a derive, method, or variant), extend it in its owning crate.

    line 456
  62. Distinctive:

    Add a new primitive only for a genuinely distinct concept, never an ad-hoc copy.

    line 458
  63. Distinctive:

    Avoid pass-through services and traits that only forward arguments to another layer with a similar signature.

    line 463
  64. Distinctive:

    Do not extract tiny one-call helper functions just to name an implementation step, reduce line count, reduce nesting, or create a test seam.

    line 471
  65. Distinctive:

    Keep reusable domain contracts and rendering/building logic in the crate or module that owns that domain.

    line 476
  66. Distinctive:

    Prefer early returns and simple control flow when it improves readability.

    line 480
  67. Distinctive:

    Do not introduce pass-through helpers or shallow modules solely to reduce indentation.

    line 481
  68. Very specific:

    Prefer capability-oriented module names for platform-native interop layers, such as screen, window, tree, keyboard, clipboard, app, and …

    line 486
  69. Very specific:

    Keep FFI and generated binding details behind narrow modules named native, binding, or ffi.

    line 489
  70. Very specific:

    Do not make dependency names such as swift_bridge or broad terms such as bridge into durable public namespaces.

    line 491
  71. Very specific:

    When adding a new Swift package or restructuring Swift sources, use Swift tooling such as swift package init to create the package skeleton …

    line 498
  72. Distinctive:

    After generating those files, use SwiftPM-side checks so generated bridge types are visible to the IDE:

    line 509
  73. Distinctive:

    Do not commit generated directories.

    line 513
  74. Very specific:

    When a change touches Rust/Swift FFI declarations or Swift native source files, rerun scripts/generate-swift-bridge before validating.

    line 517
  75. Distinctive:

    Run the SwiftPM build for every touched Swift package.

    line 519
  76. Very specific:

    Treat SwiftPM and SourceKit errors as real compatibility issues even when cargo check succeeds.

    line 520
  77. Distinctive:

    Keep availability guards, generated bridge types, and IDE-visible imports current.

    line 522
  78. Very specific:

    Do not create or use docs/superpowers/specs/ or docs/superpowers/plans/ for this repository.

    line 530
  79. Very specific:

    When an implementation is mostly complete, update durable reference material in the owning responsibility folder and its INDEX.md.

    line 535
  80. Distinctive:

    Add, merge, or revise reference docs so completed and partially completed work is discoverable outside the original plan or spec.

    line 537
  81. Distinctive:

    When editing design docs, preserve open questions and clearly label provisional names so the team can review them before implementation.

    line 540
  82. Distinctive:

    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 …

    line 542
  83. Very specific:

    Use docs/ai/references/<responsibility>/ for durable project reference material: accepted design notes, implementation handoffs, evidence …

    line 549
  84. Very specific:

    Use docs/archive/verticals/ for archived proofs that should remain recoverable but must not continue to bias active roadmap decisions.

    line 556
  85. Very specific:

    Use docs/ai/explanations/ for committed explanatory material: tutorials, interactive explainers, conceptual walkthroughs, diagrams, and …

    line 558
  86. Distinctive:

    Prefer English for committed explanations unless the user explicitly asks for another language.

    line 562
  87. Very specific:

    Use docs/notes/<owner>/ for personal, exploratory, or scratch material, including rough HTML demos, temporary investigation notes, local …

    line 567
  88. Very specific:

    Do not commit notes from docs/notes/<owner>/ unless the user explicitly asks for that exact material to be committed.

    line 570
  89. Very specific:

    If a note becomes generally useful, move or rewrite it into docs/ai/explanations/ or docs/ai/references/ as appropriate before committing.

    line 572
  90. Distinctive:

    Run formatting and tests before submitting changes that touch Rust code.

    line 578
  91. Very specific:

    Use <type>(<crate-name>): <message> for code commit subjects and PR titles.

    line 579
  92. Very specific:

    Use the exact crate name, for example feat(auv-driver-linux): add uinput support or refactor(auv-driver-common): share key parsing.

    line 580

≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

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:

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: ListRecentFramesResponse 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:

// 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)

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.