raxit
CLI

raxit init

raxit init -- scaffold a security.yaml from a repo scan.

raxit init scans your repo for tool-calling code, then writes a starting .raxit/security.yaml — the one file you edit to govern the agent.

Usage

$ raxit init
✓ Framework detected: unknown
✓ Tools discovered: 3 — calc, post_to_webhook, read_customer_db
✓ .raxit/security.yaml written
✓ Agent id: default-agent (use --agent default-agent, or edit agent: in security.yaml)
✓ Policy compiler ready (Cedar stays internal)
taint-denial posture: redact_permit (selected_by=default_non_interactive)
⚠ Taint-Denial Posture: redact-and-permit (default). Deny-on-taint NOT enabled — a tainted
session may still reach egress tools (boundary redaction applies, but nothing denies). Opt in
with: raxit init --taint-denial-posture strict
Next steps:
  edit .raxit/security.yaml   tune the generated rules
  raxit plan                  preview the decision changes
  raxit apply                 make them live (enforce mode)

The taint-denial posture: line (stdout) and the notice (stderr) print on every init run — see "Taint-Denial Posture" below for why, and what changes when you opt into strict.

The generated .raxit/security.yaml allow-lists every discovered tool by name and adds one test per rule plus a default-deny test:

apiVersion: raxit.security/v1
agent: default-agent
default: block
taint_denial:
    posture: redact_permit
    selected_by: default_non_interactive
rules:
    - effect: allow
      resource: calc
    - effect: allow
      resource: post_to_webhook
    - effect: allow
      resource: read_customer_db
tests:
    - name: calc is permitted
      action: calc
      expect: permit
    - name: unknown_tool is denied (default-deny)
      action: unknown_tool
      expect: deny

init also writes .raxit/config.json (agent id, framework, audit/warrants paths) and an empty .raxit/warrants.json.

--demo <profile>

raxit init --demo payments-bot scaffolds a canonical 5-tool example that exercises all three rule effects in one file (allow, review, block) plus the implicit default-deny:

$ raxit init --demo payments-bot
✓ Framework detected: unknown
✓ Tools discovered: 5 — read_file, search_docs, send_email, stripe/payouts, stripe/refund
✓ .raxit/security.yaml written
✓ Agent id: payments-bot (use --agent payments-bot, or edit agent: in security.yaml)
✓ Policy compiler ready (Cedar stays internal)
rules:
    - effect: allow
      resource: read_file
    - effect: allow
      resource: search_docs
    - effect: allow
      resource: send_email
    - effect: review
      resource: stripe/refund
    - effect: block
      resource: stripe/payouts

Taint-Denial Posture

Every init run records an explicit, loud choice of Taint-Denial Posture — whether a tainted session's egress call is denied outright, or only redacted at the boundary. See Taint & the lethal trifecta ("Taint-denial posture" section) for the concept; this section covers how init decides it.

The interactive prompt

When stdin is an interactive TTY, no --taint-denial-posture flag was passed, --yes/-y wasn't set, and the scan found at least one egress-capable tool, init shows a preview and asks — this is the exact, verbatim text:

Discovered 3 egress-capable tool(s) a PII/secret-tainted session could reach:
  - calc                         [likely] network calls in defining file agent.py
  - post_to_webhook              [likely] tool name contains egress verb 'post'
  - read_customer_db             [likely] network calls in defining file agent.py
Enable STRICT deny-on-taint for these tools? Default is redact-and-permit. [y/N]:

Each row is <tool-id> [<confidence>] <evidence> — confidence is certain, likely, or uncertain, and the scanner fails toward over-flagging: if the project has network evidence anywhere, every tool defined in a file that also contains that evidence is listed, even a tool (like calc above) that isn't itself an egress path. Answering y, yes, strict, or s selects strict; anything else (including a bare Enter) selects the default, redact_permit.

Flags that skip the prompt

  • --taint-denial-posture <redact-and-permit|strict> — set the posture directly; never prompts. Any other value is a load-time error: raxit init: --taint-denial-posture "bogus" is unsupported; use redact-and-permit or strict.
  • --yes / -y — accept the default posture (redact_permit) without prompting. Never selects strict--yes means "accept the default," not "accept strict."

Non-interactive behavior — never hangs

init reads stdin only in the one interactive-prompt path above. Every other combination resolves without touching stdin:

Conditionpostureselected_by
--taint-denial-posture strict, egress tool(s) foundstrictflag
--taint-denial-posture strict, no egress tools foundredact_permit (downgraded, loud warning)flag
--taint-denial-posture redact-and-permitredact_permitflag
--yes / -y (no posture flag)redact_permitdefault_yes
stdin not an interactive TTY (piped, CI, < /dev/null), no --yes, no posture flagredact_permitdefault_non_interactive
interactive TTY, no egress tools found, no --yes, no posture flagredact_permitdefault_no_answer
interactive TTY, egress tools found, answered y/yes/strict/sstrictprompt
interactive TTY, egress tools found, any other/empty answerredact_permitprompt

Requesting strict with nothing to actually guard is a defensive downgrade, not a silent no-op — it prints to stderr and still records the real outcome:

⚠ raxit init: strict requested but no egress-capable tool discovered; recorded redact_permit

The generated denyWhenTainted companion rules (strict)

On strict, init appends one co-located block rule per discovered egress-capable tool that already has an allow/review rule — the original allow/review stays, and Cedar's forbid-over-permit makes the new guard win once the session is tainted:

apiVersion: raxit.security/v1
agent: default-agent
default: block
taint_denial:
    posture: strict
    selected_by: prompt
rules:
    - effect: allow
      resource: calc
    - effect: allow
      resource: post_to_webhook
    - effect: allow
      resource: read_customer_db
    - effect: block
      resource: calc
      denyWhenTainted: [PII, SECRET, FINANCIAL, PHI, CREDENTIAL]
    - effect: block
      resource: post_to_webhook
      denyWhenTainted: [PII, SECRET, FINANCIAL, PHI, CREDENTIAL]
    - effect: block
      resource: read_customer_db
      denyWhenTainted: [PII, SECRET, FINANCIAL, PHI, CREDENTIAL]

and the matching stdout/stderr:

taint-denial posture: strict (selected_by=prompt)
⚠ Taint-Denial Posture: STRICT — deny-on-taint ENABLED; 3 egress tool(s) now DENY on the
governed tool.call path once the session is PII/secret-tainted.

strict guards the governed tool.call path — the same path the lethal-trifecta demo exercises through governed_tool. A direct, unwrapped call that bypasses governance entirely is invisible to this (or any) raxit rule.

Flags

  • --demo <profile> — write a canonical example profile instead of scanning the repo.
  • --agent <id> — override the auto-derived agent id.
  • --taint-denial-posture <redact-and-permit|strict> — set the Taint-Denial Posture directly; never prompts. See Taint-Denial Posture above.
  • --yes / -y — accept the default posture without prompting; never selects strict.

Gotchas

  • Framework detection and tool discovery are separate passes. A minimal single-file script using langchain_core.tools can print Framework detected: unknown while still correctly discovering every @tool-decorated function by AST. Don't read "unknown" as a discovery failure — check the Tools discovered: line.
  • Every rule starts as allow (or the profile's chosen effect) — init never invents review/ block rules from a plain repo scan; you add those by editing the file.
  • .mjs files (common for ESM LangChain.js agents) are scanned for tool calls, same as .js/ .py/.ts.

On this page