pywrit 0.2.7__tar.gz → 0.2.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pywrit
3
- Version: 0.2.7
3
+ Version: 0.2.9
4
4
  Summary: Python client + CLI for Writ — the gate before the write
5
5
  License-Expression: MIT
6
- Project-URL: Homepage, https://github.com/AvenueDAdmin/pywrit
6
+ Project-URL: Homepage, https://github.com/withwrit/pywrit
7
7
  Project-URL: Documentation, https://withwrit.com/docs
8
8
  Requires-Python: >=3.9
9
9
  Description-Content-Type: text/markdown
@@ -27,7 +27,9 @@ client and `writ` CLI for [Writ](https://withwrit.com): an allow/deny gate that
27
27
  in front of your agent's consequential writes (database, HTTP, files, email, queues,
28
28
  AWS) and records a hash-chained receipt for every decision.
29
29
 
30
- ![writ scan finds 4 write sites in a Python agent (0/4 gated); writ scan --apply inserts gates; a re-scan shows 4/4 gated](https://raw.githubusercontent.com/AvenueDAdmin/pywrit/main/docs/assets/scan-python.gif)
30
+ [![Listed on mcpservers.org](https://mcpservers.org/badge.svg)](https://mcpservers.org/servers/avenuedadmin/pywrit)
31
+
32
+ ![writ scan finds 4 write sites in a Python agent (0/4 gated); writ scan --apply inserts gates; a re-scan shows 4/4 gated](https://raw.githubusercontent.com/withwrit/pywrit/main/docs/assets/scan-python.gif)
31
33
 
32
34
  `writ scan` is **local, deterministic, and free**: it parses your code with Python's
33
35
  `ast` module, makes no network calls, and needs no API key.
@@ -52,7 +54,7 @@ first run it installs `pywrit[polyglot]` from PyPI using your Python 3.9+
52
54
  environment overrides (`WRIT_PYTHON`, `WRIT_SCAN_NO_INSTALL`), and the
53
55
  install test.
54
56
 
55
- ## 60-second quickstart: scan → apply → gate
57
+ ## 60-second quickstart: scan → wrap → gate
56
58
 
57
59
  **1. Scan.** See which functions write, and how many of them are gated.
58
60
 
@@ -75,14 +77,17 @@ It also prints a **risk report** (0-100, weighted by risk tier), writes the disc
75
77
  verbs to `writ-policy.json`, and shows the instrumentation it would add as a unified
76
78
  diff. Nothing in your code changes yet. `writ scan . --score` prints just the risk report.
77
79
 
78
- **2. Apply.** Insert a gate at the top of each writing function.
80
+ **2. Wrap.** One command takes the repo from unwrapped to wrapped: scan, show the diff,
81
+ ask for explicit approval, apply the gates, and report before/after coverage.
79
82
 
80
83
  ```bash
81
- writ scan . --apply # shows the diff, then asks before writing
82
- writ scan . --apply --yes # no prompt (e.g. in CI)
84
+ writ wrap . # interactive approval
85
+ writ wrap . --yes # no prompt (e.g. in CI)
83
86
  ```
84
87
 
85
- Each gated function now asks Writ before it writes, and fails closed:
88
+ `--dry-run` previews the plan and exits before prompting; `--diff-only` prints the
89
+ unified diff for review tools. Each gated function now asks Writ before it writes, and
90
+ fails closed:
86
91
 
87
92
  ```python
88
93
  def issue_refund(charge_id, amount_cents):
@@ -91,7 +96,8 @@ def issue_refund(charge_id, amount_cents):
91
96
  ...
92
97
  ```
93
98
 
94
- Re-run `writ scan .` and you'll see `gated: 4/4 (100%)`.
99
+ `writ scan . --apply` is still available as the manual alternative. Re-run `writ scan .`
100
+ and you'll see `gated: 4/4 (100%)`.
95
101
 
96
102
  **3. Gate.** Get a free API key, load the discovered policy, and run your agent.
97
103
 
@@ -148,11 +154,15 @@ Python scanning never needs it.
148
154
  TS/JS is **scan-only**: findings are listed with verbs for your policy file,
149
155
  but `writ scan --apply` never rewrites TS/JS files — gate those by hand.
150
156
  Covered patterns: `fetch`/`axios` writes, `fs` writes, SQL through knex-style
151
- clients, Prisma writes, and JS SDK calls such as `stripe.refunds.create(...)`.
157
+ clients, Prisma writes, JS SDK calls such as `stripe.refunds.create(...)`, and
158
+ generated REST resource clients: `create` / `update` / `patch` / `remove`
159
+ methods (plus their `...WithHttpInfo` variants) that build request options
160
+ with an explicit write HTTP method and route them through the client request
161
+ pipeline (twilio-style generated clients, e.g. `twilio-node`).
152
162
  (Still not covered: the *Python* SDK equivalents like `stripe.Refund.create(...)`
153
163
  — see "Not covered" above.)
154
164
 
155
- ![writ scan on a TypeScript agent finds 5 write sites, 1 of 5 gated](https://raw.githubusercontent.com/AvenueDAdmin/pywrit/main/docs/assets/scan-tsjs.gif)
165
+ ![writ scan on a TypeScript agent finds 5 write sites, 1 of 5 gated](https://raw.githubusercontent.com/withwrit/pywrit/main/docs/assets/scan-tsjs.gif)
156
166
 
157
167
  ## GitHub Action
158
168
 
@@ -163,7 +173,7 @@ job summary. The check fails when an ungated finding meets your
163
173
 
164
174
  ```yaml
165
175
  - uses: actions/checkout@v4
166
- - uses: AvenueDAdmin/pywrit@v0
176
+ - uses: withwrit/pywrit@v0
167
177
  with:
168
178
  fail-on-risk: high # high | medium | low | never
169
179
  ```
@@ -171,6 +181,46 @@ job summary. The check fails when an ungated finding meets your
171
181
  No API key needed. Full reference: [docs/github-action.md](docs/github-action.md) ·
172
182
  example workflow: [examples/github-action/writ-scan.yml](examples/github-action/writ-scan.yml)
173
183
 
184
+ ## GitHub App
185
+
186
+ Install the [Writ GitHub App](https://docs.withwrit.com/git-hub-app) on selected
187
+ repositories: every push and pull request is scanned for ungated write-sites,
188
+ with results as a check run on the PR and in the
189
+ [portal](https://app.withwrit.com), where you manage policy, keys, and the audit log.
190
+
191
+ ## MCP server (`writ-mcp`)
192
+
193
+ Give any MCP-compatible agent point-of-action policy checks. `writ-mcp` is a
194
+ [Model Context Protocol](https://modelcontextprotocol.io) server (stdio transport,
195
+ built on the MCP Python SDK) that exposes the Writ gate as **8 MCP tools**:
196
+ the agent calls `writ_check` before a consequential write and gets back `ALLOW`,
197
+ `DENY`, or `STEP_UP` — with a tamper-evident, hash-chained audit receipt for
198
+ every decision.
199
+
200
+ ```bash
201
+ uvx writ-mcp # no install — runs on demand
202
+ # or
203
+ pip install writ-mcp # then run `writ-mcp`
204
+ ```
205
+
206
+ | Tool | What it does |
207
+ |---|---|
208
+ | `writ_check` | The gate: `ALLOW` / `DENY` / `STEP_UP` for a proposed write |
209
+ | `writ_verify_token` | Validate an `ALLOW` auth token (catches purpose drift) |
210
+ | `writ_grant` | Human-sponsor approval for the `STEP_UP` path |
211
+ | `writ_revoke` / `writ_reinstate` | The kill switch |
212
+ | `writ_receipts` | Read the tenant's audit log |
213
+ | `writ_policy` | Manage the verb policy |
214
+ | `writ_sandbox` | Keyless 90-second demo grant — no API key needed |
215
+
216
+ The gate tools need a free Writ API key (`WRIT_API_KEY`): 10,000 receipts/month
217
+ free, no credit card. `writ_sandbox` works with no key at all.
218
+
219
+ The server implementation lives in [`mcp/`](mcp/) (MIT). Also published on the
220
+ official MCP Registry as `io.github.withwrit/writ`, on
221
+ [Smithery](https://smithery.ai/server/withwrit/writ-mcp), and listed on
222
+ [Glama](https://glama.ai/mcp/servers/withwrit/pywrit).
223
+
174
224
  ## Python client
175
225
 
176
226
  ```python
@@ -223,6 +273,9 @@ What's covered:
223
273
  ## CLI reference
224
274
 
225
275
  ```bash
276
+ writ wrap . # scan, diff, approve, apply, verify coverage
277
+ writ wrap . --dry-run # preview only
278
+ writ wrap . --yes # non-interactive CI mode
226
279
  writ check --key writ_... --sponsor acme --agent agent-7 \
227
280
  --verb db.write --target prod.customers --purpose "backfill region field"
228
281
  writ policy --key writ_... --set payments.refund require_grant
@@ -241,7 +294,7 @@ Show that your agent's writes are gated by Writ. Two flavors:
241
294
  **Static** (works today, no API key) — same design, no live count:
242
295
 
243
296
  ```md
244
- [![agent writes gated by Writ](https://cdn.jsdelivr.net/gh/AvenueDAdmin/pywrit@main/badge/writ-gated.svg)](https://withwrit.com)
297
+ [![agent writes gated by Writ](https://cdn.jsdelivr.net/gh/withwrit/pywrit@main/badge/writ-gated.svg)](https://withwrit.com)
245
298
  ```
246
299
 
247
300
  **Dynamic** (live 30-day gated-write count from your audit log) — mint a badge
@@ -5,7 +5,9 @@ client and `writ` CLI for [Writ](https://withwrit.com): an allow/deny gate that
5
5
  in front of your agent's consequential writes (database, HTTP, files, email, queues,
6
6
  AWS) and records a hash-chained receipt for every decision.
7
7
 
8
- ![writ scan finds 4 write sites in a Python agent (0/4 gated); writ scan --apply inserts gates; a re-scan shows 4/4 gated](https://raw.githubusercontent.com/AvenueDAdmin/pywrit/main/docs/assets/scan-python.gif)
8
+ [![Listed on mcpservers.org](https://mcpservers.org/badge.svg)](https://mcpservers.org/servers/avenuedadmin/pywrit)
9
+
10
+ ![writ scan finds 4 write sites in a Python agent (0/4 gated); writ scan --apply inserts gates; a re-scan shows 4/4 gated](https://raw.githubusercontent.com/withwrit/pywrit/main/docs/assets/scan-python.gif)
9
11
 
10
12
  `writ scan` is **local, deterministic, and free**: it parses your code with Python's
11
13
  `ast` module, makes no network calls, and needs no API key.
@@ -30,7 +32,7 @@ first run it installs `pywrit[polyglot]` from PyPI using your Python 3.9+
30
32
  environment overrides (`WRIT_PYTHON`, `WRIT_SCAN_NO_INSTALL`), and the
31
33
  install test.
32
34
 
33
- ## 60-second quickstart: scan → apply → gate
35
+ ## 60-second quickstart: scan → wrap → gate
34
36
 
35
37
  **1. Scan.** See which functions write, and how many of them are gated.
36
38
 
@@ -53,14 +55,17 @@ It also prints a **risk report** (0-100, weighted by risk tier), writes the disc
53
55
  verbs to `writ-policy.json`, and shows the instrumentation it would add as a unified
54
56
  diff. Nothing in your code changes yet. `writ scan . --score` prints just the risk report.
55
57
 
56
- **2. Apply.** Insert a gate at the top of each writing function.
58
+ **2. Wrap.** One command takes the repo from unwrapped to wrapped: scan, show the diff,
59
+ ask for explicit approval, apply the gates, and report before/after coverage.
57
60
 
58
61
  ```bash
59
- writ scan . --apply # shows the diff, then asks before writing
60
- writ scan . --apply --yes # no prompt (e.g. in CI)
62
+ writ wrap . # interactive approval
63
+ writ wrap . --yes # no prompt (e.g. in CI)
61
64
  ```
62
65
 
63
- Each gated function now asks Writ before it writes, and fails closed:
66
+ `--dry-run` previews the plan and exits before prompting; `--diff-only` prints the
67
+ unified diff for review tools. Each gated function now asks Writ before it writes, and
68
+ fails closed:
64
69
 
65
70
  ```python
66
71
  def issue_refund(charge_id, amount_cents):
@@ -69,7 +74,8 @@ def issue_refund(charge_id, amount_cents):
69
74
  ...
70
75
  ```
71
76
 
72
- Re-run `writ scan .` and you'll see `gated: 4/4 (100%)`.
77
+ `writ scan . --apply` is still available as the manual alternative. Re-run `writ scan .`
78
+ and you'll see `gated: 4/4 (100%)`.
73
79
 
74
80
  **3. Gate.** Get a free API key, load the discovered policy, and run your agent.
75
81
 
@@ -126,11 +132,15 @@ Python scanning never needs it.
126
132
  TS/JS is **scan-only**: findings are listed with verbs for your policy file,
127
133
  but `writ scan --apply` never rewrites TS/JS files — gate those by hand.
128
134
  Covered patterns: `fetch`/`axios` writes, `fs` writes, SQL through knex-style
129
- clients, Prisma writes, and JS SDK calls such as `stripe.refunds.create(...)`.
135
+ clients, Prisma writes, JS SDK calls such as `stripe.refunds.create(...)`, and
136
+ generated REST resource clients: `create` / `update` / `patch` / `remove`
137
+ methods (plus their `...WithHttpInfo` variants) that build request options
138
+ with an explicit write HTTP method and route them through the client request
139
+ pipeline (twilio-style generated clients, e.g. `twilio-node`).
130
140
  (Still not covered: the *Python* SDK equivalents like `stripe.Refund.create(...)`
131
141
  — see "Not covered" above.)
132
142
 
133
- ![writ scan on a TypeScript agent finds 5 write sites, 1 of 5 gated](https://raw.githubusercontent.com/AvenueDAdmin/pywrit/main/docs/assets/scan-tsjs.gif)
143
+ ![writ scan on a TypeScript agent finds 5 write sites, 1 of 5 gated](https://raw.githubusercontent.com/withwrit/pywrit/main/docs/assets/scan-tsjs.gif)
134
144
 
135
145
  ## GitHub Action
136
146
 
@@ -141,7 +151,7 @@ job summary. The check fails when an ungated finding meets your
141
151
 
142
152
  ```yaml
143
153
  - uses: actions/checkout@v4
144
- - uses: AvenueDAdmin/pywrit@v0
154
+ - uses: withwrit/pywrit@v0
145
155
  with:
146
156
  fail-on-risk: high # high | medium | low | never
147
157
  ```
@@ -149,6 +159,46 @@ job summary. The check fails when an ungated finding meets your
149
159
  No API key needed. Full reference: [docs/github-action.md](docs/github-action.md) ·
150
160
  example workflow: [examples/github-action/writ-scan.yml](examples/github-action/writ-scan.yml)
151
161
 
162
+ ## GitHub App
163
+
164
+ Install the [Writ GitHub App](https://docs.withwrit.com/git-hub-app) on selected
165
+ repositories: every push and pull request is scanned for ungated write-sites,
166
+ with results as a check run on the PR and in the
167
+ [portal](https://app.withwrit.com), where you manage policy, keys, and the audit log.
168
+
169
+ ## MCP server (`writ-mcp`)
170
+
171
+ Give any MCP-compatible agent point-of-action policy checks. `writ-mcp` is a
172
+ [Model Context Protocol](https://modelcontextprotocol.io) server (stdio transport,
173
+ built on the MCP Python SDK) that exposes the Writ gate as **8 MCP tools**:
174
+ the agent calls `writ_check` before a consequential write and gets back `ALLOW`,
175
+ `DENY`, or `STEP_UP` — with a tamper-evident, hash-chained audit receipt for
176
+ every decision.
177
+
178
+ ```bash
179
+ uvx writ-mcp # no install — runs on demand
180
+ # or
181
+ pip install writ-mcp # then run `writ-mcp`
182
+ ```
183
+
184
+ | Tool | What it does |
185
+ |---|---|
186
+ | `writ_check` | The gate: `ALLOW` / `DENY` / `STEP_UP` for a proposed write |
187
+ | `writ_verify_token` | Validate an `ALLOW` auth token (catches purpose drift) |
188
+ | `writ_grant` | Human-sponsor approval for the `STEP_UP` path |
189
+ | `writ_revoke` / `writ_reinstate` | The kill switch |
190
+ | `writ_receipts` | Read the tenant's audit log |
191
+ | `writ_policy` | Manage the verb policy |
192
+ | `writ_sandbox` | Keyless 90-second demo grant — no API key needed |
193
+
194
+ The gate tools need a free Writ API key (`WRIT_API_KEY`): 10,000 receipts/month
195
+ free, no credit card. `writ_sandbox` works with no key at all.
196
+
197
+ The server implementation lives in [`mcp/`](mcp/) (MIT). Also published on the
198
+ official MCP Registry as `io.github.withwrit/writ`, on
199
+ [Smithery](https://smithery.ai/server/withwrit/writ-mcp), and listed on
200
+ [Glama](https://glama.ai/mcp/servers/withwrit/pywrit).
201
+
152
202
  ## Python client
153
203
 
154
204
  ```python
@@ -201,6 +251,9 @@ What's covered:
201
251
  ## CLI reference
202
252
 
203
253
  ```bash
254
+ writ wrap . # scan, diff, approve, apply, verify coverage
255
+ writ wrap . --dry-run # preview only
256
+ writ wrap . --yes # non-interactive CI mode
204
257
  writ check --key writ_... --sponsor acme --agent agent-7 \
205
258
  --verb db.write --target prod.customers --purpose "backfill region field"
206
259
  writ policy --key writ_... --set payments.refund require_grant
@@ -219,7 +272,7 @@ Show that your agent's writes are gated by Writ. Two flavors:
219
272
  **Static** (works today, no API key) — same design, no live count:
220
273
 
221
274
  ```md
222
- [![agent writes gated by Writ](https://cdn.jsdelivr.net/gh/AvenueDAdmin/pywrit@main/badge/writ-gated.svg)](https://withwrit.com)
275
+ [![agent writes gated by Writ](https://cdn.jsdelivr.net/gh/withwrit/pywrit@main/badge/writ-gated.svg)](https://withwrit.com)
223
276
  ```
224
277
 
225
278
  **Dynamic** (live 30-day gated-write count from your audit log) — mint a badge
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pywrit"
7
- version = "0.2.7"
7
+ version = "0.2.9"
8
8
  description = "Python client + CLI for Writ — the gate before the write"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -22,7 +22,7 @@ polyglot = [
22
22
  keywords = ["ai-agents", "policy", "audit-log", "guardrails"]
23
23
 
24
24
  [project.urls]
25
- Homepage = "https://github.com/AvenueDAdmin/pywrit"
25
+ Homepage = "https://github.com/withwrit/pywrit"
26
26
  Documentation = "https://withwrit.com/docs"
27
27
 
28
28
  [project.scripts]
@@ -27,7 +27,7 @@ from .errors import (
27
27
  WritError,
28
28
  )
29
29
 
30
- __version__ = "0.2.7"
30
+ __version__ = "0.2.8"
31
31
 
32
32
  __all__ = [
33
33
  "WritClient",