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: denyinit 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/payoutsTaint-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 selectsstrict—--yesmeans "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:
| Condition | posture | selected_by |
|---|---|---|
--taint-denial-posture strict, egress tool(s) found | strict | flag |
--taint-denial-posture strict, no egress tools found | redact_permit (downgraded, loud warning) | flag |
--taint-denial-posture redact-and-permit | redact_permit | flag |
--yes / -y (no posture flag) | redact_permit | default_yes |
stdin not an interactive TTY (piped, CI, < /dev/null), no --yes, no posture flag | redact_permit | default_non_interactive |
interactive TTY, no egress tools found, no --yes, no posture flag | redact_permit | default_no_answer |
interactive TTY, egress tools found, answered y/yes/strict/s | strict | prompt |
| interactive TTY, egress tools found, any other/empty answer | redact_permit | prompt |
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_permitThe 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 selectsstrict.
Gotchas
- Framework detection and tool discovery are separate passes. A minimal single-file script
using
langchain_core.toolscan printFramework detected: unknownwhile still correctly discovering every@tool-decorated function by AST. Don't read "unknown" as a discovery failure — check theTools discovered:line. - Every rule starts as
allow(or the profile's chosen effect) —initnever inventsreview/blockrules from a plain repo scan; you add those by editing the file. .mjsfiles (common for ESM LangChain.js agents) are scanned for tool calls, same as.js/.py/.ts.

