Skip to content

Commit 6b41574

Browse files
authored
Merge pull request #11 from devonartis/doc/docs-layout-archon-style
docs: audit P1/P2 corrections + docs-layout-archon-style sweep
2 parents 684083b + 77dbf81 commit 6b41574

27 files changed

Lines changed: 1144 additions & 364 deletions

.claude/rules/karpathy.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Karpathy Guidelines — Coding Discipline
2+
3+
Derived from Andrej Karpathy's observations on common LLM coding pitfalls. These run alongside all other project rules — not optional, not situational.
4+
5+
## 1. Think Before Coding
6+
7+
State assumptions explicitly before implementing. If multiple interpretations exist, present them — don't pick silently. If something is unclear, stop and ask. Push back when a simpler approach exists.
8+
9+
## 2. Simplicity First
10+
11+
Minimum code that solves the problem. Nothing speculative.
12+
13+
- No features beyond what was asked
14+
- No abstractions for single-use code
15+
- No "flexibility" that wasn't requested
16+
- No error handling for impossible scenarios
17+
18+
AgentAuth has 5 direct dependencies by design. Every abstraction is a candidate to reject. If a change balloons a function, stop and reconsider.
19+
20+
## 3. Surgical Changes
21+
22+
Touch only what you must. Clean up only your own mess.
23+
24+
- Don't improve adjacent code, comments, or formatting
25+
- Don't refactor things that aren't broken
26+
- Match existing style, even if you'd do it differently
27+
- If you notice unrelated issues — note them in TECH-DEBT.md, don't fix them inline
28+
29+
**This is especially critical in `authz/`, `token/`, and `revoke/`.** Small "improvements" to adjacent security code introduce subtle regressions that tests don't catch because the behavior change wasn't the stated goal.
30+
31+
Every changed line should trace directly to the user's request.
32+
33+
## 4. Goal-Driven Execution
34+
35+
Define success criteria before starting. Loop until verified.
36+
37+
- "Fix the bug" → write a story that reproduces it, run against the binary, record evidence, then mark PASS
38+
- "Add validation" → write tests for invalid inputs, then make them pass
39+
- For multi-step tasks, state a brief plan with a verify step per item
40+
41+
Weak criteria ("make it work") require constant clarification. Strong criteria let you loop independently.
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# BUG-CLI-002 — `awrit init` writes config to wrong path
2+
3+
**ID:** BUG-CLI-002
4+
**Severity:** HIGH
5+
**Introduced in:** commit `4e197a5` (`fix(cli): rename aactl binary to awrit (TD-CLI-001)`)
6+
**Linked TD:** TD-CLI-002
7+
**Status:** Open — fix branch not yet created
8+
9+
---
10+
11+
## Summary
12+
13+
`awrit init` writes the generated config file to `~/.agentauth/config`. The broker's
14+
config auto-loader reads from `~/.broker/config`. These paths do not match. A user
15+
who runs `awrit init` without `--config-path` ends up with a config file the broker
16+
silently ignores, causing the broker to start with no admin secret and exit with a FATAL.
17+
18+
---
19+
20+
## Root Cause
21+
22+
Two commits touched the same logical concern but were not reconciled:
23+
24+
| Commit | File | What it did |
25+
|--------|------|-------------|
26+
| `07daa20` (TD-CFG-002) | `internal/cfg/configfile.go` | Updated broker auto-load search paths: `/etc/agentauth/config``/etc/broker/config`, `~/.agentauth/config``~/.broker/config` |
27+
| `4e197a5` (TD-CLI-001) | `cmd/awrit/init_cmd.go` | Created `resolveConfigPath()` with the **old paths**: `/etc/agentauth/config` and `~/.agentauth/config` |
28+
29+
`07daa20` landed first. `4e197a5` was created after it, but introduced new code using
30+
the stale paths — they were never synced.
31+
32+
---
33+
34+
## Affected Code
35+
36+
**File:** `cmd/awrit/init_cmd.go`
37+
**Function:** `resolveConfigPath()` (lines 53–64)
38+
39+
```go
40+
func resolveConfigPath() string {
41+
if initConfigPath != "" {
42+
return initConfigPath
43+
}
44+
if p := os.Getenv("AA_CONFIG_PATH"); p != "" {
45+
return p
46+
}
47+
home, err := os.UserHomeDir()
48+
if err != nil {
49+
return "/etc/agentauth/config" // ← should be /etc/broker/config
50+
}
51+
return home + "/.agentauth/config" // ← should be /.broker/config
52+
}
53+
```
54+
55+
**Broker reads from** (`internal/cfg/configfile.go:24`):
56+
```go
57+
locs = append(locs, filepath.Join(home, ".broker", "config"))
58+
```
59+
60+
---
61+
62+
## Impact
63+
64+
A user following the getting-started guide:
65+
66+
1. Runs `awrit init` → config written to `~/.agentauth/config`
67+
2. Starts broker → broker searches `~/.broker/config`, finds nothing
68+
3. `AA_ADMIN_SECRET` is unset → broker exits FATAL: `admin secret required`
69+
70+
The `--config-path` flag works around this, but no getting-started doc tells users
71+
they need it because the default is supposed to Just Work.
72+
73+
---
74+
75+
## Fix
76+
77+
**File:** `cmd/awrit/init_cmd.go:53–64`
78+
79+
```go
80+
func resolveConfigPath() string {
81+
if initConfigPath != "" {
82+
return initConfigPath
83+
}
84+
if p := os.Getenv("AA_CONFIG_PATH"); p != "" {
85+
return p
86+
}
87+
home, err := os.UserHomeDir()
88+
if err != nil {
89+
return "/etc/broker/config"
90+
}
91+
return home + "/.broker/config"
92+
}
93+
```
94+
95+
Two literal changes. No other files affected.
96+
97+
---
98+
99+
## Verification
100+
101+
After the fix, run:
102+
103+
```bash
104+
# Build
105+
go build -o bin/awrit ./cmd/awrit
106+
107+
# Run init
108+
./bin/awrit init --mode dev
109+
110+
# Confirm path
111+
ls -la ~/.broker/config # must exist
112+
cat ~/.broker/config # must contain ADMIN_SECRET=...
113+
114+
# Start broker (reads ~/.broker/config automatically)
115+
./bin/broker
116+
# Expect: broker starts, no FATAL on admin secret
117+
```
118+
119+
Unit test: `internal/cfg/configfile_test.go` already tests that `~/.broker/config`
120+
is in the search path. Add a test in `cmd/awrit/init_cmd_test.go` (or similar)
121+
that calls `resolveConfigPath()` with `HOME` set and asserts the returned path
122+
ends in `.broker/config`.
123+
124+
---
125+
126+
## Branch
127+
128+
`fix/td-cli-002-awrit-init-config-path` off `develop`
129+
Needs: code fix + unit test + `./scripts/gates.sh task` green + PR

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed — Docs audit P1/P2 corrections (2026-04-12)
11+
12+
- **`docs/getting-started-user.md`** — admin auth examples used the literal `"my-secret-key-change-in-production"` while the guide starts the broker with a randomly generated `$AA_ADMIN_SECRET`. Examples now reference `$AA_ADMIN_SECRET` so the first-run path works without 401s.
13+
- **`docs/awrit-reference.md`**`awrit init` sample output showed `~/.agentwrit/config`; corrected to `~/.broker/config` (the actual default write path — or rather, the broker's read path; see TD-CLI-002 for the underlying code bug).
14+
- **`docs/api.md`** — JWT claims table corrected: `iss` is driven by `AA_ISSUER` (empty by default, issuer validation skipped); app token subject is `app:{internal_app_id}` not `app:{client_id}`; `aud` is driven by `AA_AUDIENCE` (omitted if unset, audience validation skipped).
15+
- **`docs/getting-started-operator.md`**`AA_AUDIENCE` default corrected from `"agentwrit"` to *(empty)*. SQLite persistence note corrected: setting `AA_DB_PATH=""` does not enable memory-only mode — unset uses the `./data.db` default.
16+
- **`docs/api/openapi.yaml`**`info.license` corrected from `Apache-2.0` to `AGPL-3.0` with the correct license URL. Matches `LICENSE`, `README.md`, and `CLA.md`.
17+
- **`docker-compose.yml`** — Docker bridge network renamed `agentauth-net``agentwrit-net` to match brand sweep and operator docs.
18+
- **`docs/README.md`** — API reference entry corrected from "22 HTTP endpoints" to "19". Concepts entry corrected from "seven components" to "eight".
19+
- **`docs/concepts.md`** — intro sentence corrected from "seven components" to "eight".
20+
- **`TECH-DEBT.md`** — added TD-CLI-002 (HIGH: `awrit init` writes to `~/.agentauth/config`, broker reads `~/.broker/config` — broken first-run path introduced in commit `4e197a5`) and TD-CLI-003 (Low: docker-compose.yml network name lag). Bug report at `.plans/bugs/BUG-CLI-002-awrit-init-config-path.md`.
21+
1022
### Renamed CLI binary `aactl``awrit` (TD-CLI-001)
1123

1224
- **`cmd/aactl/``cmd/awrit/`** — directory renamed. Cobra command name changed (`Use: "aactl"``Use: "awrit"`). All internal CLI output, help text, and error messages updated.

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- `.claude/rules/testing.md` — LIVE test and acceptance test expectations
1010
- `.claude/rules/golang.md` — Go coding standards
1111
- `.claude/rules/mandatory-reading.md`**Read this entirely and summarize it back to the user at session start.** Defines what goes in MEMORY.md vs FLOW.md vs TECH-DEBT.md. Do NOT mix them up.
12+
- `.claude/rules/karpathy.md` — coding discipline (simplicity, surgical changes, goal-driven execution). Always active alongside the rules above.
1213

1314
## Defaults
1415

FLOW.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,3 +532,37 @@ Rewrote the AgentWrit public intro copy for the rebrand (Layer 1 of Decision 013
532532

533533
### Status: Copy ready — apply on next agentauth-core session
534534
**Next:** apply the new intro to the website, core README, and any other location the old intro lives. Single source of truth in the decision file — no per-repo drift.
535+
536+
---
537+
538+
## 2026-04-12 — Docs audit P1/P2 corrections + TD-CLI-002 bug discovery
539+
540+
### Action: Fixed 9 doc accuracy issues from external audit report
541+
542+
Branch: `doc/docs-layout-archon-style`
543+
544+
Audit report surfaced P1/P2 findings against the codebase. After verification:
545+
546+
**Docs fixed (pure doc errors — no code changes):**
547+
- `docs/getting-started-user.md` — wrong admin secret literal in auth examples → `$AA_ADMIN_SECRET`
548+
- `docs/awrit-reference.md``awrit init` sample output showed `~/.agentwrit/config``~/.broker/config`
549+
- `docs/api.md` — JWT claims table: `iss` not always "agentwrit" (driven by `AA_ISSUER`, empty by default); app subject is `app:{internal_app_id}` not `app:{client_id}`; `aud` driven by `AA_AUDIENCE`, omitted if unset
550+
- `docs/getting-started-operator.md``AA_AUDIENCE` default was wrong (`"agentwrit"` → empty); SQLite memory-mode fallback claim removed (false — empty `AA_DB_PATH` falls back to `./data.db`)
551+
- `docs/api/openapi.yaml` — license `Apache-2.0``AGPL-3.0`
552+
- `docker-compose.yml` — network `agentauth-net``agentwrit-net` (brand sweep miss)
553+
- `docs/README.md` — endpoint count 22 → 19 (verified from route registration); component count seven → eight
554+
- `docs/concepts.md` — component count seven → eight
555+
556+
**Left alone (intentional code/docs gap — code-side rebrand not done yet):**
557+
- `urn:agentauth:error:` in `internal/problemdetails/problemdetails.go` — docs say `urn:agentwrit:error:`, code hasn't been renamed; this is planned work
558+
- `agentauth_*` metric names in `internal/obs/obs.go` — docs say `agentwrit_*`, same situation
559+
560+
**New tech debt logged:**
561+
- TD-CLI-002 (HIGH) — `awrit init` writes to `~/.agentauth/config`, broker reads `~/.broker/config`. Bug introduced in `4e197a5`: TD-CFG-002 fixed the broker read side but the CLI write side (`cmd/awrit/init_cmd.go:53-64`) was created with old paths. Bug report: `.plans/bugs/BUG-CLI-002-awrit-init-config-path.md`
562+
- TD-CLI-003 (Low) — docker-compose.yml network name lag (fixed in this session)
563+
564+
### What's Next
565+
566+
1. **`fix/td-cli-002-awrit-init-config-path`** — two-line fix in `cmd/awrit/init_cmd.go:53-64`, unit test, gates, PR. Bug report ready at `.plans/bugs/BUG-CLI-002-awrit-init-config-path.md`.
567+
2. **Code-side rebrand** — rename `agentauth_*` Prometheus metrics in `internal/obs/obs.go` and `urn:agentauth:error:` in `internal/problemdetails/problemdetails.go` to match the docs. Separate PR.
568+
3. **Merge `doc/docs-layout-archon-style`** — after user review.

TECH-DEBT.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ B0 removed all sidecar Go code and infrastructure but did NOT rewrite the user-f
7777
| TD-012 | **MISSING: Role model documentation — who does what, which scopes, and why** | **CRITICAL** | `docs/` — new file needed | See detail below. Without this document, every agent that touches the code misunderstands the system. |
7878
| TD-013 | `POST /v1/admin/launch-tokens` lets admin CREATE agents — admin should only LIST/REVOKE launch tokens | High | `cmd/broker/main.go:257`, `internal/admin/admin_hdl.go:58-60` | See detail below. |
7979
| TD-014 | **Code comments audit — all handlers, services, and types need role/scope/boundary comments** | **CRITICAL** | All `internal/` packages | Every function, handler, and type must document: what it does, who can call it (role/scope), why it exists, and its boundaries. Current code has minimal Go doc comments that describe mechanics but not roles, scopes, or security boundaries. An agent reading only the source file cannot understand who calls what or why. Standard defined in `.claude/rules/golang.md`. |
80+
| TD-015 | `deleg_svc.go` comment says "strict subset" but `ScopeIsSubset` allows equal scopes | Low | `internal/deleg/deleg_svc.go:10-11` | Line 10 says "The delegated scope must be a strict subset of the delegator's scope" but the actual `ScopeIsSubset` check allows equal scopes (subset-or-equal). The behavior is correct — the comment is wrong. Fix: change "strict subset" to "subset" in the package doc. |
8081

8182
### TD-012 Detail: Missing Role Model Document
8283

@@ -352,6 +353,21 @@ Audit triggered by discovery of hardcoded `iss: "agentauth"` in `internal/token/
352353

353354
**Not creating a TD for env var prefix** — decided 2026-04-10 to keep `AA_*` indefinitely. Neutral enough (two letters), operator-facing, highest-friction change in the whole rebrand. Re-evaluate at 1.0 if ever.
354355

356+
| TD-CLI-002 | **`awrit init` writes config to `~/.agentauth/config` but broker reads `~/.broker/config`** — broken first-run path | **HIGH** | Immediate — breaks first-run UX | `cmd/awrit/init_cmd.go:53-64` |
357+
| TD-CLI-003 | **`docker-compose.yml` network still named `agentauth-net`** — docs say `agentwrit-net` after brand sweep | Low | Next compose-touching PR | `docker-compose.yml:35,42` |
358+
359+
### TD-CLI-002 Detail: awrit init config path mismatch
360+
361+
TD-CFG-002 (resolved 2026-04-10) updated `internal/cfg/configfile.go` to search `~/.broker/config` and `/etc/broker/config`. But commit `4e197a5` (TD-CLI-001, awrit rename) introduced `cmd/awrit/init_cmd.go` with `resolveConfigPath()` still returning `~/.agentauth/config` (home) and `/etc/agentauth/config` (fallback). The fix to the broker's *read* side and the creation of the CLI's *write* side happened in different commits and were never reconciled.
362+
363+
**Impact:** A user who runs `awrit init` (no `--config-path`) gets a config at `~/.agentauth/config`. The broker auto-loads from `~/.broker/config`. The config is silently ignored and the broker starts with no admin secret, causing a `FATAL` exit.
364+
365+
**Fix:** In `cmd/awrit/init_cmd.go:53-64`, update `resolveConfigPath()`:
366+
- `"/etc/agentauth/config"``"/etc/broker/config"`
367+
- `home + "/.agentauth/config"``home + "/.broker/config"`
368+
369+
**Needs:** `fix/td-cli-002-awrit-init-config-path` branch + gates + PR. Bug report at `.plans/bugs/BUG-CLI-002-awrit-init-config-path.md`.
370+
355371
## When to Fix
356372

357373
Documentation and script drift items (TD-D*, TD-S*) should be resolved **after all cherry-pick batches are complete** (B0-B6). Doing them now risks conflicts with incoming commits. Schedule as a dedicated docs refresh phase post-migration.

docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ services:
3232
timeout: 3s
3333
retries: 10
3434
networks:
35-
- agentauth-net
35+
- agentwrit-net
3636

3737

3838
volumes:
3939
broker-data:
4040

4141
networks:
42-
agentauth-net:
42+
agentwrit-net:
4343
driver: bridge

docs/README.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# AgentWrit Documentation
2+
3+
AgentWrit is an open-source credential broker for AI agents. It issues short-lived, scope-attenuated tokens so agents operate with only the permissions their task requires — nothing more, nothing longer.
4+
5+
---
6+
7+
## The Book of AgentWrit
8+
9+
Start here. These pages explain what AgentWrit is, why it exists, and how every piece fits together.
10+
11+
| Page | What you'll learn |
12+
|------|-------------------|
13+
| [What Is AgentWrit?](agentwrit-explained.md) | The problem, the solution, and the three token types — no prior knowledge required |
14+
| [Foundations](foundations.md) | What tokens are, why they beat API keys, and how JWTs work under the hood |
15+
| [The Three Actors](roles.md) | Operator, Application, Agent — who holds what token and why |
16+
| [Scopes and Permissions](scope-model.md) | The `action:resource:identifier` format, coverage rules, and the four enforcement points |
17+
| [The Credential Lifecycle](credential-model.md) | Every credential's claims, TTLs, and how they flow through the attenuation chain |
18+
| [Design Decisions](design-decisions.md) | Why we chose JWTs, Ed25519, SPIFFE, hash-chained audit, and everything else |
19+
20+
---
21+
22+
## Getting Started
23+
24+
Hands-on guides for each persona. Pick the one that matches your role.
25+
26+
| If you are... | Start here |
27+
|---------------|-----------|
28+
| **Just trying AgentWrit** to see how it works | [Your First Five Minutes](getting-started-user.md) |
29+
| **Building an AI agent** in Python, TypeScript, or Go | [Getting Started: Developer](getting-started-developer.md) |
30+
| **Deploying AgentWrit** in production | [Getting Started: Operator](getting-started-operator.md) |
31+
32+
---
33+
34+
## Guides
35+
36+
Deeper walkthroughs for specific tasks and patterns.
37+
38+
| Guide | What it covers |
39+
|-------|---------------|
40+
| [Common Tasks](common-tasks.md) | Token renewal, delegation, revocation, audit queries — the everyday operations |
41+
| [Integration Patterns](integration-patterns.md) | Resource server validation, multi-agent orchestration, cloud federation |
42+
| [Scenarios](scenarios.md) | End-to-end walkthroughs: data pipeline agent, customer service bot, CI/CD runner |
43+
| [Troubleshooting](troubleshooting.md) | Common errors, what causes them, and how to fix them |
44+
45+
---
46+
47+
## Reference
48+
49+
Lookup documentation for endpoints, CLI commands, and internals.
50+
51+
| Reference | What it covers |
52+
|-----------|---------------|
53+
| [API Reference](api.md) | All 19 HTTP endpoints — request/response formats, error codes, rate limits |
54+
| [CLI Reference (awrit)](awrit-reference.md) | Every `awrit` command with examples and output formats |
55+
| [Architecture](architecture.md) | Internal package map, component diagrams, data flow |
56+
| [Implementation Map](implementation-map.md) | Where every feature lives in the codebase — file paths, function names, test locations |
57+
| [Concepts Deep Dive](concepts.md) | The full security pattern, industry context, and all eight components |
58+
59+
---
60+
61+
## Live Demos
62+
63+
See AgentWrit in action with the [Python SDK](https://github.com/devonartis/agentauth-python) demo applications:
64+
65+
| Demo | What it shows |
66+
|------|-------------|
67+
| **[MedAssist AI](https://github.com/devonartis/agentauth-python/tree/main/demo)** | Healthcare multi-agent pipeline — clinical, prescription, and billing agents operating under strict scope isolation with LLM tool-calling, delegation, and per-patient scoping |
68+
| **[Support Ticket Zero-Trust](https://github.com/devonartis/agentauth-python/tree/main/demo2)** | Three LLM-driven agents processing support tickets with broker-issued scoped credentials, streaming execution via SSE, and natural token expiry |
69+
70+
Both demos run against a real AgentWrit broker and show the full credential lifecycle: agent registration, scope enforcement, delegation, renewal, release, and revocation.
71+
72+
---
73+
74+
## Reading Order
75+
76+
If you're new, this path gets you productive fastest:
77+
78+
```
79+
What Is AgentWrit? → Your First Five Minutes → Pick your persona guide
80+
↓ ↓
81+
Foundations → The Three Actors → Scopes → Common Tasks
82+
```
83+
84+
If you're evaluating AgentWrit for your organization, start with [What Is AgentWrit?](agentwrit-explained.md) — it's written for people who aren't deeply technical.
85+
86+
If you're a security reviewer, start with [Concepts Deep Dive](concepts.md) and [Architecture](architecture.md).

0 commit comments

Comments
 (0)