Skip to content

Commit 37852be

Browse files
committed
docs: restructure — lean README landing page + full docs/ reference
1 parent b76641a commit 37852be

File tree

6 files changed

+440
-389
lines changed

6 files changed

+440
-389
lines changed

README.md

Lines changed: 26 additions & 309 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,18 @@
55
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
66
[![Node.js >= 18](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org)
77

8-
**Hard execution and budget limits for autonomous agents — enforced locally.**
8+
Hard execution and budget limits for autonomous agents — enforced locally.
99

10-
AuthorityLayer prevents runaway spend, infinite tool loops, and uncontrolled external calls in agentic systems. It enforces strict boundaries inside your runtime and halts execution safely when limits are breached.
11-
12-
- ✅ No telemetry
13-
- ✅ No cloud dependency
14-
- ✅ Fail-closed by default
15-
- ✅ Works fully offline
16-
- ✅ Zero runtime dependencies
10+
- No telemetry
11+
- Works fully offline
12+
- Fail-closed by default
13+
- Zero runtime dependencies
1714

1815
---
1916

20-
## The Problem
21-
22-
Autonomous agents introduce a new risk surface that traditional systems don't account for:
23-
24-
- **Unbounded token spend** — a looping agent can burn thousands of dollars before you notice
25-
- **Infinite tool loops** — agents can get stuck calling the same tool repeatedly
26-
- **Retry storms** — failed API calls retried indefinitely with no ceiling
27-
- **Cascading API calls** — one agent spawns sub-calls, which spawn more
28-
- **Silent cost explosions** — spend accumulates across runs with no enforced ceiling
17+
## Live Enforcement Demo
2918

30-
Most systems rely on warnings, dashboard alerts, or provider-level quotas — all of which react *after* the damage is done.
31-
32-
**AuthorityLayer enforces hard limits directly in your execution loop.** When a boundary is crossed, execution stops immediately.
19+
![AuthorityLayer enforcement demo](./docs/assets/enforcement-demo.gif)
3320

3421
---
3522

@@ -39,14 +26,12 @@ Most systems rely on warnings, dashboard alerts, or provider-level quotas — al
3926
npm install authority-layer
4027
```
4128

42-
Verify the install in seconds:
29+
Verify the install:
4330

4431
```bash
4532
npx authority-layer doctor
4633
```
4734

48-
Expected output:
49-
5035
```
5136
AuthorityLayer Doctor authority-layer@0.1.1
5237
@@ -67,24 +52,20 @@ All checks passed. AuthorityLayer is ready.
6752
import { AuthorityLayer, EnforcementHalt } from "authority-layer";
6853

6954
const authority = new AuthorityLayer({
70-
budget: { dailyUSD: 50 }, // Hard USD spend cap
71-
loopGuard: { maxToolCallsPerRun: 25 }, // Max tool calls per run
72-
toolThrottle:{ maxCallsPerMinute: 60 }, // Sliding-window rate cap
55+
budget: { dailyUSD: 50 }, // Hard USD spend cap
56+
loopGuard: { maxToolCallsPerRun: 25 }, // Max tool calls per run
57+
toolThrottle: { maxCallsPerMinute: 60 }, // Sliding-window rate cap
7358
});
7459

7560
try {
7661
await authority.wrap(async () => {
77-
// All tool calls go through authority.tool()
7862
const result = await authority.tool("llm.chat", () =>
7963
callYourModel(prompt)
8064
);
81-
82-
// You calculate cost; authority enforces the cap
8365
authority.recordSpend(calculateCostUSD(result));
8466
});
8567
} catch (err) {
8668
if (err instanceof EnforcementHalt) {
87-
// Structured halt object — never parse the message string
8869
console.error(err.enforcement);
8970
// { status: "halted", reason: "budget_exceeded", limit: 50, spent: 52.14, event_id: "evt_..." }
9071
}
@@ -95,291 +76,27 @@ try {
9576

9677
## Enforcement Primitives
9778

98-
AuthorityLayer V1 implements three composable enforcement primitives. Each is independently opt-in — omit a config key to disable that primitive entirely.
99-
100-
### 1. Budget Cap
79+
Three composable primitives. Each is independently opt-in — omit a config key to disable it entirely.
10180

102-
Tracks cumulative USD spend across the lifetime of the process. Halts when the total exceeds the configured cap.
81+
| Primitive | Config key | What it enforces |
82+
|-----------|------------|------------------|
83+
| **Budget cap** | `budget.dailyUSD` | Cumulative USD spend across the process lifetime. Halts when spend exceeds the cap. → [docs](./docs/enforcement.md#1-budget-cap) |
84+
| **Loop guard** | `loopGuard.maxToolCallsPerRun` | Total tool calls per `wrap()` invocation. Counter resets each run. → [docs](./docs/enforcement.md#2-loop-guard) |
85+
| **Tool throttle** | `toolThrottle.maxCallsPerMinute` | Rate of tool calls using a sliding 60-second window — no fixed buckets. → [docs](./docs/enforcement.md#3-tool-throttle) |
10386

104-
```typescript
105-
const authority = new AuthorityLayer({
106-
budget: { dailyUSD: 50 },
107-
});
108-
109-
// After each billable call, report the cost
110-
const response = await authority.tool("openai.chat", () =>
111-
openai.chat.completions.create({ model: "gpt-4o", messages })
112-
);
113-
const costUSD = response.usage.total_tokens * PRICE_PER_TOKEN;
114-
authority.recordSpend(costUSD);
115-
```
116-
117-
> **Why explicit spend reporting?** Different providers expose token counts and pricing differently. AuthorityLayer doesn't assume your pricing model — you calculate the USD cost and report it. This makes the integration provider-agnostic.
118-
119-
**Halt reason:** `"budget_exceeded"`
87+
When a primitive breaches, AuthorityLayer throws a typed `EnforcementHalt` error with a structured `.enforcement` object. Execution never crashes silently.
12088

12189
---
12290

123-
### 2. Loop Guard
124-
125-
Limits the total number of tool calls within a single `wrap()` invocation. The counter resets at the start of each `wrap()` call.
126-
127-
```typescript
128-
const authority = new AuthorityLayer({
129-
loopGuard: { maxToolCallsPerRun: 25 },
130-
});
131-
```
132-
133-
Every call to `authority.tool()` increments the counter *before* the tool function executes. If the limit is already reached, the tool function is never called.
134-
135-
**Halt reason:** `"loop_limit_exceeded"`
136-
137-
---
138-
139-
### 3. Tool Throttle
140-
141-
Rate-limits tool calls using a **sliding 60-second window** — not a fixed reset bucket. This accurately reflects the true call density over the last minute, preventing bursts at bucket boundaries.
142-
143-
```typescript
144-
const authority = new AuthorityLayer({
145-
toolThrottle: { maxCallsPerMinute: 60 },
146-
});
147-
```
148-
149-
On each `authority.tool()` call:
150-
1. Timestamps older than 60 seconds are evicted
151-
2. The current timestamp is added
152-
3. If the count exceeds `maxCallsPerMinute`, execution halts
153-
154-
**Halt reason:** `"tool_throttle_exceeded"`
155-
156-
---
157-
158-
## API Reference
159-
160-
### `new AuthorityLayer(config)`
161-
162-
```typescript
163-
interface AuthorityConfig {
164-
mode?: "strict" | "warn"; // Default: "strict"
165-
budget?: { dailyUSD: number };
166-
loopGuard?: { maxToolCallsPerRun: number };
167-
toolThrottle?: { maxCallsPerMinute: number };
168-
}
169-
```
170-
171-
| Mode | Behavior |
172-
|------|----------|
173-
| `"strict"` | Throws `EnforcementHalt` immediately when a limit is breached (default) |
174-
| `"warn"` | Emits a `console.warn`**stubbed in V1**, full implementation coming in a future release |
175-
176-
---
177-
178-
### `authority.wrap(fn)`
179-
180-
Wraps an agent run with enforcement. Resets per-run counters (loop guard) and logs `run.start` / `run.complete` events to the audit chain.
181-
182-
```typescript
183-
await authority.wrap(async () => {
184-
// your agent loop here
185-
});
186-
```
187-
188-
---
189-
190-
### `authority.tool(name, fn)`
191-
192-
The single hook for all external tool calls. Checks loop guard and throttle *before* calling `fn`. If either limit is breached, `fn` is never invoked.
193-
194-
```typescript
195-
const data = await authority.tool("stripe.charge", () =>
196-
stripe.charges.create({ amount: 100, currency: "usd" })
197-
);
198-
```
199-
200-
| Parameter | Type | Description |
201-
|-----------|------|-------------|
202-
| `name` | `string` | Human-readable label logged to the event chain |
203-
| `fn` | `() => Promise<T>` | The actual tool call |
204-
205-
---
206-
207-
### `authority.recordSpend(amountUSD)`
208-
209-
Report token or API spend in USD. Accumulates across all calls in the current process lifetime (not per-run). Call this after each model or billable API response.
210-
211-
```typescript
212-
authority.recordSpend(0.0042); // $0.0042 spent this call
213-
```
214-
215-
---
216-
217-
### `authority.getChain()`
218-
219-
Returns a read-only copy of the enforcement event chain. Useful for inspecting what happened during a run or persisting to disk.
220-
221-
```typescript
222-
const events = authority.getChain(); // ReadonlyArray<EnforcementEvent>
223-
```
224-
225-
Each event contains: `event_id`, `type`, `timestamp`, `data`, `hash`, `previousHash`.
226-
227-
---
228-
229-
### `authority.verifyChain()`
230-
231-
Verifies the integrity of the in-memory event chain. Returns `false` if any event has been tampered with, reordered, or removed.
232-
233-
```typescript
234-
const intact = authority.verifyChain(); // true | false
235-
```
236-
237-
---
238-
239-
## The HaltResult Object
240-
241-
When any guard breaches, AuthorityLayer throws an `EnforcementHalt` error. Access the structured result at `err.enforcement`:
242-
243-
```typescript
244-
interface HaltResult {
245-
status: "halted";
246-
reason: "budget_exceeded" | "loop_limit_exceeded" | "tool_throttle_exceeded";
247-
limit: number; // The configured limit that was breached
248-
spent: number; // The value that exceeded it (USD, call count, etc.)
249-
event_id: string; // Unique ID from the enforcement event chain
250-
}
251-
```
252-
253-
### Catching a halt
254-
255-
```typescript
256-
import { AuthorityLayer, EnforcementHalt } from "authority-layer";
257-
258-
try {
259-
await authority.wrap(async () => {
260-
// ... agent loop
261-
});
262-
} catch (err) {
263-
if (err instanceof EnforcementHalt) {
264-
// Always access via err.enforcement — never parse err.message
265-
const { reason, limit, spent, event_id } = err.enforcement;
266-
console.error(`Halted: ${reason} (${spent} > ${limit}) [${event_id}]`);
267-
// e.g. "Halted: budget_exceeded (52.14 > 50) [evt_3f9a2c1b...]"
268-
}
269-
}
270-
```
271-
272-
---
273-
274-
## Audit Chain
275-
276-
Every significant event in an agent run is logged to a hash-linked in-memory chain:
277-
278-
| Event type | When it fires |
279-
|------------|---------------|
280-
| `run.start` | At the start of each `wrap()` call |
281-
| `tool.call` | Each time `authority.tool()` is called |
282-
| `enforcement.halt` | When a limit is breached |
283-
| `run.complete` | When `wrap()` completes without error |
284-
| `run.error` | When an unexpected error is thrown inside `wrap()` |
285-
286-
Each event is cryptographically linked to its predecessor via SHA-256. Altering, reordering, or removing any event invalidates all subsequent hashes — detectable instantly with `verifyChain()`.
287-
288-
```typescript
289-
const events = authority.getChain();
290-
// [
291-
// { type: "run.start", event_id: "evt_a1b2...", hash: "...", ... },
292-
// { type: "tool.call", event_id: "evt_c3d4...", hash: "...", ... },
293-
// { type: "enforcement.halt", event_id: "evt_e5f6...", hash: "...", ... },
294-
// ]
295-
296-
authority.verifyChain(); // true — chain is intact
297-
```
298-
299-
> **V1 note:** The chain lives in memory only. It is not persisted to disk or anchored remotely. Persistence is planned for a future release.
300-
301-
---
302-
303-
## Live Example
304-
305-
See a live enforcement halt in action:
306-
307-
```bash
308-
git clone https://github.com/032383justin/authority-layer.git
309-
cd authority-layer && npm install && npm run example
310-
```
311-
312-
Output:
313-
314-
```
315-
Starting agent run...
316-
317-
[Tool 1] LLM: LLM response to: "What is 2 + 2?"
318-
[Tool 2] Search: Result 1 for "TypeScript enforcement patterns"
319-
[Tool 3] LLM: LLM response to: "Summarize the search results"
320-
[Tool 4] LLM: LLM response to: "Any follow-up questions?"
321-
[Tool 5] LLM: LLM response to: "Final answer"
322-
323-
⛔ Execution halted by AuthorityLayer
324-
325-
{
326-
"status": "halted",
327-
"reason": "budget_exceeded",
328-
"limit": 0.05,
329-
"spent": 0.07,
330-
"event_id": "evt_53ab5487b37cd9c0"
331-
}
332-
333-
── Enforcement Event Chain ──────────────────────────────────
334-
[run.start] evt_a1b2... @ 2025-01-01T00:00:00.000Z
335-
[tool.call] evt_c3d4... @ 2025-01-01T00:00:00.010Z
336-
[tool.call] evt_e5f6... @ 2025-01-01T00:00:00.021Z
337-
[tool.call] evt_g7h8... @ 2025-01-01T00:00:00.032Z
338-
[tool.call] evt_i9j0... @ 2025-01-01T00:00:00.043Z
339-
[tool.call] evt_k1l2... @ 2025-01-01T00:00:00.054Z
340-
[enforcement.halt] evt_m3n4... @ 2025-01-01T00:00:00.055Z
341-
342-
Chain integrity: ✅ verified
343-
Total events: 7
344-
```
345-
346-
---
347-
348-
## Example Run
349-
350-
![AuthorityLayer demo](https://raw.githubusercontent.com/032383justin/authority-layer/main/demo.svg)
351-
352-
---
353-
354-
## Core Guarantees
355-
356-
| Guarantee | Description |
357-
|-----------|-------------|
358-
| **Local-first enforcement** | Works fully offline — no network dependency in the enforcement path |
359-
| **Fail-closed by default** | Breaches halt execution; nothing is silently ignored |
360-
| **Structured halts** | Always throws `EnforcementHalt` with a typed `.enforcement` object — never a raw crash |
361-
| **Tamper-evident audit log** | Hash-linked event chain detects any post-hoc modification |
362-
| **Zero outbound calls** | Makes no network requests unless you explicitly wire an alert destination |
363-
| **No silent defaults** | Omitting a config key fully disables that primitive — no hidden guards running |
364-
365-
---
366-
367-
## Requirements
368-
369-
- **Node.js** >= 18.0.0
370-
- **TypeScript** >= 5.x (if using TypeScript) — types are bundled
371-
- No runtime dependencies
372-
373-
---
374-
375-
## What AuthorityLayer Is Not
376-
377-
- Not a governance platform
378-
- Not an observability suite
379-
- Not a FinOps analytics tool
380-
- Not a workflow orchestrator
91+
## Documentation
38192

382-
It is a primitive. It enforces boundaries. Nothing more.
93+
| Topic | File |
94+
|-------|------|
95+
| Concepts & philosophy | [docs/concepts.md](./docs/concepts.md) |
96+
| Enforcement primitives (full detail) | [docs/enforcement.md](./docs/enforcement.md) |
97+
| API reference | [docs/api.md](./docs/api.md) |
98+
| Integrity chain | [docs/integrity.md](./docs/integrity.md) |
99+
| Live example | `npm run example` |
383100

384101
---
385102

0 commit comments

Comments
 (0)