CLI Reference Open-Core
The Intutic CLI provides workspace management, harness detection, config sync, and trace querying.
Installation
# Install workspace CLI globally
npm install -g @intutic/cli
# Install or run native Rust proxy gateway
npm install -g @intutic/proxy
npx @intutic/proxyGlobal options
| Option | Description |
|---|---|
--version, -V | Show the CLI version. Only before a command: intutic --version. |
--help, -h | Show help for the program or for any command, e.g. intutic gates install --help |
intutic trace is an alias of intutic traces, and intutic install-daemon / intutic uninstall-daemon are shortcuts for intutic daemon install / intutic daemon uninstall.
A command that changes the workspace needs a role that may make the change, the same as in the dashboard (what each role can change). When yours cannot, the command fails with the roles it needs, for example API PUT /api/v1/budget refused (403): Requires the OWNER or ADMIN role. A Viewer can run the read-only commands and manage their own login and keys.
Choosing a control plane
Every command that talks to a control plane picks it the same way; the first that is set wins:
- A flag:
--control-plane-url <url>(onlogin,connectanddaemon install), or--devfor the local one athttp://localhost:3001. - The environment:
INTUTIC_CONTROL_PLANE_URL, orINTUTIC_DEV=1for the local one. - A workspace initialized with
intutic init --dev, which uses the local one. - The control plane
intutic loginsaved with your credentials.
With none of these set, a command that needs a control plane says so and exits: the open core runs locally (intutic start) and has no default control plane.
intutic status shows the control plane this order picks.
intutic init
Initialize the workspace: find its root, detect harnesses, and record both locally.
intutic init [options]Options:
| Option | Description |
|---|---|
--dev | Record dev mode, so later commands use the local control plane (http://localhost:3001) |
--git-hooks | Install the Intutic Git hooks without asking |
--no-git-hooks | Skip the Git hooks without asking |
--gates | Install the harness gates and rules files (intutic gates install) without asking |
--no-gates | Skip the harness gates without asking |
What it does:
- Finds the workspace root: the nearest directory, from the current one upwards, that holds
.git/orpackage.json. Exits1if there is none. - Detects the harnesses present in the workspace and lists each with its config file.
- Reports whether you are logged in. No login is needed:
initmakes no network call. - Records the workspace root, the detected harnesses and dev mode in
~/.intutic/config.json, keeping any other settings already there. - Installs the Git hooks if you agree:
post-commitandpost-checkout(record the branch and commit withintutic sync-context),pre-commit(refuses a commit that stages a credential, and warns on risky skill files) andpost-merge(refreshes the decisions log). A hook that already exists and is not Intutic's is left untouched. - With no login and at least one harness detected, installs the harness gates and rules files if you agree: the same as running
intutic gates installafterwards. - Prints setup instructions for pointing each detected harness at the local proxy (
http://localhost:4000, orINTUTIC_PROXY_URL).
Without the gates, init writes no harness config files. intutic gates install writes them from this machine alone; on a machine with a login, intutic connect writes them instead, from the control plane's SOPs plus your local .intutic/sops/.
Prompts: with a terminal attached, init asks before installing the Git hooks, and before installing the gates. Without one (CI, a provisioning script, stdin redirected) it never asks: it skips both unless --git-hooks or --gates is passed, and says so. --git-hooks/--no-git-hooks and --gates/--no-gates skip each question either way.
Examples:
intutic init
# Non-interactive, with the hooks and the gates
intutic init --git-hooks --gatesintutic start
Run the proxy in the foreground, standalone — no account or control plane needed.
intutic start [options]Options:
| Option | Description | Default |
|---|---|---|
--port <port> | Port the proxy listens on | The port of INTUTIC_PROXY_URL, else 4000 |
--valkey-port <port> | Local Valkey port to use or start | 6379 |
--upstream-url <url> | Upstream LLM provider base URL, passed to the proxy as UPSTREAM_URL | (proxy default) |
--no-gates | Neither refresh the local gates nor watch .intutic/sops | Refresh and watch |
What it does:
- Local gates. On a machine with no login whose gates
intutic gates installinstalled, refreshes them before the proxy starts (the gate scripts, the rules files from.intutic/sops/and the policy snapshot), and again whenever.intutic/sops/changes while the proxy runs. The refresh never writes routing. Each refresh also deletes the decide logs in~/.intutic/logs/(decide-<date>.jsonl, and thedecide-state-<date>.jsonlfiles--log-statewrites) more than 30 days old. With no gates installed, one line names the recorded harnesses that have none.--no-gatesskips this step. - Decide engine (background). When the policy snapshot carries decide rules and an engine is configured (
intutic decide configure, orINTUTIC_DECIDE_MODEL), it loads the engine's model and keeps it loaded for 8 hours (Ollama'skeep_alive, with thelogprobsadapter only), then runs the known-answer canary and stores the result in~/.intutic/decide/canary.json, where the gates read it. This runs beside the proxy's start-up: each result is printed, and none stops or delays the proxy. - Valkey (best-effort). Checks for a Valkey or Redis on
127.0.0.1:<valkey-port>. If none is listening, it tries, in order: starting anintutic-valkeyDocker container (valkey/valkey:8-alpine), thenvalkey-serverorredis-serverfromPATH. If none of these works, it warns and continues in standalone mode: routing, policies, DLP, and local spend caps all still work; bandit learning persists to~/.intutic, and the response cache lasts only as long as the process. - Proxy binary. Runs the version-matched binary in
~/.intutic/bin/if it is there, otherwiseintutic-proxyfromPATH. If neither exists it printsnpm install -g @intutic/proxyand exits with status1. - Proxy environment. Starts the proxy with your environment plus:
PORTset to--port- with Valkey running:
VALKEY_URL, taken from your environment if set, otherwiseredis://127.0.0.1:<valkey-port> - without Valkey:
INTUTIC_STANDALONE=1— unlessCONTROL_PLANE_URLis set in your environment. That marks a managed deployment, where the proxy requires Valkey and refuses to start without it;intutic startleaves that decision to the proxy. UPSTREAM_URLwhen--upstream-urlis given
Ctrl+C stops the proxy, and the command exits with the proxy's exit code.
Examples:
intutic start
export ANTHROPIC_BASE_URL=http://localhost:4000
# Different port, and a Valkey on 6380
intutic start --port 8080 --valkey-port 6380intutic gates install
Install the tool-call gate and rules file for each harness intutic init recorded, from this machine alone — no account or control plane needed.
intutic gates install [options]Options:
| Option | Description |
|---|---|
--harness <id> | Only this harness, for example cursor. It must be recorded in ~/.intutic/config.json, unless --add is passed too |
--add | With --harness: record the harness in ~/.intutic/config.json first |
--route | Also point each harness's LLM traffic at the local proxy (http://127.0.0.1:4000, or the port of INTUTIC_PROXY_URL). The proxy must then be running, for example as a service with intutic daemon install --proxy, or the harnesses cannot reach their model |
--dry-run | Print what would be written, and write nothing |
--workspace <path> | The workspace to write into. Default: the one intutic init recorded |
What it writes, for every recorded harness (one with --harness):
- The gate. The same tool-call gate
intutic connectinstalls, registered where the harness reads it (.claude/settings.jsonfor Claude Code, Cursor'shooks.json, and so on). Your own hooks and settings stay. Every gate enforces the built-in protections, such as refusing an agent's attempt to remove or unlock Intutic's own files. - The policy snapshot (
~/.intutic/hooks/policy-snapshot.rulesand.json) every gate reads: the destructive-command and skill-directory tiers, and from.intutic/sops/eachreview_before:token, the lane holds of eachclosed_lanes:, thedecide:rules (with the pinsintutic decide evalwrote), and the rule records: each qualifiedrequires_before:([ok]),scope_paths:underscope_paths_mode: enforce, andplan_approval:. A SOP withroles:contributes no rule records or lane holds, since a gate knows no role. With no control plane to approve a hold, areview_before:token or a lane hold is refused outright, with a message saying so, rather than held, andplan_approval:refuses every gated call that is not a read (PLAN_NOT_APPROVED). The snapshot names no workspace and is markedsource: local. - The rules files from the SOPs in
.intutic/sops/, into each harness's own file (see Where rule sets go). A harness no SOP targets gets no rules file. - The bundled agent skills, once per workspace: the Kitkat skill (
.agents/skills/intutic-governance-kitkat/SKILL.md), which tells an agent what each refusal code means and what to do about it, and the Rule Author skill (.agents/skills/intutic-rule-author/SKILL.md), asintutic connectwrites them. Only a missing one is written; a copy already there is never overwritten.intutic disconnectdeletes the copies it wrote, unless you have edited them.
It also blanks the API key an earlier intutic connect may have left in ~/.intutic/env/runtime.env, so no gate posts events to that control plane, and moves .intutic/events/hook-events.jsonl aside to hook-events.jsonl.1 once it passes 10 MB: with no control plane, nothing drains it.
Not written: proxy routing (unless --route), MCP server wrapping, and anything sent anywhere: it makes no network call. .env.intutic, which Codex and the SDK frameworks read only when you source it, is still written for a harness a SOP targets. With --route, Windsurf's traffic goes through the proxy's TLS interception, which needs the Intutic CA (~/.intutic/ca.crt, created when the proxy first runs) trusted; gates install does not trust it for you.
It prints each file written and the gate file of each harness, and ends with Undo with intutic disconnect. Re-run it after editing .intutic/sops/, or keep intutic start running, which refreshes the gates when the SOPs change.
Refused, with exit status 1, on a machine with a login (intutic connect installs and refreshes the gates there; run intutic disconnect first to switch to local gates), and before intutic init.
Examples:
intutic gates install
# What it would write, for Cursor only
intutic gates install --harness cursor --dry-run
# Also route the harnesses through a proxy that runs as a service
intutic daemon install --proxy
intutic gates install --routeWhen the SOPs carry decide: rules, it also prints how many were compiled and how many are stamped enforce, names any decide: line that does not read by file and line number, and warns when more than 4 rules name one tool.
intutic decide test <rule>
Ask a decide rule's questions about one call, with the engine intutic decide configure set up, and print each answer's probability against its band, the when value and the outcome the rule would reach if it enforced. Decide rules walks through writing, evaluating and enforcing a rule with these commands.
intutic decide test <rule> --state <file> [options]<rule> is the rule's ref (local:data.md#prod-data-export), its id when only one local rule has it, or <file>#<id>.
Options:
| Option | Description |
|---|---|
--state <file> | A JSON file with the call: {"tool", "toolInput", "cwd"?}. A lastUserTurn in it is not sent: context: ["last_user_turn"] is reserved in 3.0, and no gate supplies the user's last turn. For an on: response rule, the response instead: {"response"}, asked in the gateway's layout (the SOP's text, then the response) and held to the engine's response limit (32,768 bytes unless INTUTIC_DECIDE_MAX_RESPONSE_STATE_BYTES says otherwise) |
--json | Print the result as JSON |
--log-state | Also write the exact state sent to ~/.intutic/logs/decide-state-<date>.jsonl |
--workspace <dir> | The workspace whose .intutic/sops to read. Default: the recorded one, else the current directory |
intutic decide eval <rule>
Measure a decide rule on labelled calls. A rule enforces only on a model a passing pre-registered eval pinned, so this is how a rule leaves shadow.
intutic decide eval <rule> --labels <file.jsonl> [--preregister <file>] [--adversarial]Each labels line is one call: {"id", "label": "refuse" | "allow", "tool", "toolInput", "cwd"?} (violation and clean read as refuse and allow). For an on: response rule each line is one response, {"id", "label", "response"}, asked about in the gateway's layout and under its response limit; a response over the limit counts as an escalation. Recall counts a refuse case as caught when it is refused or escalated; false alarms count allow cases refused. A case the engine could not answer counts as an escalation, never as an allow.
- Without
--preregister, it fits one band on the dev split (the cases whose id hashes to a multiple of 3), choosing the band with no automatic error and the fewest escalations, then reports recall, false alarms, escalation and each question's AUC on the rest. It writes a run report and no pin. --preregister <file>naming a file that does not exist writes the pre-registration there: the rule hash, the model digest, the bands and the pass marks, before any label is read. Nothing else happens.--preregister <file>naming that file evaluates every labelled case at the rule's own bands, with the adversarial families added. It passes when the pre-registration matches the rule and the model, the labels file was not used by an earlier pre-registered run of this rule, there are at least 20 cases with 5 to refuse, recall is at least 95%, false alarms at most 10%, escalation at most 40%, and planted approvals are caught at least 90% of the time. A pass writes the pin (~/.intutic/decide/evals/<ruleHash>/<digest>.json) and rewrites the local policy snapshot. A failed run exits with status1. On a logged-in machine the pin is still written, but the policy snapshot there takes its decide rules and pins only from the control plane, so the pin applies to local use on a machine with no login, and the command says so.
--adversarial adds three fixed families to the refuse cases: five planted approvals appended to the arguments, five instructions aimed at the model, and paraphrases of the command (an environment variable for the program, quoting, a line split, reordered flags, long and short options). For a response rule the approvals and instructions are appended to the response, with no paraphrase. No model writes a case. Each family is reported apart.
Options:
| Option | Description |
|---|---|
--labels <file> | The labelled calls, JSONL |
--preregister <file> | Write the pre-registration when the file is absent (reading no label); evaluate against it when present |
--adversarial | Add the adversarial families (always on under a pre-registration) |
--calibration <id> | With --preregister, when writing the pre-registration: pre-register the band and combiner of a candidate calibration of this rule that a control plane holds, fitted on the engine's model, and register the run as that calibration's companion. Needs a control plane: refused without a login |
--json | Print the run report as JSON |
--log-state | Also write each exact state sent to ~/.intutic/logs/decide-state-<date>.jsonl |
--workspace <dir> | The workspace whose .intutic/sops to read |
Examples:
intutic decide eval prod-data-export --labels dev.jsonl
intutic decide eval prod-data-export --preregister prereg.json
intutic decide eval prod-data-export --labels fresh.jsonl --preregister prereg.jsonintutic decide calibrate <rule>
Fit a logistic combiner over the rule's questions (L2, λ = 1) and a band on its output to labelled calls, and save them as a candidate in ~/.intutic/decide/evals/<ruleHash>/candidates/. The next intutic decide eval --preregister for that model carries the candidate; once that eval passes, the combiner replaces when for the model it was fitted on.
| Option | Description |
|---|---|
--labels <file> | The labelled calls, as for intutic decide eval |
--json | Print the candidate as JSON |
--workspace <dir> | The workspace whose .intutic/sops to read |
intutic decide models
The models the pre-registered bake-off measured, and which passed. No laptop-sized model passed, so none is validated for a laptop and the engine has no default model: bring a self-hosted model and validate it on your own labels with intutic decide eval. Nothing is downloaded.
| Option | Description |
|---|---|
--json | Print as JSON |
intutic decide check
The entry the shell gates (Gemini CLI, Goose, Hermes, OpenHands) and the n8n gate call for a tool call that a decide rule names. It reads one JSON request from stdin and writes one JSON line, with exit status 0:
echo '{"v":1,"harness":"goose","tool":"Bash","toolInput":{"command":"pg_dump -h prod"},"cwd":"/repo","sessionId":"s1","budgetMs":3400,"lastUserTurn":null}' \
| intutic decide check --stdin
# {"v":1,"outcome":"refuse","code":"DECIDE_REFUSED","ruleId":"decide.local:data.md#prod-data-export","reason":"…"}outcome is allow, refuse or escalate; code is null, DECIDE_REFUSED, DECIDE_ESCALATED or GOVERNANCE_UNAVAILABLE. A shadow rule never refuses. An enforcing rule refuses with GOVERNANCE_UNAVAILABLE when the engine is unavailable (an error, a timeout, a failed canary), as does input that does not read and a decide record that does not decode. An enforcing rule the engine cannot answer inside budgetMs escalates without being asked. Every evaluated call is written to the decide log, ~/.intutic/logs/decide-<date>.jsonl.
| Option | Description |
|---|---|
--stdin | Read the request from stdin |
intutic decide configure
Write ~/.intutic/decide/engine.json (mode 0600): the engine's URL, adapter and model. The engine must run on this machine or a private address, or on a host listed in INTUTIC_SELF_HOSTED_DECISION_HOSTS; hosted decision APIs are refused. The key, if the engine needs one, is read from INTUTIC_DECIDE_API_KEY only and is never written. The INTUTIC_DECIDE_* variables override the file (see Configuration).
The hook gates refuse this command when an agent runs it: run it yourself.
| Option | Description |
|---|---|
--url <url> | The engine's base URL. Default http://127.0.0.1:11434 (Ollama) |
--adapter <adapter> | logprobs (Ollama, vLLM, llama.cpp, LM Studio), systemone or decisions. Default logprobs |
--model <model> | The model the engine serves. Without one the engine is not configured |
--timeout-ms <ms> | Per-call timeout. Default 5000 |
--parallel <n> | Most requests in flight. Default 1 for Ollama, 8 otherwise |
--structured | Send structured_outputs with logprobs requests |
--no-structured | Do not send it (the default) |
--json | Print the written configuration as JSON |
intutic doctor then checks the engine and its model, runs the known-answer canary, measures the per-call p95 and names every harness whose time budget a rule cannot fit.
intutic decide disable
Run every decide rule on this machine as shadow (each call is logged, none is refused) until intutic decide enable. It rewrites the local policy snapshot; on a connected machine the sync daemon applies it on its next poll. A decide: line that does not read still refuses its tools.
The hook gates refuse this command when an agent runs it: run it yourself.
intutic decide enable
Undo intutic decide disable.
intutic decide lint
Read every decide: line in .intutic/sops/: each rule with its file, line, rule hash and whether a pin exists for it, each line that does not read with its error (a bare decide: line gets the hint "write one rule per line as decide: {json}"), and each tool more than 4 rules name. An on: response rule is marked as judged at the gateway. It warns about each rule declaring context: ["last_user_turn"], which is reserved and not supplied in 3.0; intutic gates install and intutic doctor report it too. Exits with status 1 when a line does not read; the warnings do not change the status.
| Option | Description |
|---|---|
--json | Print as JSON |
--workspace <dir> | The workspace whose .intutic/sops to read |
intutic setup
Guided setup wizard — detect harnesses, configure a provider credential, and verify it, in one interactive flow. It is the interactive counterpart of intutic init, not a replacement: this command always prompts, while init asks only whether to install the Git hooks and the gates, and never without a terminal, so it stays safe for CI. See the cohort wizard guide for a full narrative walkthrough of every step.
intutic setup [options]Options:
| Option | Description |
|---|---|
--dev | Use local control plane (http://localhost:3001) |
What it does:
- Detects harnesses in the current workspace (same detection
intutic inituses) - Asks whether to configure a provider against a connected workspace or locally (no control plane — writes a
.intutic.envfile instead) - Picks a provider from the registry (
intutic credentials listshows the same set) and prompts for its credential fields - Verifies the credential against the provider's own API before saving — a 401/403 asks for confirmation before proceeding anyway; a rate-limited or unreachable response is reported but does not block
- Saves the credential (
PUT /api/v1/workspace/provider-credentials/:provider, same routeintutic credentials sethits) or writes the local env file
There is no judge-model step: judges run only on self-hosted models, so a workspace has no judge model to choose.
Examples:
# Connected to Intutic (requires `intutic login` first)
intutic setup
# Against a local control plane
intutic setup --devintutic status
Show workspace status — auth, harnesses, sync state.
intutic statusNo options. Displays:
- Current authentication state: email, workspace, and the control plane commands use (see Choosing a control plane)
- The workspace root, dev mode and config version recorded by
intutic init - The harnesses recorded by
intutic init, by name - Gates: installed locally (by
intutic gates install), installed byintutic connect, or none - Sync state: last sync timestamp and the number of tracked files, and whether the sync daemon is running
- Running agent processes, with a warning when a recorded harness is running but the sync daemon is not
intutic doctor
Diagnose workspace health — proxy, auth, daemon, configs, logs, Valkey, CA trust, policy snapshot, gates, decide.
intutic doctorNo options. Runs these checks in order, each printing ✓ or ✗ plus a one-line remediation on failure:
- Proxy reachable (
http://127.0.0.1:4000/health, or the port ofINTUTIC_PROXY_URL) - Control plane auth (the stored credentials against
/api/v1/auth/me) - Sync daemon running (PID file or process scan)
- Harness config files intact (SHA-256 against
<workspaceRoot>/.intutic/integrity.json) - Daemon log readable (
~/.intutic/logs/sync-daemon.log, then the system-service log, then the legacy~/.intutic/daemon.log) - Valkey reachable (TCP probe on
127.0.0.1:6379) - CA cert trust (
~/.intutic/ca.crtplus the OS trust store) - Policy snapshot present, valid, non-empty and fresh (
~/.intutic/hooks/policy-snapshot.rules) - Local gates, on a machine with no login: a gate file for each recorded harness that has one
- Plan approval, only when a SOP sets
plan_approval:: with no control plane connected it fails, since every gated call that is not a read is refused withPLAN_NOT_APPROVED; on a connected machine it fails until the daemon has written a fresh approved-plans cache (~/.intutic/hooks/approved-plans.jsonl) - Cisco skill scanner on
PATH(optional; never fails) - Decide, always. With no decide rules in the snapshot and no engine configured it prints one passing line,
✓ Decide — no decide rules and no engine configured. Otherwise: the engine and its model (with the digest, and a note when the server cannot report a weights digest), the known-answer canary (cached in~/.intutic/decide/canary.json), the per-call p95 of 20 warm calls (stored in~/.intutic/decide/engine.json), and every harness and rule pair whose time budget the rule cannot fit, for example "prod-data-export cannot be evaluated within windsurf's 2,300 ms (estimated 3,100 ms)". Such a rule escalates there instead of being asked
Checks 2–5 need a control plane. On a machine with no login they are skipped with one note, the proxy and CA-trust remediations point at intutic start, and checks 8 and 9 look at what intutic gates install wrote and point at it to fix what is missing.
See intutic doctor for what each check verifies and how to fix it.
intutic disconnect
Undo intutic connect or intutic gates install on this machine: put every harness config they changed back the way it was, remove the gates and the background services, and log out.
The hook gates refuse this command when an agent runs it: run it yourself.
intutic disconnect [options]Options:
| Option | Description |
|---|---|
--harness <id> | Disconnect one harness only, for example cursor. The login, the services and the other harnesses stay. |
--dry-run | Print exactly what would change, and change nothing |
--keep-login | Keep the stored credentials |
What it undoes, for every harness (one with --harness):
- Rules files of Intutic's own (
.claude/rules/intutic-governance.md,.cursor/rules/intutic-governance.mdc,.windsurf/rules/intutic-governance.md,.clinerules/intutic-governance.md,.continue/rules/intutic-governance.md,.openhands/microagents/intutic-governance.md,.intutic/aider-sops.md) and.env.intutic: deleted, or the file you had before at that path comes back. - Rules sections in files you also write (
AGENTS.md,GEMINI.md,.github/copilot-instructions.md,.goosehints, and theAGENTS.mdof OpenClaw's agent workspace): the section between theINTUTIC:RULESmarkers is taken out, and the file comes back byte for byte when you did not edit it, or is deleted if connect created it. See Where rule sets go. - Rules files earlier versions wrote whole (
CLAUDE.md,.cursorrules,.windsurfrules,.roorules,AGENTS.md): the file you had before comes back, or the file is deleted if connect created it. - Hook registrations in each harness's settings (
.claude/settings.json, Cursor's and Windsurf'shooks.json, and the rest): only the entries that run an Intutic gate are removed. The gate scripts are deleted. - Proxy routing: base URLs and proxy settings connect pointed at the proxy (Codex
openai_base_url, ContinueapiBase, GooseOPENAI_HOST/ANTHROPIC_HOST, Grokbase_url, Pi and OpenHands base URLs, Aideropenai-api-base, Windsurfhttp.proxy, the JetBrains IDE proxy for the Windsurf plugin, dsh'sllm-deepseekroute) go back to the values they had. - MCP servers: each server connect wrapped gets its original entry back, every key included; the
intuticserver connect added is removed; and the copies of approved.mcp.jsonservers connect added to~/.claude.jsonare removed. - What connect replaced or removed comes back: the Claude Code
permissions.denyrules connect replaced, and Aider'stest-cmd,lint-cmd,auto-testandauto-lint. - Agent skills (without
--harness): the Kitkat and Rule Author skills connect wrote into.agents/skills/, unless you have edited them. A copy that was there before connect, or that an earlier version of connect wrote, stays.
Without --harness it also removes the services intutic daemon install set up for your user (a system-wide one is listed with the command that removes it), the Intutic CA certificate connect trusted (in the macOS login keychain, or connect's intutic-connect-ca.crt in the Linux system trust store, which needs root: run as a user, disconnect prints the sudo rm and bundle-rebuild commands instead), the intutic-valkey Docker container connect started, the gate caches in ~/.intutic/hooks/ (the policy snapshot with its verified copy, the approved bypasses and the egress policy), ~/.intutic/env/runtime.env (the copy of the API key the gates read) and, unless --keep-login, the stored credentials. It resets the synced config version, so a later intutic connect writes everything again.
How it knows what you had: before connect first writes a file, it keeps a copy of it, in .intutic/originals/ for files in the workspace and ~/.intutic/originals/ for the rest (owner-only, and ignored by git). A file you have not changed since is restored byte for byte. In one you have changed, only Intutic's entries are taken out and your edits stay. A file connect writes whole that you edited is left as it is, and listed.
Files from an earlier connect: versions before this one kept no copies. For their files, disconnect removes what it can recognise as Intutic's: the generated header, entries that run an Intutic gate, wrapped MCP servers (their arguments carry the original command), and URLs on the proxy connect used. A generated file git does not track is deleted; where git has a committed version that is not generated, that version comes back. A setting connect overwrote is removed rather than restored, because its earlier value is unknown, and the output says so. Deny rules connect added to permissions.deny cannot be told apart from yours, and are listed for you to review.
Left in place: your SOPs in .intutic/sops/, Intutic's own state in ~/.intutic/ (configuration, logs, events, the downloaded proxy), <file>.drift-backup copies (they hold edits connect reverted), and a valkey-server or redis-server connect started outside Docker. Git hooks from intutic init --git-hooks live in .git/hooks/, and variables from intutic env persist are removed with intutic env clear.
The control plane is told (with a login; with none there is no control plane, and nothing is sent): before it removes the credentials, a real run reports the disconnect (POST /api/v1/devices/disconnect, with the machine's fingerprint and the harnesses), so the control plane stops expecting the machine's gates instead of alerting that they went silent, the devices list and the AI inventory show the machine or harness as disconnected rather than stale or newly ungoverned, and the disconnect is recorded for SIEM export (device_disconnects). If the control plane cannot be reached within five seconds, the disconnect goes ahead and says so. Running intutic connect again reconnects.
While connect runs: a running intutic connect would write everything straight back. A real run stops the services first, then exits with status 1 before changing any file if an intutic connect you started yourself is still running. --dry-run only warns.
One harness: --harness leaves a file another connected harness also writes (AGENTS.md is shared by Codex, Muse Code, Grok Build, OpenCode, Pi, Hermes, Roo Code and dsh; .env.intutic by Codex and the SDK frameworks). It removes the harness from ~/.intutic/config.json, so connect stops writing its config and stops wrapping its MCP servers; run intutic init to manage it again.
Examples:
# See what would change
intutic disconnect --dry-run
# Disconnect everything, keep the login
intutic disconnect --keep-login
# Stop governing Cursor only
intutic disconnect --harness cursorintutic traces list
List execution traces, from the control plane when you are logged in or from the local proxy's trace log when you are not.
intutic traces list [options]Options:
| Option | Description | Default |
|---|---|---|
--limit <n> | Number of traces to show (1–100 in connected mode) | 20 |
--since <duration> | Time window: 30m, 24h, 7d, or an ISO 8601 timestamp | 24h |
--action <type> | Connected mode only. Filter by enforcement action: BYPASS, ENHANCE, HIJACK, KILL | (all) |
--verdict <type> | Local mode only. Filter by verdict: allowed, killed, upstream_error, reasked, hijacked | (all) |
--model <name> | Filter by requested model name | (all) |
--json | Output as JSON instead of a table | false |
--dev | Use local control plane (http://localhost:3001) | — |
intutic trace list is the same command.
What it does:
The mode depends only on whether intutic login has stored credentials, not on whether intutic connect is running:
- Connected mode (logged in) queries the control plane and shows Trace ID, Timestamp, Model, Action, Score, and Cost.
--verdictis ignored. If the request fails, the command exits with status1. - Local mode (not logged in) reads the proxy's daily trace files,
~/.intutic/logs/traces-YYYY-MM-DD.jsonl(%APPDATA%\intutic\logs\on Windows), newest first, and shows Trace ID, Timestamp, Model, Verdict, and Cost. There is no compliance score locally.--modelmust match the requested model exactly. It warns when a day's file reached the proxy's 64 MB daily limit (later traces that day were dropped, so the count is a minimum) and when lines could not be parsed. Passing--action, or a--verdictvalue not in the list, exits with status1.
Examples:
# Last 20 traces from the past 24 hours
intutic traces list
# All KILL actions from the past week (connected mode)
intutic traces list --action KILL --since 7d
# Killed requests from the local log (local mode)
intutic traces list --verdict killed --since 7d
# JSON output for scripting
intutic traces list --json --limit 100
# Filter by model
intutic traces list --model claude-4-sonnetintutic traces inspect <trace_id>
Show full detail of a single trace.
intutic traces inspect <trace_id> [options]Arguments:
| Argument | Description |
|---|---|
trace_id | The trace ID to inspect (e.g., tr_abc123) |
Options:
| Option | Description |
|---|---|
--dev | Use local control plane (http://localhost:3001) |
Example:
intutic traces inspect tr_abc123Logged in, it returns the trace from the control plane: token counts, costs, compliance scores, anomaly data and the corrective prompt card. Not logged in, it looks the trace up in the local trace files (~/.intutic/logs/traces-*.jsonl).
intutic budget
Check remaining daily/monthly budget and list active loops, or watch spend live. The subcommands below set the workspace's caps and the budgets and rate limits on keys and members.
intutic budget [options]
intutic budget --watch [--interval <seconds>]Options:
| Option | Description | Default |
|---|---|---|
--dev | Use local control plane (http://localhost:3001) | — |
--watch | Print machine-local and workspace spend continuously, one line per tick, until Ctrl+C | — |
--interval <seconds> | Tick interval for --watch. A non-numeric or non-positive value falls back to the default. | 5 |
What it does:
Without --watch:
- When you are logged in, prints the workspace's budget from the control plane: daily and monthly spend against their budgets with percentages, the daily cap and whether it is the workspace's own or the $100-a-day default of a workspace that never saved one, remaining budget, and an alert line when the alert threshold is exceeded.
- Prints the local spending cap from
~/.intutic/config.json(maxDailyBudgetUsd, ormax_daily_budget_usd; default$10.00). - Prints today's machine-local spend from the local proxy at
http://127.0.0.1:4000(or the port ofINTUTIC_PROXY_URL), or a dash when the proxy is not running. - When you are logged in, lists every
ACTIVEloop run with its token spend and budget limit.
Without a login it runs in standalone (offline) mode and prints only the local figures.
With --watch, it prints one line per tick in this shape:
[10:42:05] machine-local: $0.4210 / $10.00 | workspace: $3.1200 / $50.00The time is printed in your locale's format.
machine-localis today's spend and cap as reported by the local proxy athttp://127.0.0.1:4000(or the port ofINTUTIC_PROXY_URL).(enforcement off)is appended when the proxy is not enforcing the cap;— (local proxy not running)is shown when it cannot be reached.workspaceis the workspace's daily spend and daily budget, refreshed on the first tick and every 6th tick after that (every 30 seconds at the default interval). It shows— (not connected)when you are not logged in or the request fails.
--watch does not list loops. It works without a login; only the workspace figure needs one.
Examples:
intutic budget
# Live view, one line every 5 seconds
intutic budget --watch
# Every 2 seconds
intutic budget --watch --interval 2intutic skill list
List the rule and skill files in the workspace.
intutic skill listNo options.
What it does:
Looks in the workspace recorded by intutic init (~/.intutic/config.json), or the current directory when there is none, for:
- Rule files at the workspace root:
.cursorrules,CLAUDE.md,.windsurfrules,.clauderules,rules.md - Skill files one directory below each skill root:
.agents/skills/<name>/SKILL.mdand.claude/skills/<name>/SKILL.md
Prints each file found with its line count. It reads the files but does not scan their content; use intutic skill audit for that. When you are logged in, it also reports the list (paths and line counts) to the control plane. A failed report is ignored.
intutic skill audit
Scan rule files, skill files, and the scripts bundled with skills for leaked credentials and unsafe instructions.
intutic skill audit [--sarif] [--engine <native|cisco>] [--exit-zero]Options:
| Option | Description | Default |
|---|---|---|
--sarif | Print the skill-file and bundled-script findings as a single SARIF 2.1.0 JSON document on stdout (for GitHub Code Scanning and other CI tools) instead of the readable report. Findings in root rule files are not in the document but still set the exit status | — |
--engine <engine> | native runs the built-in scanner. cisco also runs Cisco's skill-scanner on each skill directory; the skill-scanner binary must be on PATH (pipx install cisco-ai-skill-scanner). | native |
--exit-zero | Exit 0 even when the audit has findings or could not scan everything | — |
What it does:
It scans the workspace recorded by intutic init, or the current directory when there is none:
- Rule files at the workspace root (
.cursorrules,CLAUDE.md,.windsurfrules,.clauderules) are checked for hardcoded Intutic virtual keys, hardcodedsk-live-secrets, recursive-delete wildcards such asrm -rf *, andcurl/wgetcommands. - Skill files (
.agents/skills/<name>/SKILL.md,.claude/skills/<name>/SKILL.md) are content-scanned, whole, for prompt-injection, data-exfiltration, and malicious-code patterns. See Skill Scanning. - Bundled files next to each
SKILL.md(up to 3 directories deep and 40 files per skill; symlinks are skipped) are hashed (SHA-256). Shell, Python, JavaScript, TypeScript, Ruby, PowerShell, and Perl scripts up to 256 KiB are also content-scanned. Data files —.md,.markdown,.txt,.rst,.json,.jsonl,.yaml,.yml,.csv,.tsvand images (.png,.jpg,.jpeg,.gif,.webp,.svg,.ico,.bmp) — are not scripts: they are listed as not applicable and do not affect the result, unless a shebang makes one a script, which is then scanned. Any other file that is larger than the cap, unreadable, or not a recognised script is reported as unscanned, never as clean: the report names each one, and the audit does not pass.
When you are logged in, three workspace settings change the run:
| Setting | Effect |
|---|---|
enableLocalSkillAuditDelete | Deletes each flagged line from the rule file or SKILL.md it was found in (bundled scripts are not changed) |
ciscoSkillScannerEnabled | Runs the Cisco engine without --engine cisco if skill-scanner is on PATH; if it is not, the run continues with the built-in scanner only |
semanticSkillAnalysisEnabled | Includes each SKILL.md's content (its first 65,536 characters) in the report it uploads, with the SHA-256 and length of the whole file. A SKILL.md longer than that is named in a warning: the semantic judge reads only the first 65,536 characters, so the skill is reported as partially scanned and needs review. It does not change the exit status |
When you are logged in, the results are also reported to the control plane; a failed report is ignored. With --sarif, nothing but the JSON document is printed. Cisco's results, when that engine ran, are added as a second run in the same document. The run's invocations entry lists each unscanned file as a warning notification, each data file as a note, and each failed Cisco run as an error notification, with executionSuccessful: false when an engine run failed.
Exit status: 1 when the audit has findings, when a file other than a data file could not be scanned, or when a Cisco engine run failed, so a CI step fails on them; 0 when everything was scanned and nothing was found, or with --exit-zero. Also 1 for an unknown --engine value, or for --engine cisco when skill-scanner is not on PATH. The report, the SARIF document and the control-plane report are all complete before the command exits.
Examples:
intutic skill audit
# Upload to GitHub Code Scanning, which then decides pass/fail
intutic skill audit --sarif --exit-zero > skills.sarif
# Also run Cisco's skill-scanner
intutic skill audit --engine ciscointutic skill scan-staged
Scan staged skill files for risky content before a commit, as a warning only.
intutic skill scan-stagedNo options.
What it does:
Lists the files staged for commit (added, copied, or modified) under .agents/skills/ and .claude/skills/, then runs the skill-content scan over the staged version of each file (what git commit will record, not what is on disk). Each finding is printed as a warning naming the file, category, and pattern.
It never blocks a commit: the exit status is always 0, findings or not. Outside a Git repository, or with nothing staged under those directories, it prints nothing.
The pre-commit hook that intutic init can install runs this after its credential scan. Unlike this command, the credential scan does refuse the commit when it finds a secret. Run intutic skill audit for the full report.
intutic policy test
Run dry-run WASM policy evaluation locally. For a Rego rule, use intutic rules test.
intutic policy test --wasm <path> --mock <path>Options:
| Option | Description |
|---|---|
--wasm <path> | Path to compiled WebAssembly rule binary (required) |
--mock <path> | Path to mock JSON request context file (required) |
intutic policy compile
Compile an AssemblyScript rule to WASM (wraps asc).
intutic policy compile [options]Options:
| Option | Description | Default |
|---|---|---|
--src <path> | Rule source entry file | assembly/index.ts |
--out <path> | Output .wasm path | build/rule.wasm |
--debug | Include debug info and source maps | false |
What it does: Shells out to npx --no-install asc <src> -o <out> --optimize --exportRuntime, creating the output directory if needed. With --debug it also passes --debug --sourceMap. If asc is not available, install it with pnpm add -D assemblyscript assemblyscript-json.
intutic policy install
Validate and install a compiled WASM rule, native or Rego, into the local proxy rules dir.
intutic policy install --wasm <path> [options]Options:
| Option | Description | Default |
|---|---|---|
--wasm <path> | Path to compiled WebAssembly rule binary (required) | — |
--name <name> | Rule name | (the file name) |
--priority <NN> | Evaluation priority — lower runs first | 100 |
What it does:
- Instantiates the rule and evaluates it against a built-in allow-mock context — a rule that fails to instantiate or evaluate, or returns a code other than 0, 1, 2 or 3, is not installed (2 installs with a deprecation warning: the proxy treats it as a block). A Rego rule is loaded and evaluated through the Rego host instead, and refused if a proxy could not run it
- Writes it as
{priority}_{name}.wasminto the local rules dir —INTUTIC_WASM_DIRif set, otherwise~/.intutic/wasm - Prints the destination path, priority, and SHA-256 of the installed binary
The proxy picks up local rule changes within ~5s on the next request. If your proxy config.yaml sets intutic_settings.wasm_local_dir, make sure it matches this path (or set INTUTIC_WASM_DIR for both).
intutic policy list-local
List WASM rules installed in the local proxy rules dir.
intutic policy list-localNo options. For each .wasm file in the local rules dir (INTUTIC_WASM_DIR, defaulting to ~/.intutic/wasm) it prints the rule name, priority, size, mtime, and a SHA-256 prefix.
intutic rules build
Compile a Rego policy to a rule with OPA, and package it with the metadata the proxies read.
intutic rules build --rego <path> --entrypoint <package/rule> [options]Options:
| Option | Description | Default |
|---|---|---|
--rego <path> | Rego file or directory (required) | — |
--entrypoint <package/rule> | The rule to evaluate, e.g. intutic/shell/deny (required) | — |
--risk-tier <tier> | Default risk tier for the rule's decisions: low, medium, high or critical | (none) |
--out <path> | Output .wasm path | build/<entrypoint>.wasm, with each character other than a letter, digit, _ or - as _ (build/intutic_shell_deny.wasm) |
What it does:
- Runs
opa build -t wasm -e <entrypoint>— OPA must be on thePATH, or setINTUTIC_OPA_BIN; without it the command says how to install it - Takes
policy.wasmfrom the bundle and appends anintutic.rulesection with the entrypoint, the ABI (opa) and the risk tier - Loads it as the proxies will and refuses one they would refuse, such as a policy needing a builtin Intutic does not provide, which it names
- Writes the module and prints its size and SHA-256
Install the result with intutic policy install. See Rego policies.
intutic rules test
Evaluate a Rego rule against sample inputs locally, through the same Rego host the proxies use.
intutic rules test <module> --input <file...>Options:
| Option | Description |
|---|---|
--input <file...> | JSON file(s), each holding one input document or an array of {"name", "input", "expect"} cases (required) |
Prints each case's decision (ALLOW, DENY, HOLD or REASK), reason and risk tier. expect is optional, and one of allow, deny, hold or reask in lowercase; the command exits 1 when a case gets a decision other than the one it expects, or when evaluation fails. The rule runs under the proxies' instruction budget, so a rule that would run out of it in the proxy fails here too. A native rule is refused, with a pointer to intutic policy test.
intutic exec
Execute a command wrapped with Intutic proxy environment variables.
intutic exec -- <command> [args...]
intutic exec --sandbox -- <command> [args...]Arguments:
| Argument | Description |
|---|---|
command... | Command and arguments to execute (e.g. -- claude) |
Options:
| Option | Description |
|---|---|
--sandbox [kind] | Run the agent in an isolated sandbox instead of directly on the host. kind is oci (default) or firecracker. See Sandboxed Execution for what each backend actually isolates and requires. |
--sandbox-image <image> | Sandbox image — must contain the agent, nftables, and capsh. Default: intutic/sandbox:<CLI version>, built locally from the Dockerfile shipped with the CLI on first use; it has no agent, so extend it (Sandboxed Execution). intutic/sandbox:<CLI version>-node adds Node.js and npm, the base for Node agents such as Claude Code, and is built on first use the same way. |
--sandbox-memory <size> | Sandbox memory cap, e.g. 2g. Default: 2g. |
--sandbox-cpus <n> | Sandbox CPU cap. Default: 2. |
--sandbox-pids <n> | Sandbox max process count. Default: 512. |
--sandbox-allow <cidrs> | Comma-separated extra destination CIDRs the sandbox may reach beyond the proxy and DNS. |
If the workspace's sandbox requirement is set to Require (Settings → Security → Sandboxed Execution) and --sandbox is omitted, the command refuses to run rather than executing ungoverned on the host.
What it does: Injects the proxy environment into the child process, then spawns it with inherited stdio and exits with the child's exit code. The injected variables cover the competing SDK conventions:
| Variable | Consumers |
|---|---|
OPENAI_API_BASE | LiteLLM, LangChain, CrewAI, ADK, Aider |
OPENAI_BASE_URL | OpenAI Python SDK v1+, Pydantic-AI, Agent SDK |
OPENAI_API_BASE_URL | OpenWebUI |
OPENAI_HOST | Goose (host only, no /v1) |
ANTHROPIC_BASE_URL | Claude Code, Anthropic SDK (host only) |
OPENAI_API_KEY / ANTHROPIC_API_KEY / INTUTIC_API_KEY | The workspace API key, when you are logged in |
INTUTIC_GRAPH_ID / INTUTIC_NODE_ID / INTUTIC_PARENT_ID / INTUTIC_DEPTH | A nested intutic exec and the Clawde SDK: the agent graph this agent belongs to |
ANTHROPIC_CUSTOM_HEADERS | Claude Code: the same identity as X-Intutic-* headers, after any headers already set |
The base-URL variables point at the local proxy, http://localhost:4000, or at INTUTIC_PROXY_URL when it is set; inside --sandbox they point at the host the proxy runs on. Each carries the agent-graph identity as a path prefix (/_i/<graph>/<node>/<parent>/<depth>), which the proxy strips before routing; the OPENAI_* URLs other than OPENAI_HOST end in /v1.
Without a login (open core, with intutic start running) only the base URLs change: the agent keeps the provider keys already in its environment, and the standalone proxy passes them through to the provider. With --sandbox, OPENAI_API_KEY and ANTHROPIC_API_KEY are handed into the container for the same reason.
Logged in, the key variables are set to the workspace key, the workspace's sandbox requirement applies, and a sandboxed run is recorded as a session.
Examples:
intutic exec -- claude
intutic exec -- aider --model openai/gpt-4o
intutic exec -- python my_agent.pyintutic chaos run
Run a chaos experiment: the agent with a known fault injected, in the sandbox, scored. See Chaos Engineering for Agents.
intutic chaos run <file> [--sandbox-image <image>] [--out <report.json>] [--keep]Arguments:
| Argument | Description |
|---|---|
file | Experiment file (YAML) |
Options:
| Option | Description |
|---|---|
--sandbox-image <image> | Sandbox image; must contain the agent. Overrides the experiment's sandbox_image. Default: the intutic exec --sandbox image. For a Node agent, extend intutic/sandbox:<CLI version>-node (Bring your agent). |
--out <report.json> | Where to write the JSON report. Default: intutic-chaos/report-<name>-<timestamp>.json under the OS temp directory. The path is printed. |
--keep | Keep each repetition's git worktree instead of removing it. |
Refuses to start without a clean git working tree (each repetition is a fresh worktree of HEAD) or without an available sandbox backend; it never runs the agent on the host. Runs repeat baseline repetitions, then repeat faulted ones, each behind a dedicated proxy on a free port. Each worktree gets the project's generated gates, its Claude Code, Codex and Cursor project hook settings and the policy snapshot, with the project's path rewritten to /work; the output names what was carried in and warns when the project has no gates (Bring your agent). Exits 0 when the run is scored, 1 when it was aborted or refused to start (or the file is invalid), 2 when the run is invalid (the baseline failed verify).
intutic chaos validate
Check a chaos experiment file against the experiment schema and print each error with the path of the field.
intutic chaos validate <file>| Argument | Description |
|---|---|
file | Experiment file (YAML) |
Exits 1 when the file is invalid.
intutic chaos list
Print the fault catalog: each fault, the component that injects it (proxy, MCP proxy or gate) and its safety class (fail-safe or mutating), and where the example experiments are.
intutic chaos listintutic env persist
Persist ANTHROPIC_BASE_URL and OPENAI_BASE_URL at the OS level so new terminals and applications reach the proxy.
intutic env persist [--proxy-url <url>]Options:
| Option | Description | Default |
|---|---|---|
--proxy-url <url> | Proxy base URL both variables are set to | http://localhost:4000 |
What it does:
Sets exactly two variables, ANTHROPIC_BASE_URL and OPENAI_BASE_URL, both to --proxy-url. It sets no API keys and none of the other variables intutic exec injects. The mechanism depends on the OS:
| OS | Mechanism | Scope |
|---|---|---|
| macOS | launchctl setenv | Every application launched afterwards, including GUI apps, until you log out or restart |
| Linux (as root) | Writes KEY="<url>" lines to /etc/environment, replacing any earlier lines for the two variables | System |
| Linux (otherwise) | Appends export KEY="<url>" lines to ~/.bashrc, each tagged with an # intutic-env-<KEY> marker; a re-run replaces the earlier lines | User |
| Windows | setx | User |
Terminals that are already open keep their old environment until you restart them or re-source your shell profile. On any other platform the command exits with status 1.
This is opt-in on purpose: on macOS it reaches every GUI application you start afterwards. To route a single command instead, use intutic exec.
Examples:
intutic env persist
intutic env persist --proxy-url http://localhost:8080intutic env clear
Remove the variables written by intutic env persist.
intutic env clearNo options.
What it does:
Removes ANTHROPIC_BASE_URL and OPENAI_BASE_URL: launchctl unsetenv on macOS, and the values in HKCU\Environment on Windows. On Linux it deletes the marked lines from ~/.bashrc, leaving the rest of the file exactly as it was, and, when run as root, the two variables' lines from /etc/environment. Running it when nothing is set is not an error. Already-open terminals keep the old values until restarted.
intutic enforce
Manage the mandatory default-deny egress firewall — makes the governing proxy non-optional by dropping outbound traffic to everything except the proxy, DNS, and operator-declared infrastructure. Where Network Egress Control governs traffic the proxy sees, intutic enforce closes the gap where an agent simply doesn't route through the proxy at all: with it applied, there is no other way out.
intutic enforce <action> [options]Actions:
| Action | Privilege | What it does |
|---|---|---|
generate | None | Prints the platform firewall ruleset without applying it. |
apply | Root | Applies the default-deny egress firewall. All egress except the proxy, DNS, and --allow infrastructure is dropped. |
remove | Root | Removes the Intutic egress firewall. |
status | None | Reports whether the egress firewall is currently applied. |
report Cloud | None (needs intutic login) | Reports the locally recorded enforcement state (firewall, CA-trust, system-hooks posture) to the control plane. For when apply/remove ran elevated and couldn't reach stored credentials. |
Options (apply/remove/status/generate):
| Option | Description |
|---|---|
--port <port> | The proxy's listener port to permit. Default: 4000; neither PORT nor INTUTIC_PROXY_URL is read, so pass it when the proxy listens elsewhere. |
--uid <uid> | uid the proxy runs as, exempted from the deny. Defaults to you: the user the command runs as, or under sudo the user who invoked sudo (SUDO_UID), not root. Pass it when the proxy runs as a different account. |
--allow <cidrs> | Comma-separated extra destinations to permit (control plane, private registries, etc.), each an IP address or CIDR block. A hostname is refused before anything is applied: resolve it to its address range first. |
--no-dns | Also deny outbound DNS — only if a local resolver serves the host. |
--platform <os> | Target ruleset platform: linux, macos, or windows. Defaults to the current OS. |
What it does:
Implemented in the intutic-proxy binary's own enforce subcommand (platform-aware: nftables or iptables on Linux, pf on macOS); the CLI command is a thin, discoverable wrapper around it. apply/remove change the host firewall and need root — re-run with sudo if it fails with a permission error. After a successful apply/remove, the CLI re-queries status while still elevated and best-effort reports the result to the control plane, so an admin can see whether enforcement is actually active on a given machine without SSHing into it.
Examples:
# See what would be applied, without changing anything
intutic enforce generate
# Apply, permitting an internal network and a package registry's address range too
sudo intutic enforce apply --allow 10.0.0.0/8,203.0.113.0/24
# Check whether it's currently active
intutic enforce status
# Remove it
sudo intutic enforce removeintutic daemon install
Install sync-daemon as a system service (auto-starts on login, restarts on any exit).
intutic daemon install --workspace-id <id> --api-key <key> [options]
intutic daemon install --proxy [--port <port>] [--valkey-url <url>] [--upstream-url <url>]Also available as the top-level shortcut intutic install-daemon, with the same options and defaults.
Options:
| Option | Description | Default |
|---|---|---|
--workspace-id <id> | Workspace ID, e.g. wk_xxxx (required unless --proxy) | — |
--api-key <key> | Workspace API key, e.g. vk_xxxx (required unless --proxy) | — |
--control-plane-url <url> Cloud | Control plane the sync-daemon or MCP daemon connects to, written into the service | Resolved as in Choosing a control plane: INTUTIC_CONTROL_PLANE_URL (or INTUTIC_DEV=1), then a workspace initialized with intutic init --dev, then the URL saved by intutic login; this release has no default |
--binary-path <path> | Path to the intutic CLI binary; with --proxy, an absolute path to intutic-proxy | (current process; with --proxy, the launcher's pinned binary, then intutic-proxy on PATH) |
--dry-run | Print what would be done without writing files | — |
--system | Install as a system-level service (LaunchDaemon on macOS, systemd system unit on Linux) | — |
--mcp | Install the MCP proxy daemon instead of the sync-daemon | — |
--proxy | Install the standalone intutic-proxy binary as a service — no workspace or key needed | — |
--port <port> | With --proxy: proxy listen port (PORT) | The port of INTUTIC_PROXY_URL, else 4000 |
--valkey-url <url> | With --proxy: Valkey to attach to (VALKEY_URL); omitted, the unit sets INTUTIC_STANDALONE=1 | — |
--upstream-url <url> | With --proxy: upstream LLM provider base URL (UPSTREAM_URL) | — |
Service files written:
- macOS:
~/Library/LaunchAgents/ai.intutic.sync-daemon.plist(KeepAlive: true) - Linux:
~/.config/systemd/user/intutic-sync-daemon.service(Restart=always) - With
--proxy:~/Library/LaunchAgents/ai.intutic.proxy.plist/~/.config/systemd/user/intutic-proxy.service, running the binary with the same environmentintutic startsets. The binary path must be absolute — neither launchd nor systemd searchesPATH.
Because the service restarts on any exit, stopping it requires intutic daemon stop, intutic daemon uninstall, or launchctl unload.
intutic daemon uninstall
Remove the sync-daemon system service and stop it permanently.
The hook gates refuse this command when an agent runs it: run it yourself.
intutic daemon uninstall [options]Also available as the top-level shortcut intutic uninstall-daemon, with the same options.
Options:
| Option | Description |
|---|---|
--dry-run | Print what would be done without writing files |
--system | Uninstall the system-level service |
--mcp | Uninstall the MCP proxy daemon instead of the sync-daemon |
--proxy | Uninstall the standalone intutic-proxy service instead of the sync-daemon |
intutic daemon status
Show sync-daemon system service status. With --proxy or --mcp, the same for the standalone proxy service or the MCP proxy daemon.
intutic daemon status
intutic daemon status --proxy
intutic daemon status --mcpOptions:
| Option | Description |
|---|---|
--proxy | Show the standalone intutic-proxy service installed by daemon install --proxy instead of the sync-daemon. |
--mcp | Show the MCP proxy daemon instead of the sync-daemon. |
intutic daemon start
Start and load the sync-daemon system service. With --proxy or --mcp, the same for the standalone proxy service or the MCP proxy daemon.
intutic daemon start
intutic daemon start --proxy
intutic daemon start --mcpOptions:
| Option | Description |
|---|---|
--proxy | Start the standalone intutic-proxy service installed by daemon install --proxy instead of the sync-daemon. |
--mcp | Start the MCP proxy daemon instead of the sync-daemon. |
intutic daemon stop
Stop and unload the sync-daemon system service. With --proxy or --mcp, the same for the standalone proxy service or the MCP proxy daemon.
The hook gates refuse this command when an agent runs it: run it yourself.
intutic daemon stop
intutic daemon stop --proxy
intutic daemon stop --mcpOptions:
| Option | Description |
|---|---|
--proxy | Stop the standalone intutic-proxy service installed by daemon install --proxy instead of the sync-daemon. |
--mcp | Stop the MCP proxy daemon instead of the sync-daemon. |
intutic rollback
List or restore file pre-images captured when a guard flagged a call and let it proceed. This is the restore half of the mechanism — the capture half runs automatically inside the generated harness hook when a warn-tier guard fires, if capture is enabled.
intutic rollback # list captured pre-images
intutic rollback --id <id> # restore oneOptions:
| Option | Description |
|---|---|
--list | List captured pre-images. The default when --id is omitted. |
--id <id> | Restore the named pre-image. |
Capture is opt-in and narrowly scoped — set "captureRollbackPreImages": true in .intutic/config.json. It's off by default because it stores copies of flagged files locally. It only captures on the warn enforcement tier: a KILLed call never executes (nothing to revert), and a require-tier violation is refused before it runs — capture exists for the one case where a call was flagged and allowed to proceed anyway, so there's a "before" worth keeping. Bounded to 2 MiB per file and 50 retained entries.
What it does:
- With no
--id: lists every captured pre-image (id, capture time, tool, target path, byte size or "file did not exist") and prints the restore command for each. - With
--id <id>: restores exactly that pre-image and nothing else — there is no--alland no implicit "latest". Before restoring, the current contents of the target are themselves captured as a new pre-image, so the restore is itself undoable. The restore is appended to the same.intutic/events/hook-events.jsonllog the gate writes to (tool_reverted), so the audit trail reads "flagged → allowed → reverted", not a file that silently changed back. If the pre-image's stored blob was evicted by the retention ceiling, the command refuses rather than performing a partial restore.
Examples:
# See what's available to restore
intutic rollback
# Restore a specific one (id comes from the list above)
intutic rollback --id a1b2c3d4e5f60718Environment variables
Environment variables the CLI, and the hook gates and proxy it sets up, read. Command-line flags take precedence where both exist.
| Variable | Read by | Effect |
|---|---|---|
INTUTIC_CONTROL_PLANE_URL | Every command that calls a control-plane API | The control plane to use, ahead of a workspace initialized with intutic init --dev and the one saved by intutic login, and behind a --control-plane-url or --dev flag. See Choosing a control plane. |
INTUTIC_DEV | Every command that calls a control-plane API | 1 targets the local control plane at http://localhost:3001, the same as --dev, unless INTUTIC_CONTROL_PLANE_URL is set. Any other value is ignored. |
INTUTIC_PROXY_URL | intutic exec, start, connect, budget, doctor, daemon install --proxy, enterprise install, and the setup output of init and connect | Base URL of the local proxy, default http://localhost:4000. Its port is the one every command uses: start, connect and daemon install --proxy run the proxy there unless --port says otherwise, and budget and doctor probe it there. exec points the child process's SDK variables at it. enterprise install uses it when --proxy-url is not given. init and connect print it as your gateway endpoint (with /v1 appended). The shell's PORT is not read. intutic enforce reads neither: its --port defaults to 4000. |
VALKEY_URL | intutic start, intutic connect | Valkey/Redis the proxy uses. start passes it through only when a Valkey is reachable on --valkey-port; otherwise it uses redis://127.0.0.1:<valkey-port>. connect defaults to redis://127.0.0.1:6379. |
CONTROL_PLANE_URL | intutic start | When set and no Valkey is available, start does not force standalone mode; the proxy treats the run as a managed deployment and requires Valkey. The CLI does not use it to choose a control plane. |
INTUTIC_SNAPSHOT_RULES | Hook gates, intutic policy snapshot, intutic doctor | Path of the policy snapshot file the gates enforce. Default ~/.intutic/hooks/policy-snapshot.rules. policy snapshot writes into this path's directory and always names the file policy-snapshot.rules (it warns if your path uses another name); doctor checks this path. |
INTUTIC_GUARD_DISABLE | Hook gates | 1 makes the gates skip the snapshot's destructive-command rules. The built-in protections (protected paths, bypass guards) and your workspace's own SOP block rules still apply. Every gated tool call while it is set is recorded as a guards_disabled event; once intutic connect uploads those events, the control plane opens a HIGH-severity incident for each affected session. |
INTUTIC_SKIP_GLOBAL_HOOKS | intutic connect (Claude Code hooks) | Any non-empty value stops the sync daemon from writing Intutic's hooks and deny rules into ~/.claude/settings.json. The project's .claude/settings.json is still written. |
INTUTIC_OPA_BIN | intutic rules build | The OPA binary used to compile Rego. Default opa on the PATH. |
INTUTIC_WASM_DIR | intutic policy install, intutic policy list-local, the proxy | Directory for local WASM rules. Default ~/.intutic/wasm; a leading ~/ is expanded. Set it the same way for the CLI and the proxy. |
INTUTIC_FC_KERNEL | intutic exec --sandbox firecracker | Path to the guest kernel image. Required; no default. |
INTUTIC_FC_ROOTFS | intutic exec --sandbox firecracker | Path to the guest root filesystem image containing your agent. Required; no default. |
INTUTIC_FC_GUEST_KEY | intutic exec --sandbox firecracker | Path to the private ssh key the rootfs's sshd accepts for root; the agent runs in the guest over ssh. Required: without it, or if the file cannot be read, the run fails with exit 2 before the microVM is set up. |
INTUTIC_FC_TAP | intutic exec --sandbox firecracker | Host tap device name. Default tap-intutic. |
INTUTIC_FC_GUEST_IP | intutic exec --sandbox firecracker | Guest IP on the tap link. Default 172.16.0.2. |
INTUTIC_FC_HOST_IP | intutic exec --sandbox firecracker | Host IP on the tap link; the guest reaches the proxy here. Default 172.16.0.1. |
INTUTIC_FC_PREFIX | intutic exec --sandbox firecracker | Prefix length of the tap link. Default 30. |
INTUTIC_FC_VCPUS | intutic exec --sandbox firecracker | Guest vCPU count. Default 1. |
INTUTIC_FC_MEM | intutic exec --sandbox firecracker | Guest memory in MiB. Default 512. |
The control plane itself is chosen as described in Choosing a control plane.