Contributing

Thank you for considering contributing to Irrlicht. Every contribution matters.

Welcome

Irrlicht is open source under the MIT license. Contributions of all kinds are welcome: bug reports, feature requests, documentation improvements, code contributions, and community support.

Whether this is your first open-source contribution or your thousandth, we appreciate you taking the time to make Irrlicht better.

Ways to Contribute

  • Report bugs via GitHub Issues -- help us find and fix problems
  • Suggest features via GitHub Discussions -- share your ideas for improvement
  • Improve documentation -- fix typos, clarify explanations, add examples
  • Submit pull requests -- fix bugs, add features, refactor code
  • Help others in Discussions -- answer questions, share your experience
First-time contributors Look for issues labeled good first issue -- these are specifically chosen to be approachable for newcomers to the codebase.

Development Setup

Prerequisites

  • macOS 13 (Ventura) or later
  • Go 1.21+
  • Swift 5.9+
  • Xcode Command Line Tools
  • git

Getting Started

  1. Fork the repository on GitHub
    Click the "Fork" button on the Irrlicht repository page to create your own copy.
  2. Clone your fork
    git clone https://github.com/YOUR_USERNAME/Irrlicht.git
  3. Enter the project directory
    cd Irrlicht
  4. Build everything
    ./tools/build-release.sh

    This compiles the Go daemon (universal binary) and the Swift macOS app.

  5. Run the test suite
    go test ./core/... -race -count=1
    ./tools/replay-fixtures.sh

    All tests must pass before you start making changes. If they don't, you've found a bug -- please report it.

Project Structure

Irrlicht is a two-process architecture: a Go daemon that monitors agent sessions, and a Swift macOS app that renders the menu bar UI.

Irrlicht/
  core/             # Go daemon -- session detection, state machine, IPC
  platforms/        # Swift macOS app + web dashboard
  site/             # Landing page + docs (GitHub Pages)
  tools/            # Build, release, and replay-fixture scripts

For a full breakdown of how the pieces fit together, see System Design.

Development Workflow

Branching

Create a feature branch from main:

git checkout -b feature/my-feature

Use descriptive branch names with a prefix that reflects the type of change:

  • feature/ -- new functionality
  • fix/ -- bug fix
  • docs/ -- documentation changes

Making Changes

  • Keep changes focused -- one feature or fix per PR
  • Follow existing code style and conventions
  • Add tests for new functionality
  • Update documentation if behavior changes

Testing

Before marking a change done, run all three layers and confirm they pass:

# Unit + e2e tests (race detector on, no cache)
go test ./core/... -race -count=1

# Replay-fixture suite (drives real agent transcripts through adapters)
./tools/replay-fixtures.sh
Important A change is only done when both commands exit 0. No exceptions.

To run tests for individual components during development:

# Single Go package
go test ./core/adapters/inbound/agents/claudecode/... -race -v

# Swift tests
cd platforms/macos && swift test

Commit Messages

Use conventional commits:

feat: add WebSocket reconnection with backoff
fix: correct state transition on ESC cancellation
docs: clarify adapter configuration options
refactor: extract session parser into standalone module
test: add table-driven tests for state machine
  • Keep the first line under 72 characters
  • Explain why, not just what
  • Reference related issues when applicable: Fixes #42

Pull Requests

  1. Ensure all tests pass
    go test ./core/... -race -count=1
    ./tools/replay-fixtures.sh
  2. Push your branch
    git push origin feature/my-feature
  3. Open a PR against main
    Go to the repository on GitHub and open a new pull request.
  4. Fill in the PR template
    Include:
    • Summary of changes
    • Test plan
    • Screenshots (for UI changes)
  5. Request review
    Tag a maintainer and address feedback promptly.

Code Guidelines

Go (Daemon)

  • Follow standard Go conventions (gofmt, go vet)
  • Use interfaces for external dependencies (ports-and-adapters pattern)
  • Prefer table-driven tests
  • Handle errors explicitly -- no panic in library code
  • Keep functions focused and testable

Swift (macOS App)

  • Follow Swift API Design Guidelines
  • Use SwiftUI idioms (@State, @Binding, @EnvironmentObject)
  • Keep views small and composable
  • Test with SwiftUI previews where possible

