- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Documented (README)
- !No description
claude mcp add pywrit -- npx -y writ-scan{
"mcpServers": {
"pywrit": {
"command": "npx",
"args": ["-y", "writ-scan"],
"env": {
"WRIT_API_KEY": "<writ_api_key>"
}
}
}
}WRIT_API_KEYResumen de MCP Servers
# pywrit
**Find the dangerous writes in your Python agent's code, then gate it.** `pywrit` is the Python
client and `writ` CLI for [Writ](https://withwrit.com): an allow/deny gate that sits
in front of your agent's consequential writes (database, HTTP, files, email, queues,
AWS) and records a hash-chained receipt for every decision.

`writ scan` is **local, deterministic, and free**: it parses your code with Python's
`ast` module, makes no network calls, and needs no API key.
## Install
```bash
pip install pywrit
```
Requires Python 3.9+. Installs the `writ` command and the `pywrit` Python client.
**JavaScript/TypeScript devs:** run the scanner with no Python setup via npm:
```bash
npx writ-scan .
```
The `writ-scan` package wraps the same scanner (including TS/JS support). On
first run it installs `pywrit[polyglot]` from PyPI using your Python 3.9+
(one-time); afterwards it starts instantly. See [`npm/`](npm/) for details,
environment overrides (`WRIT_PYTHON`, `WRIT_SCAN_NO_INSTALL`), and the
install test.
## 60-second quickstart: scan → apply → gate
**1. Scan.** See which functions write, and how many of them are gated.
```bash
writ scan .
```
```text
writ scan: /path/to/support-agent
files scanned: 4 skipped: 0
write sites: 4 in 3 function(s)
gated: 0/4 (0%)
verbs discovered: 3
crm.update
payments.refund
tickets.close
```
It also prints a **risk report** (0-100, weighted by risk tier), writes the discovered
verbs to `writ-policy.json`, and shows the instrumentation it would add as a unified
diff. Nothing in your code changes yet. `writ scan . --score` prints just the risk report.
**2. Apply.** Insert a gate at the top of each writing function.
```bash
writ scan . --apply # shows the diff, then asks before writing
writ scan . --apply --yes # no prompt (e.g. in CI)
```
Each gated function now asks Writ before it writes, and fails closed:
```python
def issue_refund(charge_id, amount_cents):
if _writ_check("payments.refund") != "ALLOW":
raise PermissionError("writ denied payments.refund")
...
```
Re-run `writ scan .` and you'll see `gated: 4/4 (100%)`.
**3. Gate.** Get a free API key, load the discovered policy, and run your agent.
```bash
writ key --email you@example.com # free API key + tenant
export WRIT_API_KEY=writ_... # read by the inserted gate
export WRIT_SPONSOR=acme WRIT_AGENT=support-agent # optional: who is acting
writ scan . --push-policy --key "$WRIT_API_KEY" # upload the discovered verb policy
```
Every gated write now gets `ALLOW`, `DENY`, or `STEP_UP` (a human sponsor must
approve), and every decision is written to your tenant's tamper-evident audit log:
```bash
writ receipts --key "$WRIT_API_KEY" # latest receipts
writ verify-chain --key "$WRIT_API_KEY" # verify the receipt hash chain
writ stream --key "$WRIT_API_KEY" # tail decisions live
writ report --key "$WRIT_API_KEY" # Agent Action Report
```
## What `writ scan` detects
Python (`.py`) files, parsed with the stdlib `ast` (no extra dependencies):
| Category | Examples |
|---|---|
| Database | `cursor.execute(...)` / `executemany` / `executescript` (write SQL only; `SELECT`/`WITH`/... skipped), `session.add` / `commit` / `delete` / `merge` / `flush` |
| HTTP | `requests.post` / `put` / `patch`, `client.delete(...)`, `session.request(...)` |
| Files | `open(..., "w"/"a"/"x"/"+")`, `Path.write_text` / `write_bytes` / `unlink` / `rename`, `os.remove` / `rename` / `makedirs`, `shutil.rmtree` / `move` / `copy` |
| Email | `sendmail`, `send_message`, `send_email` |
| Queues | `publish`, `produce`, `enqueue`, `queue.send(...)` |
| AWS SDK | `put_object`, `put_item`, `delete_item`, `upload_file`, `send_message`, `start_execution`, ... |
- Each write is mapped to a verb such as `payments.refund` or `crm.update`, inferred
from the file path and function name.
- A function that already calls `writ_check(...)` / `_writ_check(...)` counts as gated.
- Skipped: tests, hidden directories, virtualenvs, `node_modules`, `dist`, `build`.
Use `--exclude SUBSTR` (repeatable) to skip more.
- Not covered (review by hand): writes behind dynamically built SQL, third-party SDK
calls such as `stripe.Refund.create(...)`, deferred task queues, or shared clients
several layers down. The risk report lists these gaps every time.
### TypeScript / JavaScript (scan-only)
`writ scan` also finds write sites in TypeScript and JavaScript. It needs the
optional extra (tree-sitter based):
pip install 'pywrit[polyglot]'
writ scan .
Without the extra, the scanner prints a one-line hint and keeps going —
Python scanning never needs it.
TS/JS is **scan-only**: findings are listed with verbs for your policy file,
but `writ scan --apply` never rewrites TS/JS files — gate those by hand.
Covered patterns: `fetch`/`axios` writes, `fs` writes, SQL through knex-style
clients, Prisma writes, and JS SDK calls such as `stripe.refunds.create(...)`.
(Still not covered: the *Python* SDK equivalents like `stripe.Refund.create(...)`
— see "Not covered" above.)

