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 shellThe 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 notCircinus'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.