# Axon Self-hosted RAG engine in Rust: crawl, scrape, ingest, embed, and query any source, with hybrid retrieval and cited LLM synthesis over MCP, CLI, and REST. Version: 7.5.1 Every source — a web page, a site, a local checkout, a Git repo, a package, a Reddit subreddit, a YouTube transcript, or an AI session export — enters through one unified pipeline backed by SQLite, Qdrant, Hugging Face TEI, and Chrome/CDP. Axon runs as a **native binary under systemd**: an Incus system container is the preferred deployment, bare-metal systemd is a supported alternative. The infrastructure it depends on (Qdrant, TEI, Chrome) typically runs as containers or on external hosts; Axon reaches them by URL. ## The unified source pipeline All source acquisition, refresh, watch, indexing, graph extraction, embedding, publishing, and cleanup flow through one pipeline. CLI, MCP, and REST are thin transport projections over the same `SourceRequest` DTO. ```text SourceRequest → resolve and route (`axon-route`) → acquire (`axon-adapters`) → ledger generation + manifest (`axon-ledger`) → normalize / parse / prepare (`axon-document`, `axon-parse`, `axon-extract`) → embed (`axon-embedding`) → publish / query (`axon-vectors`, `axon-retrieval`) → graph + cleanup debt (`axon-graph`, `axon-prune`) ``` One durable `job_id` crosses every stage — logs, events, ledger rows, graph updates, artifacts, vector payloads, and status all share it. There is no per-source-family pipeline and no per-family job store. The design contract packet that produced this runtime lives in [`docs/pipeline-unification/`](docs/pipeline-unification/README.md); treat it as the historical design record, not as future work — the clean break is implemented. ## Deployment contract **Supported ways to run the axon binary:** - **Incus system container (preferred).** `deploy/incus/bootstrap.sh` brings up one Incus system container that runs axon native under a systemd unit (`axon-native.service`) and Qdrant/TEI/Chrome as nested containers, with GPU passthrough. See [`deploy/incus/README.md`](deploy/incus/README.md) for the profile, storage, and GPU details. - **Bare-metal systemd (supported).** Install the binary, drop in [`deploy/systemd/axon.service`](deploy/systemd/axon.service), enable it. See [`deploy/systemd/README.md`](deploy/systemd/README.md) for the walkthrough. Both paths run `/usr/local/bin/axon serve`, which hosts the HTTP API (`/v1/*`), MCP-over-HTTP (`/mcp`), the web control panel, and the in-process worker runtime in one process on `127.0.0.1:8001` by default. **Not supported as an axon deployment path:** running the axon binary itself in a Docker container as the production deployment. (Container images are still published to GHCR for users who want them, and `docker-compose.prod.yaml` remains the canonical reference for infra image versions and ports — but the supported production deployments are the two above.) **Not supported at all:** Postgres, Redis, RabbitMQ, AMQP, external worker services, Neo4j graph retrieval, or multiple competing `.env`/`config.toml` locations. Jobs are stored in SQLite and workers run in the same Tokio runtime as `axon serve`. **Target hardware:** local NVIDIA RTX 4070 with NVIDIA Container Toolkit (for TEI GPU throughput). Axon itself is CPU-only. ## Install the binary The first-class guided path is `npx skills add dinglebear-ai/axon --skill install-axon` followed by `$install-axon`. It respects the release trust boundary below, drives `axon setup`, and guides deployment/auth/client verification. The installers fetch a release binary and delegate the rest to `axon setup`. Deployment (Incus or systemd) is a separate step above. ### Linux Prerequisites: Linux x86_64, `curl`, `sha256sum`, `minisign`, `install`, and (for GPU synthesis or a configured OpenAI-compatible endpoint) the relevant credentials. Release installation is fail-closed and is not yet available to the public: releases through `v7.2.23` do not include signatures, and no public release signing key has been provisioned. Build from reviewed source until a future release publishes the key fingerprint in `SECURITY.md` and the key itself at `security/axon-release.minisign.pub`. Do not substitute a key downloaded beside the release artifacts. After those two trust-anchor files exist, the authenticated flow will be: ```bash curl -fLO https://github.com/dinglebear-ai/axon/releases/download/vX.Y.Z/install.sh curl -fLO https://github.com/dinglebear-ai/axon/releases/download/vX.Y.Z/install.sh.sha256 curl -fLO https://github.com/dinglebear-ai/axon/releases/download/vX.Y.Z/install.sh.minisig sha256sum --check install.sh.sha256 export AXON_UPDATE_MINISIGN_PUBKEY='' minisign -V -P "$AXON_UPDATE_MINISIGN_PUBKEY" -m install.sh -x install.sh.minisig AXON_VERSION=vX.Y.Z ./install.sh ``` The installer requires `AXON_UPDATE_MINISIGN_PUBKEY`, verifies the release's detached minisign signature and checksum, and installs `axon` to `~/.local/bin/axon`. Fetch a version-pinned installer from the reviewed release source instead of piping the mutable `main` branch directly to a shell. ```bash AXON_UPDATE_MINISIGN_PUBKEY='' AXON_INSTALL_DRY_RUN=1 ./install.sh AXON_UPDATE_MINISIGN_PUBKEY='' AXON_INSTALL_PREFIX=/opt/axon ./install.sh AXON_UPDATE_MINISIGN_PUBKEY='' AXON_VERSION=vX.Y.Z ./install.sh AXON_UPDATE_MINISIGN_PUBKEY='' AXON_INSTALL_SKIP_SETUP=1 ./install.sh AXON_INSTALL_METHOD=build ./install.sh # local cargo build; no release download ``` ### Windows Prerequisites: Windows x86_64, PowerShell 5.1+ or PowerShell Core, `minisign`, and the provisioned key described above. Until that key is published, build from reviewed source instead of using the release installer. Download the installer and integrity metadata from the versioned release, validate the checksum, inspect it locally, and then execute that pinned file: ```powershell Invoke-WebRequest 'https://github.com/dinglebear-ai/axon/releases/download/vX.Y.Z/install.ps1' -OutFile install.ps1 Invoke-WebRequest 'https://github.com/dinglebear-ai/axon/releases/download/vX.Y.Z/install.ps1.sha256' -OutFile install.ps1.sha256 Invoke-WebRequest 'https://github.com/dinglebear-ai/axon/releases/download/vX.Y.Z/install.ps1.minisig' -OutFile install.ps1.minisig if ((Get-FileHash .\install.ps1 -Algorithm SHA256).Hash.ToLowerInvariant() -ne ((Get-Content .\install.ps1.sha256).Split()[0]).ToLowerInvariant()) { throw 'installer checksum mismatch' } $TrustedPublicKeyFile = Get-Content .\axon-release.minisign.pub -Raw $TrustedPublicKey = ($TrustedPublicKeyFile -split "`r?`n" | Where-Object { $_ -and -not $_.StartsWith('untrusted comment:') } | Select-Object -First 1).Trim() minisign -V -P $TrustedPublicKey -m install.ps1 -x install.ps1.minisig Get-Content .\install.ps1 $env:AXON_UPDATE_MINISIGN_PUBKEY = $TrustedPublicKeyFile .\install.ps1 ``` Installs `axon.exe` to `%USERPROFILE%\.local\bin` and adds it to the user PATH. Controls: `AXON_INSTALL_DRY_RUN`, `AXON_INSTALL_PREFIX`, `AXON_VERSION`, `AXON_INSTALL_SKIP_SETUP`. ### Claude Code plugin ```bash claude plugin install ``` The plugin ships no binary and registers no automatic hooks. Install `axon` first, then invoke `axon setup plugin-hook` explicitly for a probe-only `/readyz` check. Provisioning uses `axon setup` or `axon compose up` on the host. ## Deploy ### Incus (preferred) `deploy/incus/bootstrap.sh` is an idempotent 19-step bootstrap that: launches an `images:debian/bookworm` system container under `axon-container-profile`, applies GPU passthrough, builds axon from the repo's Dockerfile `runtime` stage, installs `axon-native.service`, brings up Qdrant/TEI/Chrome as nested containers, and optionally exposes axon's port to the host via an Incus `proxy` device. A host `axon-incus-bootstrap.service` unit re-runs it on host boot. ```bash incus profile create axon-container-profile incus profile edit axon-container-profile < deploy/incus/profile.yaml AXON_EXTERNAL_QDRANT_URL=http://qdrant-host:53333 \ AXON_ENV_FILE=/home/you/.axon/.env \ ./deploy/incus/bootstrap.sh ``` See [`deploy/incus/README.md`](deploy/incus/README.md) for the split-model rationale (axon native, infra nested), storage fork (`~/.axon-incus`), and the `nvidia-procfs` fragility note. ### Bare-metal systemd ```bash useradd --system --home /var/lib/axon --shell /usr/sbin/nologin axon install -d -o axon -g axon /var/lib/axon install -m 0755 axon /usr/local/bin/axon install -d /etc/axon && install -m 0600 your.env /etc/axon/axon.env install -m 0644 deploy/systemd/axon.service /etc/systemd/system/axon.service systemctl daemon-reload && systemctl enable --now axon ``` See [`deploy/systemd/README.md`](deploy/systemd/README.md) for the full walkthrough, hardening directives, and infra notes. ## Configuration home and setup `~/.axon/` is the canonical home for persistent data on bare-metal (under Incus it's `/mnt/axon-data`, mapped from `~/.axon-incus` on the host). It is flat — no nested `axon/` subdirectory: ```text ~/.axon/ ├── .env URLs, secrets, auth, runtime bootstrap ├── config.toml non-secret tuning (search, workers, chunking, providers) ├── jobs.db SQLite: unified jobs + source ledger + graph + memory ├── output/ prepared docs, vectors, manifests ├── logs/axon.log rotated logs ├── artifacts/ large/raw source outputs ├── screenshots/ captured pages └── chrome-diagnostics/ ``` `AXON_DATA_DIR` defaults to `~/.axon`. If you previously used `~/.local/share/axon`, axon does not auto-migrate — either `mv` it to `~/.axon` or set `AXON_DATA_DIR=~/.local/share/axon` to pin the old location. `axon setup init` creates `~/.axon`, `config.toml`, and `.env` idempotently, filling only missing runtime values and preserving secrets. Focused commands: ```bash axon setup init # create ~/.axon, config.toml, .env axon preflight # check prerequisites, auth, service readiness axon doctor # check Qdrant, TEI, LLM endpoint reachability axon smoke # TEI prewarm + source/ask proof axon setup plugin-hook # probe-only SessionStart path (never deploys) ``` ### Two-layer config | File | Purpose | |---|---| | `~/.axon/.env` | URLs, secrets, auth, runtime bootstrap values | | `~/.axon/config.toml` | non-secret tuning and behavior | Precedence: **CLI flags > env vars > `~/.axon/config.toml` > built-in defaults.** `.env` keeps endpoint URLs (`QDRANT_URL`, `TEI_URL`, `AXON_CHROME_REMOTE_URL`, `AXON_SEARXNG_URL`), secrets (`AXON_HTTP_TOKEN`, `TAVILY_API_KEY`, `GITHUB_TOKEN`, `GITLAB_TOKEN`, `GITEA_TOKEN`, Reddit credentials, `HF_TOKEN`, OAuth credentials), Docker/runtime bootstrap, and LLM runtime pointers. Optional ArtifactCandidate delivery uses the paired `AXON_ARTIFACT_CANDIDATE_DEPOT_URL` and `AXON_ARTIFACT_CANDIDATE_DEPOT_TOKEN` variables. Leave both absent to disable delivery; if either is present, both must be non-empty and valid or worker/server startup fails instead of falling back to a disabled sink. `config.toml` keeps search/ask tuning, worker and job limits, TEI client tuning, Qdrant batch sizing, chunking, and logging. See [`config.example.toml`](config.example.toml), [`.env.example`](.env.example), and [`docs/guides/configuration.md`](docs/guides/configuration.md) for the full surface. ## Quick start For the full first-run walkthrough see [`docs/guides/quickstart.md`](docs/guides/quickstart.md) and [`docs/guides/getting-started.md`](docs/guides/getting-started.md). After deploy + setup: ```bash axon doctor axon https://example.com --scope site --wait true axon query "provider cooling" --content-kind code axon ask "What did we index?" ``` CLI and `axon mcp` (stdio) run actions in-process against Qdrant and TEI. `axon serve` exposes the same operations over HTTP for deployed instances. ## Sources and scopes One command acquires any source; scope selects the acquisition strategy: ```bash axon https://example.com/page --scope page # one page (default) axon https://example.com/docs --scope site # crawl a site axon /home/you/project # local checkout axon github.com/owner/repo --scope repo # hosted git axon pypi.org/project/django # package registry axon reddit.com/r/rust --scope subreddit # Reddit ``` Adapter families: `web`, `local`, `github`, `gitlab`, `gitea`/`git`, `crates`, `npm`, `pypi`, `docker`, `reddit`, `youtube`, `feed`, `sessions`, `cli_tool`, `mcp_tool`. Each emits `SourceDocument` through the same pipeline. Per-source walkthroughs live under [`docs/guides/`](docs/guides/): [web](docs/guides/web-crawls.md), [local](docs/guides/local-sources.md), [GitHub repos](docs/guides/github-repos.md), [package registries](docs/guides/package-registries.md), [sessions](docs/guides/sessions.md), [CLI tool sources](docs/guides/cli-tool-sources.md), [MCP tool sources](docs/guides/mcp-tool-sources.md). - **`axon `** — canonical acquisition. `--scope page|site|docs|repo|package|subreddit`, `--refresh if_stale|force|never`, `--watch disabled|ensure|enabled`, `--no-embed`, `--wait true`. - **`axon scrape `** — retained one-page projection: `scope=page`, `embed=true`, `limits.max_pages=1`, clean content output, no site fanout. Same pipeline as `axon --scope page`. - **`axon map `** — discover URLs on a site without scraping (`embed=false`). - **`axon sessions `** — index Claude/Codex/Gemini session exports. Vertical extractors auto-route known URLs (GitHub, PyPI, npm, crates.io, Reddit, YouTube, …) to structured per-site extractors instead of generic HTML→markdown. Disable with `AXON_ENABLE_VERTICALS=false` or the `[crawl.verticals]` config section. ## Jobs, watches, and cleanup **One durable job model** in SQLite owns lifecycle, attempts, stages, events, heartbeats, artifacts, and provider reservations. Source jobs keep one job id across resolve, acquire, prepare, embed, publish, graph, and cleanup. Job kinds: `source`, `extract`, `watch`, `map`, `research`, `ask`, `query`, `retrieve`, `memory`, `graph`, `prune`, `provider_probe`, `reset`. ```bash axon --wait true # foreground: enqueue, run workers, block to terminal axon # detached: enqueue, return job id, exit axon jobs list # all jobs axon jobs get # status, stages, counts, errors axon jobs events # paged event log axon jobs stream # live event stream for consumers axon jobs cancel axon jobs retry axon jobs recover # reclaim stale running jobs (admin) axon jobs cleanup # remove old terminal jobs axon jobs worker # run a standalone worker process ``` **Detached work needs workers.** A source/extract/watch/retry call returns a job id when detached. A process must be running with workers for detached jobs to advance — that's `axon serve` (or `jobs worker`). Use `--wait true` for foreground completion. **Watches** persist a canonical source request and schedule. Each due tick leases the watch, enqueues one `source` job, and records the run. ```bash axon watch create --every 1d axon watch list / get / status / update axon watch exec # run one tick now axon watch pause / resume / delete axon watch history ``` **Cleanup is plan-first.** `axon-prune` owns it; cleanup debt in the source ledger records work that must be retried or reconciled. ```bash axon prune plan # dry-run reviewable plan axon prune exec --confirm # destructive execution axon reset plan # dry-run reset of local stores axon reset exec --confirm # destructive reset ``` `axon migrate --from --to ` is the one-time upgrade path that scrolls an unnamed-mode Qdrant collection and re-upserts it as named-mode (dense + BM42 sparse) for hybrid RRF search. ## Retrieval and analysis See [`docs/guides/ask-query-retrieve-search.md`](docs/guides/ask-query-retrieve-search.md) for how `ask`, `query`, `retrieve`, and `search` differ. | Command | Purpose | |---|---| | `axon query ` | Hybrid vector search (RRF over dense + BM42 sparse) | | `axon retrieve ` | Fetch a source's chunks/documents | | `axon ask ` | RAG: retrieve relevant context, then answer with LLM | | `axon chat ` | Direct LLM prompt (no retrieval) | | `axon summarize ...` | Summarize one or more sources | | `axon evaluate ` | RAG vs baseline with independent LLM judge | | `axon suggest [focus]` | Suggest sources to index next | | `axon train` | Collect human preference votes on RAG candidates | | `axon search ` | Web search (SearXNG/Tavily), auto-queues source jobs | | `axon research ` | Multi-source web research with LLM synthesis | | `axon extract ...` | LLM-powered structured extraction (+ lifecycle) | | `axon brand ` | Brand identity: colors, fonts, logos, favicon | | `axon diff ` | What changed between two URLs | | `axon endpoints ` | Discover API endpoints from HTML/JS bundles | | `axon screenshot ` | Full-page screenshot | New Qdrant collections are created with named `dense` + `bm42` sparse vectors and queried with Reciprocal Rank Fusion. Legacy unnamed collections fall back to dense-only cosine; run `axon migrate` to upgrade, then point `server.default-collection` at the new collection. Tune via `[search]` and `[retrieval]` in `config.toml`. ## Memory ```bash axon memory remember "..." # store a memory record axon memory list / search / show axon memory link # relate / supersede axon memory supersede axon memory context # recall relevant memories for a query ``` Memory lives in its own Qdrant collection (`axon_memory`, or `AXON_MEMORY_COLLECTION`) with a decay model: `base_score` blended from semantic/confidence/salience/scope/reinforcement, multiplied by a half-life decay unless pinned. Run `axon memory context` explicitly for session recall; the Claude plugin does not register a `SessionStart` hook. ## CLI The full command registry is **generated**, not hand-maintained, so it can't drift. Headline groups: ```bash axon # index a source (the canonical command) axon scrape / map / sessions axon query / ask / retrieve / search / research / summarize / evaluate axon jobs / watch / prune / reset axon memory / sources / domains / stats / status axon serve / mcp / doctor / preflight / smoke / config ``` For the authoritative, always-current full registry — 113 commands across 49 groups with summaries and async/mutates markers — see the generated [`docs/reference/cli/commands.md`](docs/reference/cli/commands.md) and the machine-readable [`docs/reference/cli/commands.json`](docs/reference/cli/commands.json). Regenerated by `cargo xtask schemas cli`; cross-checked against the live clap tree. Per-command flags: `axon --help`. ## MCP Axon supports three MCP tool projections controlled by `AXON_MCP_TOOL_PROJECTION=legacy|atomic|both`, or `--mcp-tool-projection` on `axon mcp` / `axon serve mcp`. The default, `legacy`, exposes the compatible `axon` aggregate with `action`/`subaction` routing. `atomic` exposes unprefixed canonical operations such as `query`, `jobs_get`, `jobs_cancel` and `uploads_create`; their fixed routing fields are not caller arguments. `both` publishes both forms, using the same scope checks, task admission and dispatcher. The dedicated `axon_status_dashboard` tool remains unchanged in every mode. CLI selection overrides `AXON_MCP_TOOL_PROJECTION`, which overrides the deprecated `AXON_MCP_PROJECTION` fallback. See the [MCP reference](docs/reference/mcp/overview.md). ```json { "action": "doctor" } { "action": "source", "source": "https://example.com", "scope": "site" } { "action": "ask", "query": "How does setup work?" } { "action": "query", "query": "embedding pipeline" } { "action": "jobs", "subaction": "events", "job_id": "" } { "action": "watch", "subaction": "list" } { "action": "prune", "subaction": "plan" } ``` Response modes (`response_mode`): `path` (artifact ref), `inline`, `both`, `auto_inline` — MCP responses never expose a server filesystem path; clients follow the returned `artifact_id`. The generated wire contract is [`docs/reference/mcp/tool-schema.md`](docs/reference/mcp/tool-schema.md). HTTP auth: static bearer token (`AXON_HTTP_TOKEN`) or OAuth/lab-auth (`AXON_AUTH_MODE=oauth`). Tokenless HTTP is allowed only for loopback development binds; non-loopback binds require OAuth or a static token. `/mcp` and `/v1/*` share the same auth policy. ## HTTP API and surfaces `axon serve` starts one Axum HTTP server on `AXON_HTTP_HOST:AXON_HTTP_PORT` (default `127.0.0.1:8001`) mounting: - `/v1/*` — REST API (`/v1/sources`, `/v1/jobs`, `/v1/query`, `/v1/ask`, `/v1/memories`, `/v1/watches`, `/v1/prune/plan`, …). Async starts return `202` with `{ job_id, status, status_url }`. - `/mcp` — MCP streamable HTTP. - `/docs` — OpenAPI/Swagger UI (OpenAPI JSON at `/openapi.json`). - The Aurora-styled web control panel (first-run setup, config/stack inspection, command runner). - OAuth metadata + auth routes when `AXON_AUTH_MODE=oauth`. Companion apps (each is a separate release component with its own README under `apps/`): **Palette** (`apps/palette-tauri`, Tauri desktop app), **Android** (`apps/android`, APK), **Chrome extension** (`apps/chrome-extension`), and the bundled **web panel** (`apps/web`). ## LLM, search, and adapter configuration **LLM synthesis** is selected by `AXON_LLM_BACKEND`: | Backend | Setting | |---|---| | `gemini-headless` (default) | Gemini CLI under `~/.gemini` (OAuth) or `GEMINI_API_KEY` | | `openai-compat` | `AXON_OPENAI_BASE_URL` (API root, not `/chat/completions`), `AXON_SYNTHESIS_OPENAI_MODEL` | | `codex-app-server` | `codex app-server` over stdio in an isolated `CODEX_HOME`; `AXON_SYNTHESIS_CODEX_MODEL` | Each backend has `AXON_SYNTHESIS_*_MODEL` and `AXON_CHAT_*_MODEL` overrides. Completion concurrency/timeout are tuning knobs in `[providers.llm]`. **Web search/research** uses a self-hosted SearXNG (`AXON_SEARXNG_URL`) when configured, falling back to Tavily (`TAVILY_API_KEY`). Full-content vs. snippet-only research is `providers.search.research-full-content` in `config.toml`. **Adapter credentials:** `GITHUB_TOKEN`, `GITLAB_TOKEN`, `GITEA_TOKEN`, `REDDIT_CLIENT_ID`/`REDDIT_CLIENT_SECRET`, `HF_TOKEN`. These remain adapter credentials even though every such target now enters through `SourceRequest`. ## Development Start with [AGENTS.md](AGENTS.md), the canonical repository instructions. `CLAUDE.md` and `GEMINI.md` are direct relative symlinks to it; scoped guides use the same arrangement. See [contributing](docs/development/contributing.md) and [documentation maintenance](docs/development/documentation.md) for setup, sources of truth, and verification proportional to the changed files. ```bash cargo build --bin axon # debug cargo build --release --bin axon # release cargo check # fast type check ``` Test and lint: ```bash cargo fmt --all -- --check cargo clippy --workspace --all-targets --features test-helpers -- -D warnings cargo test --workspace --features test-helpers ``` `just --list` and the Justfile own the current recipe definitions. `just verify` is the broad integration gate (including operational and structural checks); `just fix` applies formatter/Clippy fixes; `just precommit` is the broad staged gate. Use scoped documentation checks for prose-only changes rather than rebuilding every product surface. Local dev infra is explicit about Qdrant ownership. `just services-up` (an alias for `just services-up-local`) starts a self-contained Qdrant/TEI/Chrome stack; `just services-up-external-qdrant` requires `AXON_EXTERNAL_QDRANT_URL` and starts only TEI/Chrome. `just services-down` removes the local infrastructure services. Published Qdrant and TEI ports bind to host loopback only; remote access must go through a separately secured network path rather than an unauthenticated LAN listener. Production startup also creates the configured external Docker network idempotently before Compose starts, and production images are pinned by digest. The dev compose file runs the locally built debug binary from `target/debug` inside the `axon:dev-runtime` image — this is a dev convenience, not the axon deployment path. `axon setup init` accepts only non-secret bootstrap values on its command line. Set tokens, API keys, and OAuth client secrets through the protected process environment or the mode-0600 `~/.axon/.env`; Axon never places those values in process arguments. **Module layout:** Rust 2018+ file-per-module — no `mod.rs`. Module roots live in `foo.rs`; submodules in `foo/bar.rs`. Tests live in sibling `foo_tests.rs` sidecar files declared via `#[cfg(test)] #[path = "foo_tests.rs"] mod tests;` inside `foo.rs`. See `AGENTS.md` for the full convention. **Monolith policy:** changed `.rs` files are enforced at CI and via lefthook pre-commit — file size ≤ 500 lines (hard fail), function size warn at 80 / hard fail at 120. Exemptions: `tests/**`, `benches/**`, `config/**`, `**/config.rs`, and `**/*_tests.*`. `./scripts/install-git-hooks.sh` installs lefthook once. ## Release gates Required before a production release: - CI fmt / check / clippy / test. - MCP schema doc sync (`python3 scripts/generate_mcp_schema_doc.py --check`). - CLI help contract tests and generated registry drift checks. - Docker image build + GHCR publish workflow. - Compose smoke workflow. - Self-hosted RTX 4070 smoke for Qwen3 TEI cold/warm timing. Releases are per-component. Three of four (`palette`, `android`, `chrome`) are release-please-driven; `cli` is bumped manually with `cargo xtask bump-version patch|minor|major --component cli` (release-please can't handle `version.workspace = true`; see [release-please#2111](https://github.com/googleapis/release-please/issues/2111)). Ordinary release-please-driven app PRs leave version files alone for release-please; auto-tag selects only the Axon-native CLI and creates its tag and GitHub Release before dispatching artifact builds. The PR gate is: ```bash cargo xtask check-release-versions --base origin/main --head HEAD --mode pr ``` See `AGENTS.md` for the full release pipeline and version-bearing-file rules. ## Troubleshooting Fast checks: ```bash # Bare-metal axon preflight axon doctor systemctl status axon journalctl -u axon -f # Incus incus exec axon -- axon doctor incus exec axon -- systemctl status axon-native incus exec axon -- journalctl -u axon-native -f ``` Important paths: - Bare-metal: `~/.axon/` (`.env`, `config.toml`, `jobs.db`, `logs/`, `artifacts/`, `output/`, `screenshots/`). - Incus: `/mnt/axon-data/` inside the container ↔ `~/.axon-incus/` on the host. Host-native CLI commands do **not** see the Incus deployment's data, and vice versa — a deliberate, permanent fork (see `deploy/incus/README.md`). Common failures: - **GPU unavailable:** verify `nvidia-smi` and NVIDIA Container Toolkit on the TEI host. Under Incus, the `nvidia-procfs` device may need re-adding after a container restart (see `deploy/incus/README.md`). - **TEI slow on first boot:** model download/cache warmup is the cold path. - **LLM unauthenticated:** for Gemini, run the Gemini CLI login outside Axon; for OpenAI-compatible, set `AXON_LLM_BACKEND=openai-compat` + `AXON_OPENAI_BASE_URL` + `AXON_SYNTHESIS_OPENAI_MODEL`. - **Detached jobs never advance:** no worker is running — start `axon serve` (or `axon jobs worker`). - **Auth failures:** make sure Claude/plugin config uses the same token as `AXON_HTTP_TOKEN` in `~/.axon/.env`. ## Documentation Beyond this README, the live doc tree (under [`docs/`](docs/)): **Guides** ([`docs/guides/`](docs/guides/)) — [quickstart](docs/guides/quickstart.md), [getting-started](docs/guides/getting-started.md), [configuration](docs/guides/configuration.md), and per-source walkthroughs ([web](docs/guides/web-crawls.md), [local](docs/guides/local-sources.md), [GitHub](docs/guides/github-repos.md), [packages](docs/guides/package-registries.md), [sessions](docs/guides/sessions.md), [CLI tools](docs/guides/cli-tool-sources.md), [MCP tools](docs/guides/mcp-tool-sources.md), [ask/query/retrieve/search](docs/guides/ask-query-retrieve-search.md)). **Operations** ([`docs/operations/`](docs/operations/)) — [deployment guide](docs/operations/deployment.md), [operations runbook](docs/operations/operations.md), [security model](docs/operations/security.md), [performance tuning](docs/operations/performance.md). **Contributing** ([`docs/development/`](docs/development/)) — [contributing](docs/development/contributing.md), [adding a source adapter](docs/development/adding-source-adapter.md), [adding an MCP action](docs/development/adding-mcp-action.md), [adding a REST route](docs/development/adding-rest-route.md). **Architecture** — [`docs/architecture/overview.md`](docs/architecture/overview.md). **Generated references** ([`docs/reference/`](docs/reference/)) — the machine-readable source of truth, regenerated by `cargo xtask schemas`: [CLI command registry](docs/reference/cli/commands.json), [OpenAPI](docs/reference/rest/openapi.json), [MCP tool schema](docs/reference/mcp/tool-schema.json), [API DTOs](docs/reference/api/schemas.json), [config/env schemas](docs/reference/config/config.schema.json), [database schema](docs/reference/runtime/database-schema.json), [graph](docs/reference/sources/graph.schema.json), [vector payload](docs/reference/sources/vector-payload.schema.json), [events](docs/reference/runtime/events.schema.json), [provider capabilities](docs/reference/runtime/provider-capabilities.schema.json). **Per-crate agent contracts** — `crates//src/CLAUDE.md` (with `AGENTS.md`/`GEMINI.md` symlinks) for each workspace crate. **Design contract packet** — [`docs/pipeline-unification/`](docs/pipeline-unification/README.md) is the historical design record for the source-pipeline unification effort (issue #298). It's retained as a permanent archive; the live docs above supersede it for current usage. ## Related files - `install.sh` / `install.ps1` — verified one-line installers. - `deploy/incus/` — Incus deployment (profile, bootstrap, host unit). - `deploy/systemd/` — bare-metal systemd unit + walkthrough. - `docker-compose.prod.yaml` — canonical infra reference (Qdrant/TEI/Chrome image versions and ports); also the dev stack base. - `.env.example` / `config.example.toml` — env and tuning templates. - `plugins/axon/.claude-plugin/plugin.json` — Claude plugin manifest. - `docs/reference/cli/commands.md` / `.json` — generated CLI command registry. - `docs/reference/mcp/tool-schema.md` — generated MCP wire contract. - `docs/` — full documentation tree: guides, `reference/`, architecture, operations, and the `pipeline-unification/` design contract packet. ## Related servers - [soma](https://github.com/jmagar/soma) — RMCP runtime for provider-backed MCP servers. - [unifi-rmcp](https://github.com/jmagar/unifi-rmcp) — UniFi controller REST API bridge. - [tailscale-rmcp](https://github.com/jmagar/tailscale-rmcp) — Tailscale API bridge. - [unraid-rmcp](https://github.com/jmagar/unraid-rmcp) — Unraid GraphQL bridge. - [apprise-rmcp](https://github.com/jmagar/apprise-rmcp) — Apprise notification fan-out. - [gotify-rmcp](https://github.com/jmagar/gotify-rmcp) — Gotify push notification bridge. - [arcane-rmcp](https://github.com/jmagar/arcane-rmcp) — Arcane Docker management bridge. - [yarr](https://github.com/jmagar/yarr) — media-stack bridge (Sonarr/Radarr/Prowlarr/Plex). - [ytdl-rmcp](https://github.com/jmagar/ytdl-rmcp) — media download and metadata workflow. - [synapse-rmcp](https://github.com/jmagar/synapse-rmcp) — local Synapse workflow server. - [cortex](https://github.com/jmagar/cortex) — syslog and homelab log aggregation. - [labby](https://github.com/jmagar/labby) — homelab control plane and MCP gateway. - [lumen](https://github.com/jmagar/lumen) — local semantic code search. ## License Original Dinglebear-authored portions of this project are licensed under [AGPL-3.0-only](LICENSE). Separate commercial licensing is available for organizations that need terms outside the AGPL. Third-party material remains under its original license. See [LICENSING.md](LICENSING.md).