sysknife CLI Reference

sysknife is the command-line interface to the SysKnife daemon. It turns a natural-language intent into a risk-labelled plan, asks for approval where needed, and streams execution output in real time.

If you want SysKnife inside Claude Code / Cursor / Codex CLI instead, see the main README and run npx sysknife-setup. Both paths share the daemon, the audit chain, and the typed-action set.

sysknife CLI demo


Quick start

# Check that the daemon is reachable
sysknife doctor

# Plan + execute a single intent
sysknife "check disk usage"

# Preview the plan without executing
sysknife --dry-run "list running containers"

# Open the interactive REPL
sysknife

Synopsis

sysknife [GLOBAL FLAGS] [SUBCOMMAND | INTENT WORDS...]

When no subcommand is given and no intent words are provided, sysknife starts an interactive REPL.


Subcommands

sysknife <intent>

Plan and (optionally) execute a natural-language intent.

sysknife "check disk usage"
sysknife check disk usage            # words are joined — same result
sysknife "list running containers"
sysknife "is firewalld active?"
sysknife "layer vim via rpm-ostree"

What happens:

  1. A spinner appears while the LLM plans (Thinking…Querying …Proposing plan…).
  2. The coloured plan is printed — each step shows a risk badge (● low / ● medium / ● HIGH), the action name, and a summary.
  3. If any step requires approval, you are prompted. HIGH-risk steps always require confirmation regardless of --yes.
  4. Execution streams output line by line with a prefix; a / result icon is printed after each step.

sysknife doctor

Check daemon connectivity and print the resolved configuration.

sysknife doctor
sysknife --json doctor      # machine-readable

Exit code 0 on success, non-zero if the daemon is unreachable.

Sample output:

✓  daemon ok
  socket    /run/sysknife/daemon.sock
  host      my-silverblue
  provider  anthropic
  model     claude-sonnet-4-6

sysknife history

Query past SysKnife execution history.

sysknife history
sysknife history --limit 50
sysknife history --status failed
sysknife history --action InstallPackages
sysknife history --since 2026-04-01T00:00:00Z
sysknife history --status succeeded --limit 5 --since 2026-04-10T00:00:00Z

Flags:

FlagDefaultDescription
--limit N20Maximum entries to return
--status STATUSFilter by job status (succeeded, failed, canceled, …)
--action ACTIONFilter by action name (e.g. InstallPackages)
--since DATETIMEOnly entries after this UTC RFC 3339 timestamp

sysknife approve

Issue a one-time receipt for a transaction returned by the MCP sysknife_plan tool. This command requires an interactive terminal. It first loads and displays the daemon-authoritative action, risk, summary, and proposed change so an agent cannot substitute an opaque transaction ID. It mints the receipt only after confirmation; high-risk approvals require typing the exact action name.

sysknife approve 018f2c9d-...
sysknife --json approve 018f2c9d-...

Give the printed approval_receipt to the MCP client for that exact step. The receipt expires after 15 minutes, is bound to the preview's action and params, and is consumed on first execution. A chat message saying "approved" is not a receipt.


sysknife audit

Inspect and anchor the tamper-evident, Ed25519-signed audit chain the daemon writes for every executed action.

sysknife audit verify

Verify the audit chain. Exits 0 if intact, 1 if any row is broken (tampered), 2 if the chain cannot be verified (missing key, unreadable database).

sysknife audit verify
sysknife audit verify --json
sysknife audit verify --pubkey /etc/sysknife/audit-key.pub
FlagDescription
--jsonMachine-readable JSON report instead of human text
--pubkey FILEVerify with only the exported public key (<audit-key>.pub), no private key: the third-party / auditor path. Works with SQLite and PostgreSQL and proves the chain without signing access.

sysknife audit checkpoint

Sign the current chain tip as a checkpoint and anchor it to an external append-only database, then verify all anchored checkpoints against the local chain. Anchoring the tip off-box is what makes tail-truncation and rewrite of the local chain detectable.

