Skip to content

v0.3.0 — AgentWrit Python SDK public release#24

Merged
devonartis merged 99 commits intomainfrom
develop
Apr 18, 2026
Merged

v0.3.0 — AgentWrit Python SDK public release#24
devonartis merged 99 commits intomainfrom
develop

Conversation

@devonartis
Copy link
Copy Markdown
Owner

Summary

First public release of the AgentWrit Python SDK. 99 commits from develop → main.

SDK

  • Complete rewrite: create_agent()Agent with renew(), release(), delegate()
  • Ed25519 challenge-response authentication
  • Typed response models, RFC 7807 error handling
  • httpx transport, mypy --strict enforced

Testing

  • 99 unit tests, 15 acceptance stories against live broker
  • 11 CI gates: lint, typecheck, unit tests (3.10-3.13), integration, bandit SAST, pip-audit, secrets scan, gitignore check

Demos

  • MedAssist AI (FastAPI + HTMX) — healthcare multi-agent pipeline
  • Support Tickets (Flask + HTMX + SSE) — zero-trust support pipeline
  • Docker images for both: devonartis/agentwrit-medassist, devonartis/agentwrit-support-tickets

Infrastructure

  • PyPI: pip install agentwrit (v0.3.0 live)
  • CI: auto-publish to PyPI on tag, auto-push Docker images on main merge
  • GitHub secrets: admin, Docker Hub, PyPI all configured

Docs

  • README with Docker quick-start, badges, both demo sections
  • getting-started, concepts, developer-guide, api-reference, testing-guide
  • 8 sample app guides, CONTRIBUTING.md, MIT LICENSE

Closes devonartis/agentwrit#31

Generated with Claude Code

Planning artifacts for upcoming v0.3.0 SDK closure and subsequent
demo app v3 implementation. These stay on develop — main is release-only.

New analysis:
- .plans/2026-04-02-sdk-broker-gap-review.md — 15 findings, 1 critical,
  5 high, 5 medium, 4 low. Field-by-field SDK/broker diff plus Codex
  adversarial review for concurrency and cache bugs.
- .plans/2026-04-04-prd-demo-and-sdk-gaps.md — consolidated PRD covering
  v2 demo post-mortem, Workstream A (SDK closure → v0.3.0), and
  Workstream B (demo app v3).
- .plans/designs/SIMPLE-DESIGN.md — simplified demo scope doc.

Demo app v3 planning (recovered from archive/demo-app-v2-rejected):
- .plans/2026-04-01-demo-app-v3-plan.md — 16-task implementation plan
- .plans/designs/2026-04-01-demo-app-design-v3.md — approved design
- .plans/designs/2026-04-01-eight-by-eight-scenarios.md
- .plans/designs/2026-04-01-why-traditional-iam-fails.md
Consolidates the 3-parallel-audit findings and records all design
decisions for the v0.3.0 rebuild. This supersedes the gap review's
recommendations where they differ.

Scope: 25 findings (15 from gap review + 10 new from audit) across
7 implementation phases. Hard breaks everywhere — v0.2.0 was never
released publicly, no consumers to preserve.

Locked decisions:
- AgentAuthClient deleted entirely, no alias. Renamed to AgentAuthApp.
- TokenResult, DelegationResult, ValidationResult are plain dataclasses.
  No __str__/__eq__ tricks. Developer writes result.token explicitly.
- revoke_token deleted. Replaced by release_token (matches endpoint).
- decode_claims is inspect-only, no signature verification.
- X-Request-ID auto-generated SDK-side (UUID per request).
- 10s default HTTP timeout, configurable.

Cross-cutting standards for all phases:
- Python logging under agentauth.<module> namespaces
- Every log/exception carries request_id for broker log correlation
- No bare except, no silent failures
- HTTP boundaries have explicit retry/fail logic

Implementation starts tomorrow: Phase 1 (rename) → Phase 2 (correctness
bugs G13/G14/G15/G16) → Phase 3 (result types) → etc.
Hard break, no alias. The class holds client_id/client_secret and
authenticates against /v1/app/auth — it IS the App in the broker's
3-tier trust model (Operator → App → Agent), not a generic "client".

Source file renamed: src/agentauth/client.py → src/agentauth/app.py
Unit test files renamed to match:
  tests/unit/test_client_auth.py       → test_app_auth.py
  tests/unit/test_client_get_token.py  → test_app_get_token.py
  tests/unit/test_client_ops.py        → test_app_ops.py

