You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+57-9Lines changed: 57 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -15,6 +15,20 @@
15
15
Built on Ed25519 challenge-response and the <ahref="https://github.com/devonartis/AI-Security-Blueprints/blob/main/patterns/ephemeral-agent-credentialing/versions/v1.3.md">Ephemeral Agent Credentialing v1.3</a> pattern.
16
16
</p>
17
17
18
+
<palign="center">
19
+
<ahref="#why-agentwrit">Why</a> ·
20
+
<ahref="#installation">Install</a> ·
21
+
<ahref="#prerequisites">Prerequisites</a> ·
22
+
<ahref="#quick-start">Quick Start</a> ·
23
+
<ahref="#agent-lifecycle">Lifecycle</a> ·
24
+
<ahref="#medassist-ai-demo">Demo</a> ·
25
+
<ahref="#scope-format">Scopes</a> ·
26
+
<ahref="#delegation">Delegation</a> ·
27
+
<ahref="#error-handling">Errors</a> ·
28
+
<ahref="#architecture">Architecture</a> ·
29
+
<ahref="#documentation">Docs</a>
30
+
</p>
31
+
18
32
---
19
33
20
34
## Why AgentWrit?
@@ -24,9 +38,9 @@ AI agents need credentials to access databases, APIs, and file systems. Most tea
24
38
-**Ephemeral identities** — every agent gets a unique Ed25519 keypair, generated in memory and never persisted to disk
25
39
-**Task-scoped tokens** — credentials are limited to exactly what the agent needs (`read:data:customers`, not `read:*:*`)
26
40
-**Short-lived by default** — tokens expire in minutes, not hours or days
27
-
-**Delegation chains** — agents can delegate narrower permissions to other agents, enforced at every hop
41
+
-**Delegation chains** — agents can delegate a subset of their permissions to other agents; the broker rejects any attempt to widen
28
42
29
-
This SDK is the Python client for the [AgentWrit broker](https://github.com/devonartis/agentwrit). The broker is the credential authority; this SDK makes it easy to integrate from Python.
43
+
This SDK is the Python client for the [AgentWrit broker](https://github.com/devonartis/agentwrit) — the broker is the credential authority, and this SDK is how your Python code talks to it.
30
44
31
45
## Installation
32
46
@@ -50,19 +64,53 @@ cd agentwrit-python
50
64
uv sync --all-extras
51
65
```
52
66
53
-
**Requirements:** Python 3.10+ and a running [AgentWrit broker](https://github.com/devonartis/agentwrit) instance.
67
+
**Requirements:** Python 3.10+. The SDK also needs a broker and credentials — see [Prerequisites](#prerequisites).
68
+
69
+
## Prerequisites
70
+
71
+
The SDK is a client. It does **not** run the broker, and it does **not** mint its own credentials. Before any code in [Quick Start](#quick-start) will work, you need three things:
72
+
73
+
**1. A reachable AgentWrit broker.**
74
+
The broker is a separate service that issues and validates tokens.
75
+
76
+
-*Have a platform team running one?* Ask them for the broker URL.
77
+
-*Running it yourself?* Stand one up locally — the [broker repo](https://github.com/devonartis/agentwrit) ships a `docker compose` setup. From this repo:
78
+
```bash
79
+
docker compose up -d # pulls devonartis/agentwrit from Docker Hub
**3. Environment variables set** on the process that uses the SDK:
93
+
```bash
94
+
export AGENTWRIT_BROKER_URL="http://localhost:8080"# from step 1
95
+
export AGENTWRIT_CLIENT_ID="<from step 2>"
96
+
export AGENTWRIT_CLIENT_SECRET="<from step 2>"
97
+
```
98
+
99
+
> Auth is lazy — the SDK doesn't talk to the broker until your first `create_agent()` call. If that call raises `AuthenticationError`, your `client_id` or `client_secret` is wrong (or the operator rotated them). If it raises `TransportError`, the broker URL is unreachable.
54
100
55
101
## Quick Start
56
102
103
+
> Assumes [Prerequisites](#prerequisites) are met — broker reachable, app registered, env vars set.
104
+
57
105
```python
58
106
import os
59
107
from agentwrit import AgentWritApp, validate
60
108
61
109
# Connect to the broker (lazy — no auth until first create_agent)
The [`demo/`](demo/) directory contains **MedAssist AI** — an interactive healthcare demo that showcases every AgentWrit capability against a live broker.
114
162
115
-
**What it does:** A FastAPI web app where you enter a patient ID and a plain-language request. A local LLM (OpenAI-compatible) chooses which tools to call. The app dynamically creates broker agents with only the scopes those tools need, for that specific patient. You see scope enforcement, cross-patient denial, delegation, token renewal, and release — all in a real-time execution trace.
163
+
**What it does:** A FastAPI web app where you enter a patient ID and a plain-language request. A local LLM (OpenAI-compatible) chooses which tools to call, and the app dynamically creates broker agents with only the scopes those tools need for that specific patient. Every step — scope enforcement, cross-patient denial, delegation, token renewal, release — appears in a real-time execution trace.
Agents delegate narrower scope to other agents. Authority can only narrow, never widen.
220
+
Agents delegate a subset of their scope to other agents. Delegation cannot widen authority — equal or narrower scope is accepted; any scope the delegator doesn't hold is rejected.
Copy file name to clipboardExpand all lines: demo/BEGINNERS_GUIDE.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -14,7 +14,7 @@ Traditional setups often give every service (or every “agent”) the **same lo
14
14
-**What task** they are doing,
15
15
-**Which scopes** they are allowed to use (often **per patient**, per action).
16
16
17
-
The **broker** is the authority: it registers apps, mints tokens, validates them, supports **delegation** (narrowing authority), **renewal**, **release**, and **revocation**, and writes an **audit trail**.
17
+
The **broker** is the authority: it registers apps, mints tokens, validates them, supports **delegation** (passing scope to another agent — equal or narrower, never widening), **renewal**, **release**, and **revocation**, and writes an **audit trail**.
18
18
19
19
---
20
20
@@ -144,7 +144,7 @@ flowchart LR
144
144
145
145
## 7. Diagram: delegation (prescription write)
146
146
147
-
Delegation is **authority narrowing**: the clinical agent already has `write:prescriptions:{pid}`; it asks the broker to issue a **delegated token** for the prescription agent’s SPIFFE ID with **only**that scope (or a subset).
147
+
Delegation is **bounded authority transfer** — the broker rejects any attempt to widen past the delegator's scope. In this demo, the clinical agent already has `write:prescriptions:{pid}` and asks the broker to issue a **delegated token** for the prescription agent's SPIFFE ID with that same scope (or a narrower subset). Equal-scope and narrower delegation are both valid; widening is rejected.
Copy file name to clipboardExpand all lines: demo/templates/operator.html
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -38,7 +38,7 @@ <h2>Broker Health</h2>
38
38
<!-- Scope Ceiling -->
39
39
<divclass="panel">
40
40
<h2>App Scope Ceiling</h2>
41
-
<pclass="description">The maximum scopes this application can grant to agents. Set by the operator at app registration. Each agent gets a strict subset, scoped to a specific patient.</p>
41
+
<pclass="description">The maximum scopes this application can grant to agents. Set by the operator at app registration. Each agent gets a subset of this ceiling, typically scoped to a specific patient.</p>
Copy file name to clipboardExpand all lines: docs/api-reference.md
+40-6Lines changed: 40 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,8 @@
1
1
# API Reference
2
2
3
-
Complete reference for the AgentWrit Python SDK public API.
3
+
Complete reference for the AgentWrit Python SDK public API. Companion to [Getting Started](getting-started.md) and [Developer Guide](developer-guide.md).
@@ -97,7 +99,18 @@ Shortcut for `agentwrit.validate(app.broker_url, token)`.
97
99
app.close() ->None
98
100
```
99
101
100
-
Closes the underlying HTTP transport. Call this when you're done with the app to release connections.
102
+
Closes the underlying HTTP transport. Call this when you're done with the app to release the connection pool.
103
+
104
+
> `AgentWritApp` is **not** a context manager — `with AgentWritApp(...) as app:` will raise `AttributeError`. Use a `try/finally` instead:
105
+
>
106
+
> ```python
107
+
> app = AgentWritApp(...)
108
+
>try:
109
+
> agent = app.create_agent(...)
110
+
># ... use agent ...
111
+
>finally:
112
+
> app.close()
113
+
>```
101
114
102
115
---
103
116
@@ -255,7 +268,7 @@ from agentwrit import AgentClaims
255
268
|`exp`|`int`| Expiration (Unix timestamp) |
256
269
|`nbf`|`int`| Not before (Unix timestamp) |
257
270
|`iat`|`int`| Issued at (Unix timestamp) |
258
-
|`jti`|`str`| Unique token ID (32 hex chars) |
271
+
|`jti`|`str`| Unique token ID (broker-assigned; format is broker-defined, do not assume a fixed length) |
259
272
|`scope`|`list[str]`| Granted scope |
260
273
|`task_id`|`str`| Task identifier |
261
274
|`orch_id`|`str`| Orchestrator identifier |
@@ -320,6 +333,25 @@ RFC 7807 structured error from the broker.
320
333
|`request_id`|`str \| None`| Broker-generated trace ID |
321
334
|`hint`|`str \| None`| Optional guidance for resolution |
322
335
336
+
#### Known `error_code` values
337
+
338
+
> Observed broker behavior at the time of writing. The broker's [api.md](https://github.com/devonartis/agentwrit/blob/main/docs/api.md) is the authoritative source — consult it for additions or renames.
|`forbidden`| 403 | Admin-side app-not-found or scope-ceiling check during admin launch-token creation |
346
+
|`insufficient_scope`| 403 | Caller's token is valid but lacks the scope required for this endpoint (emitted by the validation middleware) — **or** the token has been revoked |
347
+
|`scope_violation`| 403 |`/v1/register` or `/v1/delegate` rejected the requested scope as exceeding the caller's authority |
348
+
|`not_found`| 404 | App or delegate agent does not exist |
349
+
|`payload_too_large`| 413 | Request body exceeded 1 MB |
350
+
|`rate_limited`| 429 | Rate limit hit on the auth endpoints |
> **Watch the 403 split.** Both `scope_violation` and `insufficient_scope` surface as `AuthorizationError` in the SDK. If you switch on `error_code`, handle both: `scope_violation` covers "your request exceeded your authority"; `insufficient_scope` covers "your token doesn't have the scope this endpoint needs, or the token was revoked."
354
+
323
355
### RegisterResult
324
356
325
357
```python
@@ -365,9 +397,11 @@ Raised on HTTP 401. App credentials are invalid.
Raised on HTTP 403. Three distinct sub-cases, all surface through this class — inspect `e.problem.error_code` to differentiate:
401
+
402
+
-**Scope ceiling violation** — requested scope exceeds the app's ceiling during `create_agent()` (`error_code: scope_violation`)
403
+
-**Delegation violation** — delegated scope exceeds delegator's scope, or exceeds broker-enforced delegation depth, during `delegate()` (`error_code: scope_violation`)
404
+
-**Token revocation or insufficient scope at the endpoint** — caller's token was revoked, or lacks the scope the endpoint requires (`error_code: insufficient_scope`)
0 commit comments