## GitHub Action
Scan every pull request for ungated write sites. Findings land as check
annotations on the exact file and line, plus a Markdown risk report in the
job summary. The check fails when an ungated finding meets your
`fail-on-risk` threshold (default: `high`).
```yaml
- uses: actions/checkout@v4
- uses: AvenueDAdmin/pywrit@v0
with:
fail-on-risk: high # high | medium | low | never
```
No API key needed. Full reference: [docs/github-action.md](docs/github-action.md) ·
example workflow: [examples/github-action/writ-scan.yml](examples/github-action/writ-scan.yml)
## Python client
```python
from pywrit import WritClient
client = WritClient(api_key="writ_...")
result = client.check(
sponsor_id="acme",
agent_id="agent-7",
verb="db.write",
target="prod.customers",
purpose="backfill region field",
)
if result.decision == "ALLOW":
# result.auth_token is a short-lived token bound to this exact write
perform_write(...)
elif result.decision == "STEP_UP":
# a human sponsor must approve first: client.grant(...), then re-check
...
else:
# DENY
...
```
No API key yet? Try the keyless sandbox:
```python
client = WritClient()
client.sandbox({
"sponsorId": "acme",
"agentId": "agent-7",
"verb": "demo_write", # sandbox only allows demo_write ...
"target": "demo-customers", # ... on targets starting with demo-
"purpose": "trying the gate",
})
```
What's covered:
- `check(...)`: the gate. `ALLOW` / `DENY` / `STEP_UP`, plus a receipt every time
- `verify_token(...)`: validate an `ALLOW` auth token (catches purpose drift)
- `grant(...)`: human-sponsor approval for the `STEP_UP` path
- `get_policy()` / `set_policy(...)`: manage the tenant policy
- `revoke(...)` / `reinstate(...)` / `revoked()`: the kill switch
- `receipts()` / `receipt(id)` / `verify_chain()` / `stream_receipts()`: the audit log
- `sandbox(...)`: keyless trial, no API key required
## CLI reference
```bash
writ check --key writ_... --sponsor acme --agent agent-7 \
--verb db.write --target prod.customers --purpose "backfill region field"
writ policy --key writ_... --set payments.refund require_grant
writ revoke --sponsor acme --agent agent-7 --reason "runaway loop" # kill switch (sponsor token)
writ grant --sponsor acme --agent agent-7 --verb payments.refund \
--target ch_123 --purpose "approved refund" # STEP_UP approval (sponsor token)
```
Sponsor-token commands (`revoke`, `reinstate`, `revoked`, `grant`) read
`--sponsor-token` or `WRIT_SPONSOR_TOKEN`. Run `writ --help` for the full command list.
## README badge
Show that your agent's writes are gated by Writ. Two flavors:
**Static** (works today, no API key) — same design, no live count:
```md
[](https://withwrit.com)
```
**Dynamic** (live 30-day gated-write count from your audit log) — mint a badge
token, then embed the snippet the API returns:
```bash
curl -s https://api.withwrit.com/v1/badge/tokens \
-H "Authorization: Bearer writ_..." \
-H "Content-Type: application/json" \
-d '{}'
```
The dynamic endpoint ships with the gate — until it's live, `POST /v1/badge/tokens`
returns 404 and the static badge above is the one to use.
See [`badge/`](badge/) for embed docs and the verification model (what the
badge proves — and what it doesn't).
## Docs
Full docs: [docs.withwrit.com](https://docs.withwrit.com) ·
Quickstart: [docs.withwrit.com/quickstart](https://docs.withwrit.com/quickstart) ·
Site: [withwrit.com](https://withwrit.com)
## License
MIT
Lo que la gente pregunta sobre pywrit
¿Qué es AvenueDAdmin/pywrit?
+
AvenueDAdmin/pywrit es mcp servers para el ecosistema de Claude AI con 1 estrellas en GitHub.
¿Cómo se instala pywrit?
+
Puedes instalar pywrit clonando el repositorio (https://github.com/AvenueDAdmin/pywrit) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.
¿Es seguro usar AvenueDAdmin/pywrit?
+
Nuestro agente de seguridad ha analizado AvenueDAdmin/pywrit y le ha asignado un Trust Score de 80/100 (tier: Trusted). Revisa el desglose completo de comprobaciones superadas y flags en esta página.
¿Quién mantiene AvenueDAdmin/pywrit?
+
AvenueDAdmin/pywrit es mantenido por AvenueDAdmin. La última actividad registrada en GitHub es del 2026-10-01, con 2 issues abiertos.
¿Hay alternativas a pywrit?
+
Sí. En ClaudeWave puedes explorar mcp servers similares en /categories/mcp, ordenados por popularidad o actividad reciente.
Despliega pywrit en tu cloud
Lleva este repo a producción en minutos. Cada plataforma genera su propio entorno con variables de entorno editables.
¿Mantienes este repo? Añade un badge a tu README
Pega el badge en tu README de GitHub para mostrar que está auditado por ClaudeWave. Cada badge enlaza de vuelta a esta página y muestra el Trust Score actual.
[](https://claudewave.com/repo/avenuedadmin-pywrit)<a href="https://claudewave.com/repo/avenuedadmin-pywrit"><img src="https://claudewave.com/api/badge/avenuedadmin-pywrit" alt="Featured on ClaudeWave: AvenueDAdmin/pywrit" width="320" height="64" /></a>Más MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev
The fastest path to AI-powered full stack observability, even for lean teams.