# credentials via env (preferred; keeps them off the command line)
SYSKNIFE_CHECKPOINT_DB=postgres://user@host/db sysknife audit checkpoint
# or explicitly
sysknife audit checkpoint --db postgres://user@host/db
FlagDescription
--db URLPostgres URL of the append-only checkpoint database. Prefer SYSKNIFE_CHECKPOINT_DB so credentials are not exposed via ps / shell history.

Each row is signed with Ed25519; verification uses the public key, so an auditor can verify without the ability to forge. See configuration for the key and checkpoint-DB env vars.


sysknife completions <shell>

Print a shell completion script to stdout.

sysknife completions bash   >> ~/.bashrc
sysknife completions zsh    >> ~/.zshrc
sysknife completions fish   >> ~/.config/fish/completions/sysknife.fish

Supported shells: bash, zsh, fish, elvish, powershell.


sysknife mcp-server

Start an MCP (Model Context Protocol) server over stdio, so Claude Code, Claude Desktop, Cursor, Codex, and any other MCP-capable agent can drive SysKnife.

sysknife mcp-server

It exposes five tools backed by the SysKnife daemon: sysknife_plan, sysknife_execute, sysknife_history, sysknife_doctor, and sysknife_audit_verify. Planning and execution stay behind the same approval interlock as the CLI — sysknife_plan returns typed steps with daemon-issued transaction IDs, and each step still requires an explicit sysknife approve <transaction-id> in a real terminal before it can run.

Register it with your agent by pointing it at the binary, e.g. in claude_desktop_config.json:

{ "mcpServers": { "sysknife": { "command": "sysknife", "args": ["mcp-server"] } } }

npx sysknife-setup writes this configuration for the common clients automatically.


REPL (no arguments)

sysknife

Starts an interactive session. Each line is treated as a natural-language intent and planned + executed in sequence.

Key bindings:

KeyAction
↑ / ↓Navigate command history
Ctrl+RReverse incremental history search
Ctrl+A / Ctrl+EJump to line start / end
Ctrl+WDelete word before cursor
Ctrl+CCancel current line (does not exit)
Ctrl+DExit the REPL
exit / quitExit the REPL

History is persisted to ~/.local/share/sysknife/history between sessions.


Global flags

All flags apply to every subcommand and to free-form intents.

FlagDescription
--yesAuto-approve LOW-risk steps. With --max-risk medium, also approves MEDIUM. HIGH always requires human confirmation.
--max-risk LEVELAbort if the plan contains any step above this ceiling. Values: low, medium, high.
--non-interactiveFail immediately (exit 3) if any step would require interactive approval. Use in scripts and CI.
--dry-runPrint the plan and exit without executing anything.
--step-by-stepPrompt for approval before each individual step instead of once for the whole plan.
--jsonEmit NDJSON to stdout — one JSON object per event (plan, preview, result). All colour and spinner output is suppressed. Safe to pipe.
--timeout SECSHard wall-clock timeout in seconds. Aborts the whole operation if exceeded.
--log-to FILETee all stdout output to FILE in addition to the terminal. Appends if the file exists.

Exit codes

CodeMeaning
0Success
1Plan or step refused — you rejected it, it exceeded the configured risk ceiling, or approval was required but the session is non-interactive
2Execution failed — the action ran but returned an error (also returned when --timeout expires)
3Planning failed — LLM error, provider unreachable, or the intent could not be turned into a plan
4Configuration or daemon error — invalid configuration, or the daemon could not be reached

Subcommands with their own semantics (for example sysknife audit verify) pass through their own exit code.


Environment variables

LLM provider

sysknife auto-detects between Anthropic and local Ollama from the presence of ANTHROPIC_API_KEY. Every other provider must be selected explicitly with SYSKNIFE_LLM_PROVIDER (and its matching API key set).

