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
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
-
Fork the repository on GitHub
Click the "Fork" button on the Irrlicht repository page to create your own copy. -
Clone your fork
git clone https://github.com/YOUR_USERNAME/Irrlicht.git -
Enter the project directory
cd Irrlicht -
Build everything
./tools/build-release.shThis compiles the Go daemon (universal binary) and the Swift macOS app.
-
Run the test suite
go test ./core/... -race -count=1 ./tools/replay-fixtures.shAll 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 functionalityfix/-- bug fixdocs/-- 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
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
-
Ensure all tests pass
go test ./core/... -race -count=1 ./tools/replay-fixtures.sh -
Push your branch
git push origin feature/my-feature -
Open a PR against
main
Go to the repository on GitHub and open a new pull request. -
Fill in the PR template
Include:- Summary of changes
- Test plan
- Screenshots (for UI changes)
-
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
panicin 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.AgentfromAgent()with the rightSourcevariant (FilesUnderRoot/FilesUnderCWD/ProcessOwnedStore) - Registered in the
allAgentsslice incore/cmd/irrlichd/main.go - Emits all three lifecycle states (
working,waiting,ready) replaydata/agents/<name>/capabilities.jsonpopulated againstreplaydata/agents/features.jsonbaseline-helloandfull-lifecycle-toolcallfixtures committed underreplaydata/agents/<name>/scenarios/tools/replay-fixtures.shgreengo test ./core/... -race -count=1green- 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
~/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=1and./tools/replay-fixtures.shafter 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
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.