Welcome — and thank you for considering a contribution. InnerWarden is a Linux/macOS security agent built in Rust; the project is open to detectors, integrations, dashboard polish, documentation, and test coverage. This guide gets you from "I want to help" to "my PR is merged" without surprises.
If you have a question that isn't answered below, open a Discussion or comment on an existing issue.
# 1. Fork + clone
gh repo fork InnerWarden/innerwarden --clone --remote
cd innerwarden
# 2. Toolchain (rustup picks the pinned version from rust-toolchain.toml if present)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup component add rustfmt clippy
# 3. Build + test
make test # all unit + integration tests
make build # debug binaries for sensor / agent / ctl
# 4. Try the dashboard locally
cargo run -p innerwarden-agent -- --data-dir ./data --dashboard
# open http://127.0.0.1:7378 (default admin password: innerwarden)If make test passes on a fresh clone, your environment is good to go.
We label issues so you can find work that matches your time and experience:
good first issue— well-scoped, no architectural decisions required, mentor-friendly. Most are test-coverage tasks (one file, ~50–500 lines, follow an existing pattern). Start here.help wanted— larger work, may need design discussion in the issue first.test— coverage / regression-test work. Often overlaps withgood first issue.documentation— wiki pages, README sections, integration recipes.enhancement— new features. Open a discussion or comment on the issue before writing code so we can avoid wasted effort.
If you find an issue you want to work on, leave a comment so we can avoid two people building the same thing.
In rough order of how often we merge them:
- Test coverage — every PR that raises a file from <80% to ≥80% closes a labelled issue. Patterns to follow are already in
crates/*/src/**/tests.rs. The[help wanted, good first issue, test]triple-label issues are pre-scoped for you. - New detectors —
crates/sensor/src/detectors/accepts new detection rules. Read Module Authoring for the full template. - Integration recipes —
integrations/*.tomlplus a recipe doc. See existing examples forslack,telegram,pagerduty. - Dashboard polish — UX improvements, accessibility fixes, lucide icon standardization. Frontend lives in
crates/agent/src/dashboard/frontend/(vanilla JS + CSS, no framework). - Documentation — wiki pages, README clarifications, code-level rustdoc.
- Bug fixes — small fixes welcome; for non-trivial bugs include a regression test.
InnerWarden is a defensive security tool. Please optimise for:
- Deterministic sensor behaviour — no HTTP, no LLM, no AI in the sensor crate. Detectors fail-open on errors and never crash the process.
- Conservative defaults —
dry_run = true, observe-only, audit-everything. Auto-execution is opt-in. - Bounded, reversible, audited responses — every skill has a TTL, a revert path, and a hash-chained decision log entry.
- Explicit documentation for behavioural changes — anything user-visible gets a note in
CHANGELOG.mdplus a wiki page update if applicable.
Our pipeline rejects PRs that fail any of these gates, so run them locally first:
make test # all unit + integration tests
cargo fmt --check # rustfmt with default settings
cargo clippy --tests -- -D warnings # no new warnings allowedFor dashboard frontend changes there is no JS test runner, but every visible behaviour gets a Rust anchor test that does substring-grep on the bundled HTML/CSS/JS via include_str!. See crates/agent/src/dashboard/mod.rs test module for the pattern. A bundle-anchor regression test is required for any dashboard contract you don't want a future refactor to silently break.
For detectors and response skills there are scenario-replay tests in testdata/scenarios/. New detectors should land with a fixture that exercises both the positive (true positive) and negative (regression / false positive) paths.
Most things are enforced by rustfmt and clippy; the conventions below are project-specific:
- Commits in English, Conventional Commits format:
feat(area): description,fix(area): description,test(area): description,docs: description. Area is a crate or subsystem (agent,sensor,ctl,dashboard, etc.). - Branches: short slug, e.g.
feat/splunk-hec-sink,test/ctl-mesh-coverage,fix/dashboard-blocked-count. - I/O errors in sinks: log with
warn!, do not propagate with?. Sinks are best-effort. spawn_blockingfor any synchronous file I/O inside Tokio tasks.- Comments: only when the why is non-obvious. Don't restate what the code does.
- No emoji in source files — the dashboard uses inline lucide SVGs from
crates/agent/src/dashboard/frontend/js/icons.js. Add a new icon to that module and reuse it.
Detailed rules live in the wiki: Sensor Capabilities, Agent Capabilities, Module Authoring.
Before opening a PR, confirm:
- Branch is rebased on the latest
main. -
make testpasses locally. -
cargo fmt --checkreports no diffs. -
cargo clippy --tests -- -D warningshas no new warnings. - If you touched user-visible behaviour, you added a regression test that would fail without the change.
- If you touched the dashboard frontend, you added a bundle-anchor test in
dashboard/mod.rs. - If your change affects detection or response capabilities, configuration, or operational safety guidance, the corresponding doc/wiki page is updated.
- PR description references the issue (
Closes #123) so it auto-closes on merge. - PR title uses Conventional Commits format.
If a change affects any of the following, update docs in the same PR:
- detection or response capabilities
- generated artifacts (events, incidents, decisions schemas)
- configuration (
agent.toml,sensor.toml) - deployment / update flow
- operational safety guidance
In practice that often means updating README.md, CHANGELOG.md, CLAUDE.md, or a wiki page.
- A maintainer will respond within 2–3 business days. If your PR has been open longer with no review, ping it; it has probably scrolled off the top of the queue.
- Most PRs go through 1–2 review rounds. We optimise for "small, focused, anchored" — large PRs that mix concerns get split.
- CI must be green before merge. If a check is flaky (it happens), a maintainer will rerun it; you don't need to push noop commits.
Good contributions:
- new detectors or detector improvements
- new response skills (bounded, reversible, audited)
- operational safety improvements
- test coverage and replay coverage
- documentation and setup guides
- module authoring
- dashboard UX / accessibility fixes
Changes that need extra care — open an issue first:
- auto-execution defaults
- new privileged response skills
- privacy-sensitive data collection
- schema-breaking output changes
- architectural rewrites (storage layer, event pipeline, AI router)
- new top-level CLI commands
If you are unsure whether a change fits the project's current direction, open an issue or draft PR first.
Do not open a public issue for a vulnerability. Email disclosures to the address listed in SECURITY.md (or, if absent, to the maintainer email on the repo profile) with details and reproduction steps. We aim to respond within 48 hours.
By contributing, you agree that your contributions will be licensed under the Apache License 2.0, the same as the rest of the project. Some satellite crates (smm, hypervisor, killchain, dna) are BUSL-1.1 or proprietary — those are not in this repo.
- Lead: @esteves-uk
- Discussions: https://github.com/InnerWarden/innerwarden/discussions
- Issues: https://github.com/InnerWarden/innerwarden/issues
Thank you for helping make Linux & macOS security infrastructure more accessible.