All 34 files updated:
- AgentAuthClient → AgentAuthApp (class name)
- agentauth.client → agentauth.app (module path, imports, mock patches)
- src/agentauth/client.py → src/agentauth/app.py (doc references)

Gates:
- mypy --strict src/: clean (6 source files)
- pytest tests/unit/: 119/119 passing
- ruff: 10 pre-existing errors in tests/sdk-core/ and
  tests/integration/test_app_auth.py, unchanged by this rename

This is the first phase of 7 in the v0.3.0 SDK closure work. See
.plans/designs/2026-04-04-v0.3.0-sdk-design.md for the full plan.
Planning artifacts for v0.3.0 SDK closure:
- 6 phase-scoped specs (Phases 2-7) at .plans/specs/2026-04-05-v0.3.0-phase*-spec.md
  covering all 24 remaining findings from the SDK-broker gap review
- Phase 2 (Cache Correctness) implementation plan with TDD tasks for
  G13 (task_id/orch_id keying), G14 (eviction on release), G15 (per-key
  locking), G16 (TokenExpiredError removal)
- Phase 2 acceptance stories (SDK-P2-S1..S4) appended to
  tests/sdk-core/user-stories.md

Archive cleanup — 12 stale planning docs moved to .plans/ARCHIVE/:
- 2 DONE (HITL removal plan + spec, shipped in v0.2.0)
- 9 ARCHIVED (demo app v1/v2/v3 design/spec/plan + supporting docs)
- 1 SUPERSEDED (PRD folded into v0.3.0 design)

Each archived file has Unicode strikethrough (U+0336) in its filename
AND ~~markdown strikethrough~~ with a ~~Status~~ banner inside. Renamed
via git mv — history preserved.

MEMORY.md + FLOW.md updated to reflect current state: demo archived,
v0.3.0 closure active, Phase 2 ready to execute, in-repo broker design
in progress (next session).
The class was defined, exported, and documented, but never raised
anywhere in the SDK. Callers writing 'except TokenExpiredError:'
handlers would never see them fire. v0.3.0's TokenResult.expires_at
(Phase 3) makes expiry checkable by the caller directly.

Breaking change — pre-release, no alias.

Closes G16.
Cache was keyed by (agent_name, frozenset(scope)) only. But the broker
embeds task_id and orch_id in JWT claims AND in the SPIFFE subject.
Two calls with the same name+scope but different task_id returned the
SAME cached token — breaking task isolation and corrupting audit trail.

Cache key is now (agent_name, frozenset(scope), task_id, orch_id).
TokenCache.get/put/needs_renewal/remove each accept keyword-only
task_id/orch_id params; AgentAuthApp.get_token threads its already-
accepted task_id/orch_id args through to every cache call site.

Closes G13.
After revoke_token() succeeded, the cache entry remained -- a subsequent
get_token() with the same key returned the revoked token with zero
broker calls, which then failed at use time with confusing 401s.

Added TokenCache.remove_by_token() (linear-scan eviction) and wired it
into AgentAuthApp.revoke_token() after successful broker release.
Eviction is skipped when revoke fails so caller can retry.

Closes G14.
Two threads hitting a cold cache both completed the full registration
flow, each receiving a different SPIFFE ID from the broker. Last-writer
wins cached; the first thread's token became orphaned — valid at the
broker, unreferenced in SDK, unrevokable.

Added per-key locks (TokenCache.acquire_key_lock) and wrapped the
cache-miss path in AgentAuthApp.get_token() with double-checked locking:
fast-path check (lock-free), acquire lock, re-check, register, cache,
release. Exactly one thread registers per logical cache key; others see
the populated cache on the second read.

remove_by_token now also evicts the stale per-key lock so the lock dict
doesn't grow unbounded.

Closes G15.
This commit completes the core container logic for the AgentAuth SDK. The AgentAuthApp serves as the primary entry point for developers, acting as the 'trust anchor' for all agents created within its scope.

Key Architectural Implementations:

1. Lazy Authentication ():
   - To improve ergonomics and reduce startup latency, the SDK does not authenticate immediately upon instantiation.
   - Authentication is deferred until the first protected operation (e.g.,  or ) is invoked.
   - This aligns with the 'App-as-Container' model where the application's lifecycle and its credentials are managed as a single unit.

