Skip to main content

Quick Start

Circinus is not yet published as an installable package — there is no uv tool install circinus-runtime today, and this page will not pretend otherwise. The only supported path right now is running it from a source checkout with uv, and the source repository is currently private — during this Alpha, git clone below only works if you already have access. If you don't, this is exactly what the Try/Install CTA on this site is for: it's a request for access, not a command you can run yet.

git clone https://github.com/horonomy/circinus.git
cd circinus
uv sync # install the project and its dev dependencies
uv run circinus install claude-code # register Circinus's hooks into .claude/settings.json
uv run circinus start # start the local runtime (circinusd)
uv run circinus status # installed? daemon healthy? shadow or enforce? hooks connected?
uv run circinus doctor # PASS/WARN/FAIL diagnosis of the whole install, with remediation

That's the whole setup. circinus install claude-code writes only the minimum hooks it needs (PreToolUse, PostToolUse, PostToolUseFailure) into .claude/settings.json — project scope by default, --scope user for ~/.claude/settings.json — and preserves every other key and hook already there. It is safe to re-run; install and uninstall (uv run circinus uninstall claude-code) are both idempotent. uv run circinus install claude-code --print shows the change without writing anything.

Once installed, Circinus starts in shadow mode: hooks fire, events are recorded, and every PreToolUse decision is allow — every install gets this, and no shipped command changes it (see Limitations for what actually reaching enforce mode would take). If the daemon is down, the hook fails open (shadow mode) or closed (enforce mode) explicitly, and logs the gap rather than staying silent.

circinus must resolve on PATH for the hook itself, not just your shell

The hook commands Circinus writes into settings.json are the bare word circinus (e.g. circinus hook pre-tool-use), not uv run circinus .... Claude Code spawns that command in its own subprocess later — uv run only puts circinus on PATH for the duration of the command you ran it with, not for that later, separately-spawned process. Install the entrypoint on PATH before relying on hooks firing (e.g. uv tool install --editable ., or an activated .venv). circinus doctor's hooks_installed check confirms the entries exist in settings.json, not that the circinus command they invoke is actually reachable — see Troubleshooting for the exact symptom this produces.

Supported Claude Code workflow​

This MVP integrates with exactly one agent host: Claude Code, via its PreToolUse, PostToolUse, and PostToolUseFailure hooks. circinus install claude-code registers those hooks; from then on, every matched tool call in your Claude Code session is observed and durably recorded, and (in shadow mode) reported on without changing the outcome. There is no support yet for other agent hosts or frameworks.

Bash and fs_write (Write/Edit) are gated end to end; WebFetch is not

Circinus's hook matcher recognizes several tool names, but the enforcement gate (PreToolUse) is wired end to end for Bash calls and, as of MVP 2.1, for Write/Edit calls (the fs_write action class) — WebFetch is observed and recorded for provenance, but not yet run through the same synchronous gate. See Limitations for the full list of what is and isn't enforced today.

Confirm the bootstrap worked​

The project's own smoke path exercises the same install → start → hook flow end to end, against the real daemon over a real unix socket, with no network and no provider key:

uv run pytest tests/benchmark/ tests/acceptance/

Multiple projects on one machine​

Circinus's local state defaults to a single per-machine, per-user location — ${XDG_STATE_HOME:-~/.local/state}/circinus — not per-project or per-checkout. Two installs on the same machine (two different repos, or two clones during evaluation) share one daemon, one SQLite database, and one install manifest by default; circinus status/circinus doctor run from one checkout can report state that actually belongs to another. This is very likely the intended design (a single daemon per machine, matching a systemwide agent-trust runtime), but it can surprise anyone running Circinus from more than one project directory.

To isolate a checkout, set XDG_STATE_HOME before running any circinus command for that checkout:

XDG_STATE_HOME=/tmp/circinus-state-project-a uv run circinus install claude-code
XDG_STATE_HOME=/tmp/circinus-state-project-a uv run circinus start

See Troubleshooting → Local state location and safe backup / purge for backup/purge guidance and the same detail in more depth.

Where to go next​

  • CLI Reference for every subcommand — doctor, repair, config, explain, authorize, and the rest.
  • Architecture for how the end-to-end decision path actually works.
  • Limitations before you rely on this for anything — read this one honestly, not optimistically.