agent-desktop/CONTRIBUTING.md
Lahfir b00a967e0b
Some checks are pending
CI / Format (push) Waiting to run
CI / Test (push) Waiting to run
CI / FFI Python Smoke (push) Waiting to run
CI / FFI Header Drift (push) Waiting to run
CI / FFI Panic Guard (push) Waiting to run
CI / FFI Stub-Adapter Passthrough (push) Waiting to run
CI / FFI Codegen Drift (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
CodeQL / Analyze (rust) (push) Waiting to run
Release / Release Please (push) Waiting to run
Release / Build (aarch64-apple-darwin) (push) Blocked by required conditions
Release / Build (x86_64-apple-darwin) (push) Blocked by required conditions
Release / Build FFI (aarch64-apple-darwin) (push) Blocked by required conditions
Release / Build FFI (x86_64-apple-darwin) (push) Blocked by required conditions
Release / Build FFI (x86_64-unknown-linux-gnu) (push) Blocked by required conditions
Release / Build FFI (aarch64-unknown-linux-gnu) (push) Blocked by required conditions
Release / Build FFI (x86_64-pc-windows-msvc) (push) Blocked by required conditions
Release / FFI Release Gates (push) Blocked by required conditions
Release / Publish to GitHub Release (push) Blocked by required conditions
Release / Publish to npm (push) Blocked by required conditions
Release / Publish Skills to ClawHub (push) Blocked by required conditions
Supply Chain / Audit (push) Waiting to run
docs: add community health files for GitHub community standards (#83)
Completes the recommended community profile (opensource.guide best practices):
- CODE_OF_CONDUCT.md — Contributor Covenant v2.1
- CONTRIBUTING.md — repo-accurate dev workflow, quality gates, coding standards,
  conventional-commit and command-extensibility guidance
- SUPPORT.md — where to get help / report issues
- .github/ISSUE_TEMPLATE/ — bug + feature issue forms and config (security and
  docs contact links; blank issues disabled)
- .github/PULL_REQUEST_TEMPLATE.md — summary, type, gate checklist
2026-06-28 21:41:39 -04:00

8.3 KiB

Contributing to agent-desktop

agent-desktop is a native Rust CLI and FFI library that gives AI agents structured access to desktop applications through OS accessibility trees. Contributions that sharpen that core mission are welcome.

Kinds of contributions that fit this project

  • Bug fixes — wrong JSON output, incorrect ref resolution, STALE_REF on a stable target, etc.
  • New commands — additions to the 54-command surface (follow the Extensibility Pattern below)
  • Platform adapters — Windows (Phase 2) and Linux (Phase 3) adapters implementing PlatformAdapter
  • App-specific quirks — documented edge cases for specific apps (Electron, game engines, etc.) under skills/
  • Docs and skill files — keeping skills/agent-desktop*/ accurate when behaviour changes

Out of scope: embedding LLMs, GUI/TUI interfaces, browser automation, macro recording.

Code of Conduct

This project follows the guidelines in CODE_OF_CONDUCT.md. All contributors are expected to uphold them.

Prerequisites

Requirement Notes
Rust toolchain Pinned to stable via rust-toolchain.toml (rust-version 1.85). rustup picks the correct channel automatically.
macOS 13.0+ Required to build and run the macOS adapter (crates/macos/). The stub adapters for Windows and Linux compile on any platform.
Accessibility permission Required for integration and E2E tests against real apps. Grant it in System Settings > Privacy & Security > Accessibility by adding the terminal you run tests from.
Screen Recording permission Required only for screenshot tests. Same path in System Settings.

Getting started

git clone https://github.com/lahfir/agent-desktop
cd agent-desktop

# Wire up the pre-commit hook (one time per clone)
git config core.hooksPath .githooks

# Debug build
cargo build

# Release build (optimised, < 15 MB)
cargo build --release

# Run the binary
./target/release/agent-desktop snapshot --app Finder -i

Dev workflow and quality gates

All of these must pass before a PR is merged. The pre-commit hook runs the first four automatically.

# Format check
cargo fmt --all -- --check

# Lint — zero warnings required
cargo clippy --all-targets -- -D warnings

# Unit tests (MockAdapter, golden fixtures)
cargo test --lib --workspace

# Binary-level command tests
cargo test -p agent-desktop

# FFI integration tests (C-ABI, enum fuzzing, out-param zeroing)
cargo test -p agent-desktop-ffi --tests

# Core isolation — output must contain no platform crate names
cargo tree -p agent-desktop-core

# E2E harness against the SwiftUI fixture app (requires --release build + AX permission)
cargo build --release
bash tests/e2e/run.sh

The E2E harness drives the release binary against a real SwiftUI/AppKit fixture and asserts every effect by independent observation — never by trusting ok: true. See tests/e2e/README.md for what it covers and how to add a scenario.

CI additionally checks that the release binary stays under 15 MB and that crates/ffi/src/commands/generated.rs is not out of sync with build.rs.

Pre-commit hook

The repo ships a pre-commit hook at .githooks/pre-commit. After cloning, enable it once:

git config core.hooksPath .githooks

On every commit that touches .rs or .toml files, the hook runs:

  1. Inline comment ban — rejects bare // comments in staged .rs files (only /// and //! are permitted)
  2. cargo fmt --all -- --check
  3. cargo clippy --all-targets -- -D warnings
  4. cargo test --lib --workspace

When changes touch crates/ffi/, the hook also runs the FFI codegen-drift check and the stub-adapter passthrough tests locally.

To bypass in a genuine emergency:

git commit --no-verify
# or
SKIP_PRECOMMIT=1 git commit -m "..."

Coding standards

Conventional Commits (required)

Every commit title must begin with one of these prefixes:

Prefix When to use
feat: new capability
fix: bug fix
feat!: / BREAKING CHANGE: footer breaking API or CLI change
refactor: restructures code without changing behaviour
perf: measurable performance improvement
test: adds or fixes tests
docs: documentation only
ci: CI/CD changes
chore: maintenance, dependency bumps
style: formatting only

Format: type: concise imperative description — lowercase prefix, no capital after the colon, focus on the why.

Examples: feat: add scroll-to command, fix: prevent stale ref on window resize, ci: add binary size check

File rules

  • 400 LOC hard limit per file. If a file approaches 400 lines, split by responsibility. Generated files marked @generated are exempt — fix the generator, not the output.
  • No inline comments. Code must be self-documenting through naming. Use /// doc-comments on public items when the name alone is insufficient. // and end-of-line // comments are rejected by the pre-commit hook.
  • One struct/enum per file for domain types. node.rs defines AccessibilityNode. action.rs defines Action.
  • One command per file. Each CLI command lives in its own file under crates/core/src/commands/. Filename matches the command name.
  • No God objects. No struct with more than 7 fields; no function with more than 5 parameters. Use builder patterns or config structs.
  • Explicit pub boundaries. Only lib.rs re-exports public items. Internal modules use pub(crate). No wildcard re-exports.

Error handling

  • Zero unwrap() in non-test code. Propagate Results with ? or match explicitly. Panics are test-only.
  • Every error carries an ErrorCode (machine-readable), message (human-readable), an optional suggestion, and an optional platform_detail.

Core isolation (non-negotiable)

agent-desktop-core must never import a platform crate. Platform crates must never import each other. The only legitimate wiring points are the binary crate (src/) and the FFI crate (crates/ffi/). CI enforces this with cargo tree -p agent-desktop-core.

Adding a new command

Follow the Extensibility Pattern exactly — no step may be skipped:

  1. Create crates/core/src/commands/{name}.rs with a standalone execute() function.
  2. Register it in crates/core/src/commands/mod.rs.
  3. Add the CLI subcommand variant to src/cli/mod.rs and its argument struct under src/cli_args/.
  4. Add a match arm in dispatch() in the binary crate.
  5. If a new Action variant is needed, add it to crates/core/src/action.rs.
  6. If a new adapter method is needed, add it to the PlatformAdapter trait with a default of Err(AdapterError::not_supported()).

No existing files are modified beyond these six registration points.

Mandatory skill update: every new command or changed CLI flag must be reflected in the corresponding file under skills/agent-desktop/references/. Skill files are source-of-truth documentation consumed by AI agents and must stay in sync with the implementation.

Submitting a pull request

  1. Branch from main.
  2. Keep PRs focused. One logical change per PR; separate refactors from features.
  3. Ensure all quality gates pass locally before pushing (see Dev workflow above).
  4. Use a Conventional Commit title for the PR title — it becomes the squash-merge commit message.
  5. Link related issues with Fixes #N or Refs #N in the PR description.
  6. Check that cargo tree -p agent-desktop-core is clean if you touched any crate dependency.
  7. CI runs automatically on every push. A red CI is a blocker.

Reporting bugs and security issues

Bugs and feature requests: open an issue on GitHub Issues. Include the OS version, the agent-desktop version output, the exact command that failed, and the full JSON response.

Security vulnerabilities: do not open a public issue. Use GitHub private vulnerability reporting for this repository. Include the affected version or commit, reproduction steps, expected impact, and any proof-of-concept details. See SECURITY.md for the full scope and response policy.

License

By contributing, you agree that your contributions are licensed under the Apache-2.0 License that covers this project.