2. Automated Session Management:
   - The app manages its own JWT session internally via .
   - The SDK automatically detects token expiry (with a 60-second safety buffer) and triggers a re-authentication flow () before the existing token becomes invalid.
   - This removes the burden from the developer to handle app-level session refreshes.

3. Core API Surface:
   - : Provides a high-level check of the broker's operational status, including database connectivity and uptime.
   - : Provides a convenience shortcut for module-level token validation, allowing the app to quickly verify agent tokens before granting tool access.
   - : Ensures graceful teardown of the underlying The httpx command line client could not run because the required dependencies were not installed.
Make sure you've installed everything with: pip install 'httpx[cli]' transport client.

Business Logic & Security:
- The  and  are strictly used to obtain the app JWT and are never exposed in the public API or logs.
- All communication is routed through a private  instance to ensure consistent error handling and telemetry.

Ref: .plans/v0.3.0-rewrite-implementation-plan.md
This commit implements the core Agent object, which represents an ephemeral,
task-scoped principal in the AgentAuth trust model.

Key Architectural Implementations:

1. Ephemeral Identity:
   - The Agent carries its unique SPIFFE ID (), , and .
   - These identifiers are immutable and tie the agent's lifecycle to
     specific orchestration context.

2. Lifecycle Methods (Stubs for Phase 3 Orchestration):
   - : Designed to mutate the agent in-place, refreshing the
      while maintaining the same identity.
   - : Implements the 'self-revocation' pattern, allowing
     agents to signal task completion and minimize credential exposure.
   - : Enables the 'Principle of Least Privilege' by allowing
     agents to spawn sub-agents with attenuated scopes.

3. Security & Ergonomics:
   - : Provides a convenient dictionary for use in
     HTTP clients (e.g., ).
   -  state: Tracks whether the agent has been decommissioned
     to prevent misuse of revoked credentials.

Business Logic:
The Agent is treated as a living principal, not a static token. By wrapping
the token with lifecycle methods, the SDK guides the developer toward
secure patterns like mandatory release and controlled delegation.

Ref: .plans/v0.3.0-rewrite-implementation-plan.md
This commit bridges the high-level App API with the internal registration ceremony.

Key Implementation Details:

1. Orchestration Integration:
   -  now delegates its implementation to the
     .
   - This maintains a clean separation between the user-facing 'Container'
     (the App) and the complex, multi-step cryptographic handshake required
     to mint an agent.

2. Complete Agent Lifecycle:
   - The call flow is now fully realized:
     App Auth -> Launch Token -> Challenge -> Signing -> Registration -> Agent Object.

Business Logic:
By using the orchestrator, we ensure that the 'App-as-Container' principle
is strictly followed: the App manages the credentials, while the
Orchestrator manages the ephemeral 'birth' of the agents.

Ref: .plans/v0.3.0-rewrite-implementation-plan.md
This commit finalizes the public-facing interface of the AgentAuth Python SDK.

Key Implementation Details:

1. Complete Export Set:
   - All major classes (AgentAuthApp, Agent) are exported.
   - The full exception hierarchy (AgentAuthError, AuthenticationError, etc.) is exposed.
   - All public data models (AgentClaims, ValidateResult, etc.) are exported.
   - Module-level utility functions (scope_is_subset, validate) are available at the top level.

2. Version Update:
   - The package version has been updated to 0.3.0, marking the completion of the spec-driven rewrite.

3. PEP 561 Compliance:
   - Re-exports are structured to support static type checkers and ensure a clean, flat API for the end developer.

Business Logic:
By providing a flat, well-organized export at the package level, we allow developers to simply use  rather than navigating the internal module structure, significantly improving the library's ergonomics.

Ref: .plans/v0.3.0-rewrite-implementation-plan.md
This commit establishes the fundamental building blocks of the AgentAuth Python SDK. These modules are designed to be strictly typed and provide the base logic for all subsequent phases.

Key Implementations:

1. Data Models (src/agentauth/models.py):
   - Implemented all core dataclasses: AgentClaims, DelegationRecord, ValidateResult, DelegatedToken, RegisterResult, HealthStatus, and ProblemDetail.
   - All models are @DataClass(frozen=True) to ensure immutability.
   - Included business-logic documentation for each model to clarify their role in the AgentAuth trust model.