General

  • No unnecessary abstractions -- three similar lines beat a premature abstraction
  • Delete unused code -- don't comment it out
  • Only add comments where the logic isn't self-evident
  • Prefer editing existing files over creating new ones

Adding a New Agent Adapter

Agent adapters are the most concrete extension path Irrlicht offers. The repo ships a guided onboarding flow so a new adapter can be built, fixtured, and promoted without re-deriving conventions from the source.

Start with the onboarding factory

Run the /ir:onboarding-factory skill (under .claude/skills/ir:onboarding-factory/). It is a zero-bash dispatcher over four verbs -- create-scenario, create-agent, assess, and record -- each of which drives the of factory CLI (tools/onboarding-factory). The factory is the sole writer of everything under replaydata/; record drives the agent's CLI through the cell's recipe, captures lifecycle events, and verifies the recording against its spec.

The verbs cover the whole flow -- create-agent (first-time onboarding of a new agent column), assess (judge a cell + author its recipe and spec), and record (capture + verify, including re-recording against a newer CLI).

Judge support, don't declare it

Scenarios are agent-agnostic: one five-field row (id, name, description, acceptance_criteria, process) in replaydata/agents/scenarios.json, with no per-adapter data and no requires gate. Whether a scenario applies to your adapter -- and whether the daemon can observe it and the driver can drive it -- is judged per cell by the assess verb across three pillars (agent capability / daemon sensor capture / driver capability), each anchored to cited evidence.

This means: never write per-adapter scenarios. Add the agent-agnostic row once via of scenario add, then assess and record each adapter against it.

Aim for a maturity stage

The promotion criteria for alpha / beta / stable are documented on the Adapters reference. Read them before opening the PR -- the bar your adapter clears determines the stage label that ships with it.

Adapter PR checklist (alpha bar)

Tick every box below before opening the PR. This is the alpha stage rubric, copied verbatim so it can serve as a PR template.

  • Adapter package at core/adapters/inbound/agents/<name>/
  • Exports an agent.Agent from Agent() with the right Source variant (FilesUnderRoot / FilesUnderCWD / ProcessOwnedStore)
  • Registered in the allAgents slice in core/cmd/irrlichd/main.go
  • Emits all three lifecycle states (working, waiting, ready)
  • replaydata/agents/<name>/capabilities.json populated against replaydata/agents/features.json
  • baseline-hello and full-lifecycle-toolcall fixtures committed under replaydata/agents/<name>/scenarios/
  • tools/replay-fixtures.sh green
  • go test ./core/... -race -count=1 green
  • README compatibility grid updated to alpha

Promotion to beta and stable happens later, against the additional checklists in the Maturity stages section -- promotion is not part of the initial PR.

Reporting Bugs

Bug reports for Irrlicht (the daemon, the macOS app, or any adapter) live on GitHub Issues and must carry the bug label so they count against the maturity-stage criteria.

Before Filing

  • Check existing issues for duplicates
  • Try the latest version
  • Check logs: ~/Library/Application Support/Irrlicht/logs/

Bug Report Should Include

  • macOS version
  • Irrlicht version (irrlichd --version)
  • Steps to reproduce
  • Expected vs actual behavior
  • Relevant log output
Logs location Irrlicht stores daemon logs at ~/Library/Application Support/Irrlicht/logs/. Including relevant excerpts in your bug report helps us diagnose the issue much faster.

Feature Requests

  • Open a Discussion first to gauge interest before writing code
  • Describe the problem you're solving, not just the solution
  • Consider how it fits the project philosophy: zero-config, deterministic, honest signals

AI Agent Contributors

Irrlicht is designed to be agent-verifiable. If you're an AI coding agent contributing to this project:

  • Run go test ./core/... -race -count=1 and ./tools/replay-fixtures.sh after every change
  • A task is only complete when both exit 0
  • Never mark a task done based only on compilation
  • If a test fails, inspect it and fix the root cause
  • Do not skip or comment out failing assertions
Non-negotiable Both the Go test suite and the replay-fixture suite must exit 0. If either fails, the work is not done -- regardless of whether the code compiles or individual tests pass in isolation.

Code Review

  • All PRs require at least one review
  • Be kind and constructive
  • Explain the why behind requested changes
  • Small PRs are reviewed faster

License

By contributing, you agree that your contributions will be licensed under the MIT License.

Recognition

All contributors are recognized in the project. Thank you for helping make Irrlicht better.