Files
portersky ae9c71d76e docs: require m_ prefix for private data members
Co-Authored-By: qwen3.8-27b@q3_k_xl: added m_ member naming rule
2026-08-29 14:32:50 +02:00

9.5 KiB

AGENTS.md

Project Overview

xone_macos is a user-space macOS app that speaks to the Xbox Wireless Dongle (MediaTek MT76xx chip) and exposes connected controllers as HID gamepads. It ports the Linux kernel driver medusalix/xone to macOS: a C++ protocol stack (USB, MT76 chip, GIP, auth) plus a Swift app layer.

Current state: build system and module scaffolding are in place. The protocol ports land phase by phase; see PLAN.md.

Build System

  • Generator: Ninja (the Xcode generator also works; Unix Makefiles do not support Swift)
  • CMake minimum: 3.21
  • Languages: C++23 (protocol stack), Swift (app layer)

Commands

Configure:

cmake -S . -B build -GNinja -DBUILD_TESTING=ON

Build:

ninja -C build

Run:

./build/xone_app

Run tests (full Unity output):

ninja -C build check

Run a single test (requires prior build):

ninja -C build test_version && ninja -C build test

Prefer ninja -C build check for everyday use; it builds and runs in one step. The built-in test target only executes CTest and does not trigger a rebuild, so the binaries must already be up to date.

Configure with AddressSanitizer:

cmake -S . -B build-asan -GNinja -DBUILD_TESTING=ON -DENABLE_ASAN=ON

Dependencies

Dependencies are managed via custom Find*.cmake scripts in deps/. These scripts use FetchContent under the hood to download and build libraries automatically.

To add a new dependency:

  1. Add the corresponding Find<name>.cmake to deps/
  2. Add find_package(<name> REQUIRED) to CMakeLists.txt
  3. Link with <name>::<name> in target_link_libraries()

Static Libraries

The project is split into static libraries, layered bottom-up:

  • xone_usb: USB transport (IOKit / IOUSBFamily)
  • xone_auth: auth + crypto (ECDH, RSA, SHA transcript/PRF)
  • xone_mt76: MT76 chip protocol (firmware load, EFUSE, radio init, beacons, pairing, WCID key setup)
  • xone_gip: GIP protocol (client lifecycle, handshake, status reports)
  • xone_hid: virtual HID gamepad presentation
  • xone_api: C ABI bridge consumed by the Swift app and tests

The Swift executable xone_app links against xone_api.

CMake Module Path

deps/ is added to CMAKE_MODULE_PATH so find_package() resolves to the custom scripts instead of system-installed packages.

Coding Conventions

C++ (protocol stack)

  • Language: C++23
  • Trailing return type for function signatures (e.g. auto fn() -> void)
  • 4-space indentation
  • No semicolons after closing braces for namespaces/classes
  • auto for obvious types (e.g. auto main(...) -> int)
  • East const (e.g. char const* not const char*)
  • Public members first in class declarations, private members at the bottom
  • Private data members start with m_ (e.g. m_state)
  • <> includes only for system headers (std, OS, etc.)
  • "" includes for third-party dependencies
  • Naming: snake_case for variables, functions, and classes
  • Naming: SCREAMING_SNAKE_CASE only for macros and constants
  • Header extensions: C++ headers use .hpp, C headers use .h
  • Include order:
    1. C++ standard library headers (<chrono>, <vector>, etc.)
    2. (blank line)
    3. C standard library headers (<stdlib.h>, <string.h>, etc.)
    4. (blank line)
    5. OS-specific headers (IOKit, CoreFoundation, POSIX, etc.)
    6. (blank line)
    7. Third-party dependencies ("unity.h", etc.)
    8. (blank line)
    9. Local/project headers

Swift (app layer)

  • 4-space indentation
  • Types: UpperCamelCase; functions, properties, and parameters: lowerCamelCase
  • Prefer let over var; default to immutability
  • Use guard let for early return; no force-unwraps outside tests
  • Keep the app layer thin (UI + lifecycle); protocol work lives in C++

C bridge (include/app/xone_api.h)

  • Pure C only: no C++ syntax. The header is imported into Swift via -import-objc-header, so it must compile as C.
  • Standard C declaration style with east const (e.g. char const*); trailing returns do not apply here.
  • Use stdbool.h types so Swift sees Bool.