2. Exception Hierarchy (src/agentauth/errors.py):
   - Created a typed exception hierarchy starting from AgentAuthError.
   - Implemented ProblemResponseError to map RFC 7807 (application/problem+json) error responses from the broker.
   - Mapped specific HTTP status codes (401, 403, 429) to AuthenticationError, AuthorizationError, and RateLimitError.

3. Scope Utility (src/agentauth/scope.py):
   - Implemented scope_is_subset() to perform client-side validation of agent authority.
   - Implemented validate() as a module-level utility for token verification via the broker.
   - Documentation explains the 'authority can only narrow, never expand' principle.

4. Cryptographic Helpers (src/agentauth/crypto.py):
   - Implemented Ed25519 keypair generation, nonce signing, and base64 encoding.
   - These helpers facilitate the agent registration ceremony (challenge-response).

Strict typing (mypy --strict) has been verified for these modules.

Ref: .plans/v0.3.0-rewrite-implementation-plan.md
…2, 2.3)

This commit implements the core 'container' logic that manages the application's identity and communication with the broker.

Key Implementations:

1. Private Transport ():
   - Implemented  to encapsulate all The httpx command line client could not run because the required dependencies were not installed.
Make sure you've installed everything with: pip install 'httpx[cli]' interactions.
   - Implemented RFC 7807 (Problem Details) parsing to map broker error responses to the SDK's typed exception hierarchy.
   - Handled network-level failures by mapping them to .

2. App Session Management ():
   - Implemented  to track the application's JWT and expiration.

3. AgentAuthApp ():
   - Implemented the primary entry point for developers.
   - Implemented 'Lazy Authentication': The app authenticates on-demand during the first protected call, reducing startup overhead.
   - Implemented automatic session renewal: The app checks for token expiry (with a 60-second buffer) and re-authenticates before the token becomes invalid.
   - Implemented  for broker connectivity checks.
   - Implemented  as a convenience wrapper for module-level verification.
   - Implemented  for clean teardown of the transport client.

Business Logic:
The  acts as the trust anchor. It manages the app's own credentials and provides the foundation for creating agents. The lazy authentication and automatic renewal ensure that the developer doesn't have to manage the complexities of JWT lifecycles.

Ref: .plans/v0.3.0-rewrite-implementation-plan.md
…ssing)

Replace the flat token-vending design (get_token → string) with the
app-as-container model from the new PRD. AgentAuthApp creates Agent
objects with lifecycle methods (renew, release, delegate).

Source changes:
- requests → httpx (ADR SDK-011)
- New: models.py (AgentClaims, ValidateResult, DelegatedToken, etc.)
- New: errors.py (ProblemDetail + ProblemResponseError hierarchy)
- New: scope.py (scope_is_subset + module-level validate)
- New: _transport.py (httpx transport with RFC 7807 error parsing)
- New: agent.py (Agent class, lifecycle stubs)
- New: app.py (AgentAuthApp with lazy auth, create_agent, health)
- New: orchestrator.py (internal create_agent ceremony)
- Removed: token.py (TokenCache), retry.py (retry logic)

Test changes:
- Rewrote test_crypto.py, test_errors.py for new API
- New: test_models.py, test_scope.py
- Removed all old tests (test_app_auth, test_get_token, etc.)

Gates: ruff clean, mypy --strict clean, 46 unit tests passing.

Agent lifecycle methods (renew, release, delegate) are stubs —
will be implemented TDD-style next.
…egate)

TDD cycle: wrote 15 failing tests for Agent.renew(), Agent.release(),
and Agent.delegate(), then implemented minimal code to pass.

- renew(): POST /v1/token/renew with Bearer auth, mutates in-place (ADR SDK-008)
- release(): POST /v1/token/release, idempotent, marks agent released
- delegate(): POST /v1/delegate, returns DelegatedToken with chain
- No validate() on Agent (ADR SDK-006)
- All methods guard against use after release()

Also added 13 transport tests (RFC 7807 parsing, error dispatch, network errors).

Gates: ruff clean, mypy --strict clean, 74 unit tests passing.
Covers lazy authentication, session reuse, health(), validate()
shortcut, create_agent() orchestration sequence, scope ceiling
violations, agent_name auto-generation, and secret redaction.

Gates: ruff clean, mypy --strict clean, 91 unit tests passing.
Tests the standalone validate(broker_url, token) function usable by
resource servers without constructing an AgentAuthApp (ADR SDK-007).

