CLI reference
The writ CLI wraps the API. Install it:
pip
curl
Set WRIT_BASE to point at a different gate, WRIT_SPONSOR_TOKEN to avoid
passing --sponsor-token every time.
Keys, login, and config
Credentials are resolved in this order: explicit flag > environment variable
(WRIT_API_KEY, WRIT_SPONSOR_TOKEN, WRIT_BASE) > ~/.writ/config.json.
Policy
Repo scanner
The scanner parses Python with the AST: ORM and DB calls, HTTP clients
and third-party SDKs (Stripe, Twilio, Resend, SendGrid), file writes,
emails, queues, deferred tasks (Celery/RQ/Dramatiq), agent tool
registries (LangChain/CrewAI/OpenAI), and AWS SDK writes generated from
the botocore service models. SELECT queries are not flagged. Verbs are
inferred as <domain>.<action> from the file path and function name
(issue_refund in payments/ becomes payments.refund). The scan
report also prints a risk profile (db×2, money×1, fs×0, ...) and top
ungated sites so you can triage before applying gates. Test files and
virtualenvs are skipped.
TS/JS findings from non-product paths — docs/, scripts/, sandbox/,
examples/, benchmark/ and demo/ directories, plus build-tooling
files (gulpfile.js, Gruntfile.js, webpack.config.*,
rollup.config.*, vite.config.*, and equivalents) — are suppressed
from the report by default so first scans show product code, not docs
and build tooling. Nothing is dropped silently: the report prints the
suppressed count per path class and names every suppressed file, and
the signed manifest records the same breakdown under
findings.tsjs.suppressedNonProduct. --include-non-product reports
them as normal findings again. See Scanner for the full
story.
Without the polyglot extra, writ scan does not silently skip TS/JS: the
report prints a prominent warning block naming the unscanned file count and
the exact install command (pip install 'pywrit[polyglot]'), in the normal
report and in writ scan --score, and the signed manifest records the state
under findings.tsjs.notScanned (reason, extra, files,
installCommand).
Go is scan-only too, behind the same extra: a first detection family
(database/sql Exec / ExecContext, GORM Create / Save /
Update / Updates / Delete, HTTP client writes and http.NewRequest
with a write method, generated-client
<client>.<Resource>.<New|Update|Delete|Create>), reported as go files scanned / go write sites lines and under findings.go in the signed
manifest. _test.go files and vendor/ trees are skipped. Without the
extra, Go files are counted in the same warning block (recorded under
findings.go.notScanned), and writ scan --apply never rewrites .go
files. Package-level generated clients (charge.New(...), the pre-v87
stripe-go shape) are not detected yet. See Scanner for
the full story.
Every scan report ends with a pointer to the Writ GitHub App (install:
https://github.com/apps/writ-scanner, guide:
https://docs.withwrit.com/git-hub-app), which runs the scan on every
push and pull request with check runs and history in the portal; the
signed manifest carries the same pointer under githubApp.
CI attestation
The decision loop
Identity directory
Custom verbs
Per-principal policy overrides
API keys, badge, vault, stats
Gated execution
GitHub App
Doctor, templates, and MCP setup
GitHub Action
This installs pywrit, scans the repo, and submits a signed manifest on every push.
Step-up notifications, explain, and completions
Kill switch
Audit log
Agent Action Report
See Audit log for what the report aggregates and how the money totals are derived.