Shell Scripts

  • Always use #!/bin/sh shebang for shell scripts
  • Scripts must be POSIX compliant (no bashisms)
  • When providing commands to users:
    • Windows/PowerShell: use ` for line continuation
    • Unix/Linux/macOS: use \ for line continuation

Commit Messages

  • Follow the 50/72 rule:

    • Subject line: max 50 characters
    • Body lines: wrapped at 72 characters
  • Use conventional commit prefixes (feat:, fix:, docs:, chore:, ci:, etc.)

  • Separate subject from body with a blank line

  • Keep messages concise: no one wants to read a novel in the log

  • Always include a Co-Authored-By: trailer listing every agent or model that contributed to the commit. Use one line per co-author:

    Co-Authored-By: porter (anthropic/claude): scaffolded build system
    Co-Authored-By: luna (openai/gpt-5.6-luna): reviewed edge cases
    

Example:

feat: add C ABI bridge for the Swift app

Expose xone_version() and xone_dongle_present() through a pure C header
so the Swift app can query the protocol stack.

Versioning

This project follows Semantic Versioning. The version is set in the top-level CMakeLists.txt (project(xone_macos VERSION ...)).

  • Patch (x.y.Z): bump on every commit that changes code. No commit is too small.
  • Minor (x.Y.z): bump when adding a feature or significant new capability.
  • Major (X.y.z): bump on breaking API changes.

Documentation (Markdown)

  • Wrap normal text and lists at max 80 columns (for readability in terminals and editors).
  • Exceptions: Tables and code blocks (```) can exceed 80 columns when formatting requires it (e.g. trees, alignment).
  • Use standard Markdown: **bold**, `inline code`, ## headings, - or numbered lists, fenced code blocks with language hints (```cpp, ```sh).
  • Keep examples concise, up-to-date, and self-documenting.
  • This file (AGENTS.md) follows its own rules.
  • Do not use em dashes (). Use a colon or rewrite the sentence.

Source Layout

xone_macos/
  CMakeLists.txt      # Build configuration
  src/                # Protocol stack + app layer
    usb/              #   USB transport (IOKit / IOUSBFamily)
    mt76/             #   MT76 chip protocol (port of transport/mt76.c)
    gip/              #   GIP protocol (port of bus/protocol.c)
    auth/             #   Auth + crypto (port of auth/)
    hid/              #   Virtual HID gamepad presentation
    app/              #   Swift entry point + C ABI bridge
  include/            # Headers (common, usb, mt76, gip, auth, hid, app)
  tests/              # Unity test suites
  deps/               # Custom Find*.cmake scripts (FetchContent)
  firmware/           # Downloaded firmware binaries (gitignored)

Upstream Reference

Protocol logic is ported from the Linux kernel driver medusalix/xone. See the "Source Files to Port" table in PLAN.md for the module-by-module mapping and the "Quick Reference" table in README.md for the Linux-to-macOS API replacements. Kernel idioms (kzalloc, spin locks, URBs, uinput) must be replaced with their user-space / IOKit equivalents when porting.

Behavioral Guidelines

Reduce common LLM coding mistakes. These guidelines bias toward caution over speed. For trivial tasks, use judgment.

1. Think Before Coding

Don't assume. Don't hide confusion. Surface tradeoffs.

Before implementing:

  • State your assumptions explicitly. If uncertain, ask.
  • If multiple interpretations exist, present them, don't pick silently.
  • If a simpler approach exists, say so. Push back when warranted.
  • If something is unclear, stop. Name what's confusing. Ask.

2. Simplicity First

Minimum code that solves the problem. Nothing speculative.

  • No features beyond what was asked.
  • No abstractions for single-use code.
  • No "flexibility" or "configurability" that wasn't requested.
  • No error handling for impossible scenarios.
  • If you write 200 lines and it could be 50, rewrite it.

Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.

3. Surgical Changes

Touch only what you must. Clean up only your own mess.

When editing existing code:

  • Don't "improve" adjacent code, comments, or formatting.
  • Don't refactor things that aren't broken.
  • Match existing style, even if you'd do it differently.
  • If you notice unrelated dead code, mention it, don't delete it.

When your changes create orphans:

  • Remove imports/variables/functions that YOUR changes made unused.
  • Don't remove pre-existing dead code unless asked.

Every changed line should trace directly to the user's request.

4. Goal-Driven Execution

Define success criteria. Loop until verified.

Transform tasks into verifiable goals:

  • "Add validation" means: write tests for invalid inputs, then make them pass.
  • "Fix the bug" means: write a test that reproduces it, then make it pass.
  • "Refactor X" means: ensure tests pass before and after.

For multi-step tasks, state a brief plan:

1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]

Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.

Platform Support

The project targets macOS only (Intel and Apple Silicon). Platform and compiler detection lives in deps/Platform.cmake and deps/Flags.cmake. Swift is compiled by CMake, which requires the Ninja or Xcode generator.