Covers: valid/invalid results, delegation chain parsing, optional
sid field, trailing slash handling, request body verification.

Gates: ruff clean, mypy --strict clean, 98 unit tests passing.
Old phase-based entries superseded. New entries track spec-driven
rewrite: 4 implementation phases DONE, 10 acceptance stories at
UNIT_PASS (7) / PASS (2) / NOT_STARTED (1, needs live broker).

Next: integration tests against live broker.
Bug found during acceptance testing: the broker's /v1/token/validate
response does not include 'aud' in claims. The parser crashed with
KeyError because it used data["aud"] instead of data.get("aud", []).

Root cause: parser was written without checking the actual broker
response contract. Added spec Section 8.1 (Response-to-Model Parsing
Contract) to define which fields are required vs optional so this
class of bug cannot recur.

TDD: wrote failing test reproducing the KeyError, then fixed.

Gates: ruff clean, mypy --strict clean, 99 unit tests passing.
Acceptance run 2026-04-07: 3 of 8 stories passed (S1-S3).

Bug 1 (fixed): validate() parser crashed on missing 'aud' field.
Broker doesn't return aud in /v1/token/validate. Parser used
data["aud"] instead of data.get("aud", []). Fixed in prior commit.
Added spec Section 8.1 parsing contract.

Bug 2 (open): each acceptance script creates a new AgentAuthApp,
triggering separate POST /v1/app/auth calls. 8 scripts = rate limit.
Fix: rewrite as pytest tests using session-scoped client fixture.

Evidence files captured in tests/sdk-core/evidence/.
Reject the FIX_NOW.md 'critical design flaw' finding after thorough
analysis of the Broker's scope enforcement logic.

ANALYSIS:
The FIX_NOW.md claimed the SDK uses 'requested_scope' instead of the
Broker-granted scope, leading to silent failures where the SDK would
report write:* when the JWT only had read:*.

This scenario CANNOT occur because the Broker implements ALL-OR-NOTHING
scope enforcement (id_svc.go:111):
  - If requested_scope exceeds launch token ceiling → 403 Forbidden
  - If registration succeeds → requested_scope equals JWT scope exactly

The SDK's current  is CORRECT and not a bug.

FILES CHANGED:
- FIX_NOW.md → REJECT-FIX_NOW.md (renamed to preserve history)
- broker/BACKLOG.md (new): Deferred enhancement for explicit token
  validation methods (defense-in-depth, not bug fix)

BACKLOG ITEM:
Future SDK enhancement to add Agent.validate_token() and Agent.has_scope()
methods that call POST /v1/token/validate for explicit verification.
This is architectural improvement, not a fix.

SEE: broker/BACKLOG.md for enhancement details
SEE: REJECT-FIX_NOW.md for original (invalid) finding

No code changes required — orchestrator.py remains correct.
Document the investigation that rejected the FIX_NOW.md finding:

- Broker implements ALL-OR-NOTHING scope enforcement (id_svc.go:111)
- Silent divergence between SDK and JWT claims is IMPOSSIBLE
- When registration succeeds, requested_scope equals granted scope exactly

MEMORY.md:
- Added 'FIX_NOW.md Rejected' lesson entry
- Updated 'What's next' to focus on acceptance test runner fix

FLOW.md:
- Added 2026-04-07 decision log entry
- Documented investigation, verdict, and artifacts
- Clarified immediate next steps (acceptance test runner fix)

No code changes — orchestrator.py remains correct.
Acceptance Tests (tests/integration/test_acceptance_1_8.py):
- 15 stories, all passing against live broker, zero redundancy
- Stories 1-4: core lifecycle (create, renew, release, validate)
- Stories 5-8: delegation (narrow, rejected, multi-hop chain A→B→C, full-scope)
- Story 9: scope gating via scope_is_subset()
- Story 10: natural token expiry (5s TTL, no release)
- Story 11: RFC 7807 ProblemDetail error structure
- Story 12: multiple agents with isolated scopes
- Stories 13-15: released agent guard, garbage token handling, health check
- Every test has executive-readable banners (WHO/WHAT/WHY/EXPECTED)
- Every SDK response captured in evidence files for audit trail
- Delegation tests validate the actual DelegatedToken via broker (not registration scope)
- Story 7 uses raw HTTP for hop 2 to build real A→B→C chain
- Story 8 discovered: broker accepts same-scope delegation (equal is subset)

