Contributing to Axon
July 31, 2026 · View on GitHub
Last Modified: 2026-07-07
This is the entry point for local development conventions: build setup, the
monolith policy, and security guardrails. For running tests see
testing.md; for cutting a release see
release-checklist.md; for adding a new extension
point (source adapter, parser, provider, vector store, REST route, MCP
action) see the adding-*.md guides in this directory.
Build setup
This repo follows the build conventions of the rmcp server family. The canonical upstream reference is rmcp-template/docs/contributing/rust.md.
System prerequisites
- Rust stable ≥ 1.86 (
rustup update stable) clangandmoldfor fast Linux builds:apt install clang moldmingw-w64for Windows cross-compilation:apt install mingw-w64justcommand runner (optional):cargo install just
Global Cargo config
Build performance depends on ~/.cargo/config.toml on the developer's
machine. See
rmcp-template/docs/contributing/rust.md
for the expected config (mold linker, dev profile tuning). Compile caching is
provided by the mise-managed kache, configured as the global
rustc-wrapper. Use KACHE_DISABLED=1 or RUSTC_WRAPPER="" to bypass it for
diagnostics.
Local .cargo/config.toml
This repo's .cargo/config.toml contains the xtask alias and the Windows
cross-compile linker:
[alias]
xtask = "run --package xtask --"
[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"
The Windows linker entry is a per-repo setting because CI environments may
not have the standard global ~/.cargo/config.toml. All other settings
(profile tuning, mold linker for Linux) are inherited from the global config.
Windows cross-compilation
axon publishes Windows binaries via the release CI workflow. To cross-compile locally:
rustup target add x86_64-pc-windows-gnu
cargo build --target x86_64-pc-windows-gnu --release
Monolith policy
This repository enforces a ratcheting policy to prevent new monolithic files and functions from being introduced.
Scope:
- Enforced on changed code, not the full codebase.
- Enforced locally via
lefthookpre-commit. - Enforced in CI for pull requests and pushes.
Limits:
- File size limit:
500lines - Rust function size limit: warn at
80lines, hard fail at120lines
Checked file types: file-size enforcement applies only to changed Rust
source files (.rs); function-size enforcement applies to changed Rust
functions in .rs files.
Test exemptions (the following paths/patterns are exempt):
tests/****/tests/****/*_test.***/*.test.***/*.spec.*benches/**config/****/config/****/config.rs
Exceptions: temporary file-level exceptions can be added to
.monolith-allowlist (one repo-relative path per line). Use exceptions only
when necessary, add a comment with ticket/date/owner above the entry, and
remove entries as soon as refactoring is complete.
Local enforcement:
./scripts/install-git-hooks.sh # install hooks once
python3 ~/.claude/hooks/enforce_monoliths.py --staged # run manually against staged changes
CI enforcement:
python3 ~/.claude/hooks/enforce_monoliths.py --base "$BASE_SHA" --head "$HEAD_SHA"
This keeps enforcement ratcheted to the change set under review.
Config files: policy logic lives in ~/.claude/hooks/enforce_monoliths.py,
local hooks in lefthook.yml, the hook installer in
scripts/install-git-hooks.sh, the CI job in .github/workflows/ci.yml, and
the exception list in .monolith-allowlist.
Security guardrails
Safety and security patterns enforced across the Axon stack.
Credential management
- All credentials live in
~/.axon/.envwithchmod 600permissions. - Never commit real
.envfiles. - Use
.env.exampleas a tracked template with placeholder values only. - Direct Docker Compose commands should pass
--env-file ~/.axon/.envso the canonical env file is used for${VAR}interpolation; service containers also read${AXON_HOME:-${HOME}/.axon}/.env.
.gitignore and .dockerignore must include:
.env
*.secret
*.pem
*.key
Lefthook hooks verify security invariants:
| Hook | Purpose |
|---|---|
cargo xtask check-env-staged | Blocks commits that include .env files |
cargo xtask check-mcp-http | Verifies MCP transport configuration parity |
Web panel token model
The current web panel uses the file-backed panel password generated by
axon serve, plus the MCP HTTP auth boundary for MCP and first-party action
routes.
| Token | Scope | Browser-visible |
|---|---|---|
~/.axon/panel-password | Gates /api/panel/config, /api/panel/ops, and setup routes | Returned only after /api/panel/login succeeds |
AXON_MCP_HTTP_TOKEN | Static bearer for /mcp and protected /v1 routes | Client-configured secret |
OAuth JWT (AXON_MCP_AUTH_MODE=oauth) | OAuth bearer for /mcp and protected /v1 routes | Client obtains through OAuth flow |
Rules:
~/.axon/panel-passwordmust stay mode0600.- Non-loopback HTTP binds require bearer or OAuth auth.
- Do not expose Chrome, Qdrant, or TEI directly to a network.
- Mobile clients must require an explicit panel-token unlock for
/api/panel/*. Do not fall back toAXON_MCP_HTTP_TOKENor OAuth tokens for panel config routes on the client. - Mobile settings UIs must not write a masked placeholder back to disk as a secret value. Preserve the raw server text privately and patch only genuinely changed secret fields.
MCP OAuth is an HTTP auth mode for MCP and first-party action clients. It does not replace the file-backed panel password used by setup/config panel routes.
Docker security
Non-root execution. The axon container runs the unified server as
UID/GID 1000:1000 via Compose and the runtime image USER directive:
user: "1000:1000"
No baked environment. Docker images must not contain credentials at build
time: no ENV AXON_PG_URL=... in Dockerfiles, no COPY .env in Dockerfiles.
Credentials are injected at runtime via env_file: or container
environment:.
Image verification:
# Check for baked secrets
docker inspect axon:local | jq '.[0].Config.Env'
# Check container revision matches git SHA
docker compose --env-file ~/.axon/.env -f docker-compose.prod.yaml ps
Network security
- All service URLs should use
https://in production. - HTTP is acceptable for local development and Docker-internal networking.
- The Chrome CDP endpoint is HTTP-only by design (internal network).
- Android allows cleartext only for the configured private Tailscale domains
in
apps/android/app/src/main/res/xml/network_security_config.xml; any other persisted Android server URL should behttps://.
validate_url() (SSRF guard) enforces: no private/loopback IPs, no file://
or other non-HTTP schemes, and connect-time DNS-rebinding is closed by
SsrfBlockingResolver (re-checks every resolved IP).
The Spider
firewallfeature (which would block known malware/phishing domains) is not enabled —spider_firewall's build.rs fails under CI rate-limiting.validate_url()is the primary SSRF guard. Seedocs/reference/spider-feature-flags.md.
Input handling
- Default crawl
--max-pagesis bounded at 2000; use path budgets or explicit--max-pages 0only for intentional deep crawls. AXON_MAX_PENDING_CRAWL_JOBScaps the queue to prevent runaway crawls.- Auto path-prefix scoping limits crawl scope on deep URLs.
--respect-robotsdefaults tofalse— legal implications acknowledged.chunk_text()splits at 2000 chars with 200-char overlap. Very long pages produce many Qdrant points — monitor collection size after large crawls.
Logging
- Never log credentials, tokens, or API keys.
- CLI outputs JSON data to stdout and progress/logs to stderr.
- Log rotation: 10 MB max, 3 backups (
AXON_LOG_MAX_BYTES,AXON_LOG_MAX_FILES). - Keep terminal/progress logs on stderr and machine-readable command data on stdout.