VariableDescription
SYSKNIFE_LLM_PROVIDERForce a provider: anthropic, openai, gemini, ollama, groq, deepseek, mistral, xai
SYSKNIFE_LLM_MODELOverride the model name for the selected provider
ANTHROPIC_API_KEYUse the Anthropic provider (default model: claude-sonnet-4-6)
OPENAI_API_KEYUse the OpenAI provider (default model: gpt-4.1)
GEMINI_API_KEYUse the Gemini provider (default model: gemini-2.0-flash)
GROQ_API_KEYUse the Groq provider (default model: llama-3.3-70b-versatile)
DEEPSEEK_API_KEYUse the DeepSeek provider (default model: deepseek-chat)
MISTRAL_API_KEYUse the Mistral provider (default model: mistral-large-latest)
XAI_API_KEYUse the xAI provider (default model: grok-3)
SYSKNIFE_ANTHROPIC_URLOverride the Anthropic base URL (default: https://api.anthropic.com)
SYSKNIFE_OLLAMA_URLOverride the Ollama base URL (default: http://localhost:11434)
SYSKNIFE_BRAIN_MAX_TURNSPlanning loop turn limit — integer ≥ 1 (default: 10)
SYSKNIFE_OLLAMA_THINKSet true/false to override thinking-mode detection for Ollama models

Auto-detection (when SYSKNIFE_LLM_PROVIDER is not set):

  1. ANTHROPIC_API_KEY present and non-empty → anthropic
  2. Otherwise → ollama (must be running locally)

The other providers (openai, gemini, groq, deepseek, mistral, xai) are not auto-detected from their API-key variables. To use one, set SYSKNIFE_LLM_PROVIDER to its name and provide the matching key from the table above.

Daemon socket

VariableDescription
SYSKNIFE_SOCKETDaemon socket the CLI dials (unix://, vsock://, or a bare path). Falls back to the same resolution as SYSKNIFE_LISTEN_URI: $XDG_RUNTIME_DIR/sysknife/daemon.sock, then /tmp/sysknife-$UID.sock as a last resort. Production deployments set this via the systemd unit to /run/sysknife/daemon.sock.

Scripting and CI

For non-interactive use (scripts, CI pipelines), combine --json, --non-interactive, and --max-risk:

# Plan only — parse the JSON to inspect before executing
PLAN=$(sysknife --dry-run --json "check disk usage")
echo "$PLAN" | jq '.plan.steps[].action'

# Execute automatically up to medium risk; fail if anything higher appears
sysknife --yes --max-risk medium --non-interactive "list layered packages"

# Full pipeline with a timeout and log
sysknife --yes --max-risk low --non-interactive --timeout 60 \
     --log-to /var/log/sysknife/run.log \
     "check disk usage"

The --json output schema:

// Planning output
{ "plan": { "intent": "…", "summary": "…", "steps": [
    { "action": "GetDiskUsage", "summary": "…", "risk": "low", "params": {} }
] } }

// Per-step preview (before execution)
{ "summary": "…", "risk_level": "low", "reboot_required": false,
  "warnings": [], "request_hash": "…", … }

// Per-step result (after execution)
{ "status": "succeeded", "summary": "…", "job_id": "…",
  "needs_reboot": false, "warnings": [], … }

Examples

# Check if any services are failing
sysknife "which systemd services are failed?"

# See recent SysKnife activity
sysknife history --limit 10

# Dry-run a destructive action to inspect the plan
sysknife --dry-run "layer vim via rpm-ostree"

# Execute step-by-step with manual approval of each action
sysknife --step-by-step "update system"

# Non-interactive: fail fast if the plan needs a human
sysknife --non-interactive --max-risk low "check memory pressure"

# Get JSON output and parse with jq
sysknife --dry-run --json "list containers" | jq '.plan.steps[].action'

# Override the LLM for a single run
SYSKNIFE_LLM_PROVIDER=openai OPENAI_API_KEY=sk-... sysknife "check disk usage"

# Use a local Ollama model
SYSKNIFE_LLM_PROVIDER=ollama SYSKNIFE_LLM_MODEL=llama3.2:3b sysknife "list services"

Shell completion setup

Run once per shell:

# bash (add to ~/.bashrc)
eval "$(sysknife completions bash)"

# zsh (add to ~/.zshrc)
eval "$(sysknife completions zsh)"

# fish
sysknife completions fish | source