Documentation (full rewrite — old v0.2.0 docs were completely wrong):
- README.md: updated quick start, diagrams, and examples for v0.3.0 API
- docs/getting-started.md: step-by-step beginner guide using create_agent() → Agent
- docs/concepts.md: roles, scopes (with real mistakes from testing), delegation,
  error model, SPIFFE identities, multi-hop limitation documented
- docs/developer-guide.md: lifecycle patterns, delegation (single + multi-hop),
  scope gating, error handling — all from tested patterns
- docs/api-reference.md: every class, method, dataclass, exception from source

Key changes from old docs:
- get_token() → create_agent() returning Agent object
- revoke_token() → agent.release()
- validate_token() → validate() module function returning ValidateResult
- delegate() on client → agent.delegate() returning DelegatedToken
- ScopeCeilingError → AuthorizationError
- BrokerUnavailableError → TransportError
- requests → httpx
- Removed: token caching, auto-renewal, retry, thread safety (never existed)
Removed:
- tests/integration/test_acceptance.py (old 22-story suite with broken delegation
  tests, wrong scope formats, and silent failures — replaced by test_acceptance_1_8.py)
- tests/sdk-core/s*.py (old standalone scripts that caused 429 rate limit)
- tests/sdk-core/evidence/s*.txt (old evidence files from superseded tests)
- tests/sdk-core/evidence/test_run.log

Updated:
- tests/sdk-core/run_acceptance.sh — points to test_acceptance_1_8.py, adds -s flag
  for banner visibility

Added:
- docs/testing-guide.md — how to run unit and acceptance tests, what each story
  covers, how to add new stories, evidence file conventions, rate limit handling
Claude-harness-bot and others added 29 commits April 14, 2026 16:30
Integration tests were fake green: 14 of 15 stories skipped
because CI never provided AGENTWRIT_CLIENT_ID or CLIENT_SECRET.

Fix: CI now registers a test app with the broker via admin API
before running tests. Also fails the job if any tests skip —
all 15 stories must run, no silent skips allowed.

Refs devonartis/agentwrit#31

Generated with Claude Code
ci: fix integration tests — register app, reject skips (V5)
Old logo said "AGENTAUTH" — was only renamed, not replaced.
New logo pulled from upstream devonartis/agentwrit repo.

Refs devonartis/agentwrit#31

Generated with Claude Code
fix: replace stale AgentAuth logo with correct AgentWrit logo
All validate() and raw HTTP examples used bare `broker_url` which
was never assigned. Changed to `app.broker_url` throughout.

Refs devonartis/agentwrit#31

Generated with Claude Code
fix: broker_url undefined in code examples (TE-1/TE-2/TE-3)
Sets reader expectations before the first code block and aligns
both docs against the actual SDK API.

README.md
- Add Prerequisites section (broker + credentials + env vars)
- Add inline TOC for scannability
- Quick Start opens with pointer to Prerequisites
- Fix agent.release missing parens (silent no-op)
- Tighten orphan sentence, break run-on demo description
- Troubleshooting blockquote with actual exception classes

docs/getting-started.md
- Expand Prerequisites with two-path framing
- Qualify "5 minutes" claim
- Fix orchestration order (challenge before keygen)
- Use agent.bearer_header convenience accessor
- Add Testing Guide and MedAssist Demo to Next Steps

Refs devonartis/agentwrit#31

Generated with Claude Code
Aligns the dev guide with the README and getting-started polish,
promotes a real SDK limitation from a buried sub-clause to a proper
callout, and tightens informal headings.

- Frontmatter cross-links to README Prerequisites
- Basic Pattern uses agent.bearer_header accessor
- Long-Running Tasks: hedge note on broker lifetime cap
- Single-Hop Delegation: document delegate(ttl=N) keyword
- Multi-Hop: promote registration-token constraint to blockquote
- Rename "What We Learned About Delegation" → "Delegation Behavior"
- Rename "Garbage Tokens" → "Invalid Tokens"
- Fix result.claims.iss comment — broker-configured, not fixed
- Next Steps: add Testing Guide and MedAssist Demo rows

Refs devonartis/agentwrit#31

Generated with Claude Code
Alignment, navigation, and grounded error-code enumeration.

- Add inline TOC (6 anchors)
- Frontmatter pointer to Getting Started and Developer Guide
- close(): note AgentWritApp is not a context manager, show
  try/finally pattern (verified: no __enter__/__exit__)
- jti: soften from "32 hex chars" to "broker-assigned"
- ProblemDetail: enumerate all 10 known error_code values
- Call out the 403 trap: scope_violation and insufficient_scope
  both surface as AuthorizationError
- AuthorizationError: expand to 3 sub-cases with error_codes

Refs devonartis/agentwrit#31

Generated with Claude Code
Voice consistency and framing updates to match the new
README/getting-started structure.

- Frontmatter pointer to Getting Started for code-first readers
- Operator role: acknowledge solo-broker path (both hats)
- "Common Scope Mistakes" → neutral voice
- Delegation rules: verified-against-broker intro
- Multi-hop: blockquote callout matching developer-guide
- validate() generic error scoped to validate endpoint only
- Fix bare broker_url → app.broker_url (2 occurrences)
- Next Steps: add Testing Guide and MedAssist Demo

Refs devonartis/agentwrit#31

Generated with Claude Code
- Frontmatter links to README Prerequisites
- Fix stale credentials advice: register your own app, don't
  rely on hardcoded values in run script (TE-6, TE-13)
- pytest is now primary path, wrapper script secondary
- Inline caveat on test_acceptance_1_8.py filename (all 15
  stories, rename is a follow-up)
- Rate limit manual recovery note
- Next Steps table for doc parity

Refs devonartis/agentwrit#31

Generated with Claude Code
The broker's ScopeIsSubset is a non-strict subset check — equal
scope passes, any scope the delegator doesn't hold is rejected.
Same-scope delegation is accepted and verified in acceptance
Story 8 ("Delegate All Scope — No Narrowing").

Canonical phrasing: "Delegation cannot widen authority. Equal or
narrower scope is accepted."

Files: README, concepts, developer-guide, sample-apps (04, 05,
README), sample-app-mini-max, demo guides, operator template,
scope.py docstring, models.py docstring, integration test banner,
sdk-core s7_delegation.py.

Broker-side fix filed as devonartis/agentwrit#41.

Refs devonartis/agentwrit#31

Generated with Claude Code
docs: tech editor pass + delegation accuracy fix
Module docstring referenced internal dev artifacts that were
relocated to ~/proj/devflow/ and are not in the public repo.

Refs devonartis/agentwrit#31

Generated with Claude Code Harness Agent

Co-Authored-By: Claude <claude@anthropic.com>
Updates all sdk-core evidence files to reflect the agentauth -> agentwrit
rename. SPIFFE IDs now use agentwrit.local as returned by the live broker.

Refs devonartis/agentwrit#31

Generated with Claude Code Harness Agent

Co-Authored-By: Claude <claude@anthropic.com>
Refs devonartis/agentwrit#31

Generated with Claude Code Harness Agent

Co-Authored-By: Claude <claude@anthropic.com>
Replaces default test credentials with an env-var guard that prints
a helpful error and exits if AGENTWRIT_CLIENT_ID or
AGENTWRIT_CLIENT_SECRET are not set.

Refs devonartis/agentwrit#31

Generated with Claude Code Harness Agent

Co-Authored-By: Claude <claude@anthropic.com>
Refs devonartis/agentwrit#31

Generated with Claude Code Harness Agent

Co-Authored-By: Claude <claude@anthropic.com>
…apps (TE-8)

Refs devonartis/agentwrit#31

Generated with Claude Code Harness Agent

Co-Authored-By: Claude <claude@anthropic.com>
…5, TE-20)

Refs devonartis/agentwrit#31

Generated with Claude Code Harness Agent

Co-Authored-By: Claude <claude@anthropic.com>
…#20)

fix: add bandit SAST + pip-audit to CI, fix assert in production code, upgrade 4 vulnerable deps. Closes #19, Refs devonartis/agentwrit#31
…21)

docs: Docker quick-start, demo2 section, fix stale AACTL_ env var names. Closes #5, Refs devonartis/agentwrit#31, Refs devonartis/agentwrit#33
ci: add PyPI auto-publish workflow on tag push. Refs devonartis/agentwrit#31
docs: add PyPI, CI, and download badges to README. Refs devonartis/agentwrit#31
@devonartis devonartis merged commit 75c25e6 into main Apr 18, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python SDK — publish to GitHub + PyPI

2 participants