triage-ows 1.0.0
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.
- package/README.md +786 -0
- package/bin/triage-ows.js +218 -0
- package/bin/triage-policy.js +66 -0
- package/bin/triage-server.js +4 -0
- package/dashboard-dist/assets/index-Dnhi_dJQ.css +2 -0
- package/dashboard-dist/assets/index-g_2MwC-o.js +9 -0
- package/dashboard-dist/favicon.svg +7 -0
- package/dashboard-dist/index.html +16 -0
- package/dist/config.d.ts +32 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +61 -0
- package/dist/config.js.map +1 -0
- package/dist/emitter.d.ts +7 -0
- package/dist/emitter.d.ts.map +1 -0
- package/dist/emitter.js +41 -0
- package/dist/emitter.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/scoring/behavior.d.ts +3 -0
- package/dist/scoring/behavior.d.ts.map +1 -0
- package/dist/scoring/behavior.js +13 -0
- package/dist/scoring/behavior.js.map +1 -0
- package/dist/scoring/compliance.d.ts +3 -0
- package/dist/scoring/compliance.d.ts.map +1 -0
- package/dist/scoring/compliance.js +11 -0
- package/dist/scoring/compliance.js.map +1 -0
- package/dist/scoring/identity.d.ts +3 -0
- package/dist/scoring/identity.d.ts.map +1 -0
- package/dist/scoring/identity.js +16 -0
- package/dist/scoring/identity.js.map +1 -0
- package/dist/scoring/index.d.ts +10 -0
- package/dist/scoring/index.d.ts.map +1 -0
- package/dist/scoring/index.js +35 -0
- package/dist/scoring/index.js.map +1 -0
- package/dist/scoring/limits.d.ts +7 -0
- package/dist/scoring/limits.d.ts.map +1 -0
- package/dist/scoring/limits.js +9 -0
- package/dist/scoring/limits.js.map +1 -0
- package/dist/scoring/network.d.ts +3 -0
- package/dist/scoring/network.d.ts.map +1 -0
- package/dist/scoring/network.js +16 -0
- package/dist/scoring/network.js.map +1 -0
- package/dist/scoring/onchain.d.ts +4 -0
- package/dist/scoring/onchain.d.ts.map +1 -0
- package/dist/scoring/onchain.js +35 -0
- package/dist/scoring/onchain.js.map +1 -0
- package/dist/scoring/risk.d.ts +3 -0
- package/dist/scoring/risk.d.ts.map +1 -0
- package/dist/scoring/risk.js +22 -0
- package/dist/scoring/risk.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +405 -0
- package/dist/server.js.map +1 -0
- package/dist/store.d.ts +13 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +177 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +107 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +26 -0
- package/dist/types.js.map +1 -0
- package/dist/webbotauth.d.ts +38 -0
- package/dist/webbotauth.d.ts.map +1 -0
- package/dist/webbotauth.js +120 -0
- package/dist/webbotauth.js.map +1 -0
- package/dist/xmtp.d.ts +6 -0
- package/dist/xmtp.d.ts.map +1 -0
- package/dist/xmtp.js +161 -0
- package/dist/xmtp.js.map +1 -0
- package/package.json +58 -0
- package/policy-template.json +14 -0
- package/src/config.ts +86 -0
- package/src/emitter.ts +40 -0
- package/src/index.ts +18 -0
- package/src/scoring/behavior.ts +15 -0
- package/src/scoring/compliance.ts +12 -0
- package/src/scoring/identity.ts +12 -0
- package/src/scoring/index.ts +31 -0
- package/src/scoring/limits.ts +10 -0
- package/src/scoring/network.ts +18 -0
- package/src/scoring/onchain.ts +44 -0
- package/src/scoring/risk.ts +25 -0
- package/src/server.ts +410 -0
- package/src/store.ts +197 -0
- package/src/types.ts +137 -0
- package/src/webbotauth.ts +128 -0
- package/src/xmtp.ts +188 -0
- package/triage.config.example.json +22 -0
package/README.md
ADDED
|
@@ -0,0 +1,786 @@
|
|
|
1
|
+
# Triage x OWS
|
|
2
|
+
|
|
3
|
+
**Reputation-gated spending policies for the agent economy.**
|
|
4
|
+
|
|
5
|
+
Triage is a scoring server and policy engine for the [Open Wallet Standard](https://github.com/Open-Wallet-Standard). It evaluates every transaction an AI agent attempts, assigns a trust score based on 5 factors, and enforces dynamic spending limits. Agents start restricted and earn financial autonomy over time.
|
|
6
|
+
|
|
7
|
+
Triage does not create agents. It governs how much financial autonomy they earn.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
OWS Wallet --> triage-policy (stdin/stdout) --> Scoring Server --> APPROVE / DENY
|
|
11
|
+
|
|
|
12
|
+
Dashboard + XMTP
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# 1. Install
|
|
21
|
+
npm install triage-ows hono
|
|
22
|
+
|
|
23
|
+
# 2. Initialize config
|
|
24
|
+
npx triage-ows init
|
|
25
|
+
|
|
26
|
+
# 3. Start the server + dashboard
|
|
27
|
+
npx triage-ows dev
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Dashboard at `http://localhost:4021`. WebSocket at `ws://localhost:4021/ws`.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## How It Works
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
stdin (PolicyContext JSON)
|
|
38
|
+
|
|
|
39
|
+
+------v------+
|
|
40
|
+
| triage- | OWS spawns this as a subprocess
|
|
41
|
+
| policy | for every transaction
|
|
42
|
+
+------+------+
|
|
43
|
+
|
|
|
44
|
+
HTTP POST /api/policy/evaluate
|
|
45
|
+
|
|
|
46
|
+
+------v------+
|
|
47
|
+
| Scoring | 5-factor trust formula
|
|
48
|
+
| Server | + risk penalty
|
|
49
|
+
+------+------+
|
|
50
|
+
|
|
|
51
|
+
+------------+------------+
|
|
52
|
+
| | |
|
|
53
|
+
Record in Emit WS XMTP notify
|
|
54
|
+
store event (on deny)
|
|
55
|
+
| | |
|
|
56
|
+
v v v
|
|
57
|
+
Agent DB Dashboard Human owner
|
|
58
|
+
(in-mem) (React) (can override)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
1. **OWS spawns `triage-policy`** as a subprocess for each transaction
|
|
62
|
+
2. The executable reads `PolicyContext` from stdin and POSTs to the scoring server
|
|
63
|
+
3. The server computes the agent's trust score across 5 factors
|
|
64
|
+
4. Three checks run in order: frozen tier, per-transaction limit, daily limit
|
|
65
|
+
5. Result (`allow: true/false`) is written to stdout for OWS
|
|
66
|
+
6. Every decision is broadcast via WebSocket to the dashboard
|
|
67
|
+
7. Denials trigger XMTP notifications to the human owner, who can reply "override"
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Trust Formula
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
Trust Score = Identity + OnChain + Behavior + Compliance + Network - Risk
|
|
75
|
+
(0-35) (0-20) (0-20) (0-15) (0-5) (0-30)
|
|
76
|
+
|
|
77
|
+
Clamped to [0, 100]
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Identity (0-35)
|
|
81
|
+
|
|
82
|
+
Additive scoring with a hard cap at 35:
|
|
83
|
+
|
|
84
|
+
| Condition | Score | Cumulative |
|
|
85
|
+
|-----------|-------|------------|
|
|
86
|
+
| Fresh wallet (base) | 4 | 4 |
|
|
87
|
+
| Has transaction history | 12 | 12 |
|
|
88
|
+
| OWS wallet with approved transactions | 20 | 20 |
|
|
89
|
+
| + Web Bot Auth verified (RFC 9421) | +4 | 24 |
|
|
90
|
+
| + World ID verified (human proof) | +11 | 31-35 |
|
|
91
|
+
|
|
92
|
+
An OWS wallet with both Web Bot Auth and World ID: `min(35, 20 + 4 + 11) = 35`.
|
|
93
|
+
|
|
94
|
+
### On-Chain (0-20)
|
|
95
|
+
|
|
96
|
+
| Sub-factor | Max | Calculation |
|
|
97
|
+
|-----------|-----|-------------|
|
|
98
|
+
| Account age | 5 | `min(5, monthsOld * 0.5)` |
|
|
99
|
+
| Transaction count | 5 | `min(5, log10(totalRequests) * 2.5)` |
|
|
100
|
+
| Counterparty diversity | 5 | `min(5, uniqueCounterparties / 10 * 5)` |
|
|
101
|
+
| Balance (funded) | 5 | 5 if on-chain balance > 0, else 0 |
|
|
102
|
+
|
|
103
|
+
Balance is checked via Base Sepolia RPC (`viem`), cached for 10 minutes.
|
|
104
|
+
|
|
105
|
+
### Behavior (0-20)
|
|
106
|
+
|
|
107
|
+
| Sub-factor | Max | Calculation |
|
|
108
|
+
|-----------|-----|-------------|
|
|
109
|
+
| Success rate | 5 | `min(5, successfulRequests / totalRequests * 5)` |
|
|
110
|
+
| Pacing | 5 | 5 if <5 req/min, 2 if 5-15, 0 if >15 |
|
|
111
|
+
| Clean days | 5 | `min(5, consecutiveCleanDays * 0.5)` |
|
|
112
|
+
| Counterparty concentration | 5 | 5 if >=5 targets, 2 if >=2, 0 if 1 |
|
|
113
|
+
|
|
114
|
+
### Compliance (0-15)
|
|
115
|
+
|
|
116
|
+
| Sub-factor | Max | Calculation |
|
|
117
|
+
|-----------|-----|-------------|
|
|
118
|
+
| Approval rate | 5 | `min(5, totalApproved / totalDecisions * 5)` |
|
|
119
|
+
| Approval streak | 5 | `min(5, consecutiveApprovals * 0.25)` |
|
|
120
|
+
| Override frequency | 5 | `5 - min(5, humanOverrides * 1.67)` |
|
|
121
|
+
|
|
122
|
+
Fewer human overrides = higher compliance score. Agents that consistently stay within limits score highest.
|
|
123
|
+
|
|
124
|
+
### Network (0-5)
|
|
125
|
+
|
|
126
|
+
Average trust score of known counterparties, divided by 20. Agents that transact with other trusted agents earn network reputation.
|
|
127
|
+
|
|
128
|
+
Can be disabled via config: `networkScore.enabled: false`.
|
|
129
|
+
|
|
130
|
+
### Risk Penalty (0-30, subtracted)
|
|
131
|
+
|
|
132
|
+
| Factor | Max | Trigger |
|
|
133
|
+
|--------|-----|---------|
|
|
134
|
+
| Frequency spike | 10 | >15 requests in 60 seconds |
|
|
135
|
+
| Failed transactions | 5 | `min(5, failedRequests * 2)` |
|
|
136
|
+
| Inactivity decay | 5 | `min(5, hoursInactive * 0.5)` |
|
|
137
|
+
| Spend pressure | 5 | >85% daily limit + active approvals |
|
|
138
|
+
| Denial streak | 5 | `min(5, consecutiveDenials * 2.5)` |
|
|
139
|
+
|
|
140
|
+
Frequency penalty and inactivity decay rate are configurable.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Spending Tiers
|
|
145
|
+
|
|
146
|
+
| Tier | Min Score | Daily Limit | Per-Tx Limit | Color |
|
|
147
|
+
|------|-----------|-------------|--------------|-------|
|
|
148
|
+
| Sovereign | 80 | $1,000 | $500 | `#fff8e1` |
|
|
149
|
+
| Trusted | 60 | $200 | $100 | `#ffd700` |
|
|
150
|
+
| Building | 40 | $50 | $25 | `#4caf50` |
|
|
151
|
+
| Cautious | 20 | $10 | $5 | `#00bcd4` |
|
|
152
|
+
| Restricted | 1 | $2 | $1 | `#2196f3` |
|
|
153
|
+
| Frozen | 0 | $0 | $0 | `#1a1a4e` |
|
|
154
|
+
|
|
155
|
+
All limits are configurable via `triage.config.json` `scoreBands`.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## API Reference
|
|
160
|
+
|
|
161
|
+
### POST /api/policy/evaluate
|
|
162
|
+
|
|
163
|
+
Core policy evaluation endpoint. Called by `triage-policy` for every transaction.
|
|
164
|
+
|
|
165
|
+
**Headers:**
|
|
166
|
+
- `Content-Type: application/json`
|
|
167
|
+
- `x-policy-secret: <secret>` (optional, if `POLICY_SECRET` env is set)
|
|
168
|
+
- `Signature-Input` + `Signature` (optional, RFC 9421 Web Bot Auth)
|
|
169
|
+
|
|
170
|
+
**Request:**
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"chain_id": "eip155:84532",
|
|
174
|
+
"wallet_id": "5dccd73e-...",
|
|
175
|
+
"api_key_id": "0d3531c9-...",
|
|
176
|
+
"transaction": {
|
|
177
|
+
"to": "0xRecipient...",
|
|
178
|
+
"value": "1000000000000000",
|
|
179
|
+
"raw_hex": "0x",
|
|
180
|
+
"data": "0x"
|
|
181
|
+
},
|
|
182
|
+
"spending": {
|
|
183
|
+
"daily_total": "0",
|
|
184
|
+
"date": "2026-04-04"
|
|
185
|
+
},
|
|
186
|
+
"timestamp": "2026-04-04T12:00:00Z"
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Response (200):**
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"allow": true,
|
|
194
|
+
"trustScore": 82,
|
|
195
|
+
"tier": "Sovereign",
|
|
196
|
+
"dailyLimit": 1000,
|
|
197
|
+
"dailySpent": 150.50,
|
|
198
|
+
"perTxLimit": 500
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Denial reasons:**
|
|
203
|
+
- `Agent is frozen` (tier check)
|
|
204
|
+
- `Exceeds per-transaction limit ($500)` (per-tx check)
|
|
205
|
+
- `Exceeds daily spending limit ($1000)` (daily check)
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
curl -X POST http://localhost:4021/api/policy/evaluate \
|
|
209
|
+
-H "Content-Type: application/json" \
|
|
210
|
+
-d '{"chain_id":"eip155:84532","wallet_id":"w1","api_key_id":"k1","transaction":{"to":"0xABC","value":"1000000000000000","raw_hex":"0x","data":"0x"},"spending":{"daily_total":"0","date":"2026-04-04"},"timestamp":"2026-04-04T12:00:00Z"}'
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### POST /api/override/:address
|
|
214
|
+
|
|
215
|
+
Human override for a denied transaction. Boosts trust score by `overrideBoost` (default +3). Override expires after 5 minutes.
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
curl -X POST http://localhost:4021/api/override/0xAgentAddress
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Response (200):** Full `AgentProfile` JSON.
|
|
222
|
+
**Response (404):** `{ "error": "Agent not found" }` or `{ "error": "No pending override for this agent" }` (including expired overrides).
|
|
223
|
+
|
|
224
|
+
### GET /api/agents
|
|
225
|
+
|
|
226
|
+
Top 20 agents sorted by trust score.
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
curl http://localhost:4021/api/agents
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### GET /api/agents/:address
|
|
233
|
+
|
|
234
|
+
Single agent profile.
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
curl http://localhost:4021/api/agents/0xAgentAddress
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### POST /api/agents/:address/pubkey
|
|
241
|
+
|
|
242
|
+
Register an agent's Ed25519 public key for Web Bot Auth (RFC 9421).
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
curl -X POST http://localhost:4021/api/agents/0xAgent/pubkey \
|
|
246
|
+
-H "Content-Type: application/json" \
|
|
247
|
+
-d '{"publicKey":"base64EncodedEd25519PublicKey"}'
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### GET /api/stats
|
|
251
|
+
|
|
252
|
+
Aggregate statistics.
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
curl http://localhost:4021/api/stats
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Response:**
|
|
259
|
+
```json
|
|
260
|
+
{
|
|
261
|
+
"totalAgents": 5,
|
|
262
|
+
"totalDecisions": 142,
|
|
263
|
+
"totalApproved": 128,
|
|
264
|
+
"totalDenied": 14
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### POST /api/verify-context
|
|
269
|
+
|
|
270
|
+
World ID sign request. Returns signing parameters for client-side World ID verification. Returns 501 if `WORLD_ID_RP_ID` and `WORLD_ID_SIGNING_KEY` are not configured.
|
|
271
|
+
|
|
272
|
+
### POST /api/verify-human
|
|
273
|
+
|
|
274
|
+
World ID proof verification. Verifies proof server-side via World API, stores nullifier hash.
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
curl -X POST http://localhost:4021/api/verify-human \
|
|
278
|
+
-H "Content-Type: application/json" \
|
|
279
|
+
-d '{"address":"0xAgentAddress"}'
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### POST /api/x402/verify
|
|
283
|
+
|
|
284
|
+
Verify an x402 payment signature via the facilitator.
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
curl -X POST http://localhost:4021/api/x402/verify \
|
|
288
|
+
-H "Content-Type: application/json" \
|
|
289
|
+
-d '{"paymentHeader":"...","payTo":"0xRecipient","maxAmountRequired":"1000000"}'
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### GET /api/x402/payment-requirements
|
|
293
|
+
|
|
294
|
+
Returns payment info for HTTP 402 responses. Requires `PAY_TO_ADDRESS` env var.
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
curl http://localhost:4021/api/x402/payment-requirements
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### WebSocket: /ws
|
|
301
|
+
|
|
302
|
+
Real-time event stream. Connect to `ws://localhost:4021/ws`.
|
|
303
|
+
|
|
304
|
+
**Event types:**
|
|
305
|
+
```typescript
|
|
306
|
+
// Transaction decision
|
|
307
|
+
{ type: 'POLICY_DECISION', agent, amount, trustScore, tier, decision: 'APPROVE'|'DENY'|'OVERRIDE', reason, dailyLimit, dailySpent, timestamp }
|
|
308
|
+
|
|
309
|
+
// Trust score change (on override)
|
|
310
|
+
{ type: 'TRUST_CHANGE', agent, oldScore, newScore, oldTier, newTier, reason, timestamp }
|
|
311
|
+
|
|
312
|
+
// Budget warning (>80% daily limit)
|
|
313
|
+
{ type: 'BUDGET_WARNING', agent, spent, limit, percentage, timestamp }
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## CLI Reference
|
|
319
|
+
|
|
320
|
+
```
|
|
321
|
+
triage-ows -- Reputation-gated spending policies for OWS agent wallets
|
|
322
|
+
|
|
323
|
+
Usage:
|
|
324
|
+
triage-ows init Scaffold triage.config.json + .env.example
|
|
325
|
+
triage-ows dev Start scoring server + dashboard (dev mode)
|
|
326
|
+
triage-ows register Register Triage policy with OWS
|
|
327
|
+
triage-ows attach Attach an OWS agent to Triage governance
|
|
328
|
+
triage-ows seed Populate demo agents for testing
|
|
329
|
+
triage-ows status Show server status + agent summary
|
|
330
|
+
triage-ows help Show this help
|
|
331
|
+
|
|
332
|
+
Options:
|
|
333
|
+
--port <number> Server port (default: 4021)
|
|
334
|
+
--config <path> Config file path (default: ./triage.config.json)
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### triage-ows init
|
|
338
|
+
|
|
339
|
+
Creates `triage.config.json` and `.env.example` in the current directory. Skips if files already exist.
|
|
340
|
+
|
|
341
|
+
### triage-ows dev
|
|
342
|
+
|
|
343
|
+
Starts the scoring server and dashboard. Reads config from `triage.config.json`.
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
triage-ows dev --port 8080 --config ./custom.config.json
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### triage-ows register
|
|
350
|
+
|
|
351
|
+
Registers the Triage policy with OWS. Copies `policy-template.json` to `~/.ows/policies/triage-trust.json` and runs `ows policy create`.
|
|
352
|
+
|
|
353
|
+
### triage-ows attach
|
|
354
|
+
|
|
355
|
+
Creates an OWS API key attached to a wallet with the Triage policy.
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
triage-ows attach --wallet sovereign-agent --key sovereign-key
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Runs `ows key create --name <key> --wallet <wallet> --policy triage-trust`.
|
|
362
|
+
|
|
363
|
+
### triage-ows status
|
|
364
|
+
|
|
365
|
+
Shows server status and agent summary table.
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
triage-ows status --port 4021
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Library Usage
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
import {
|
|
377
|
+
// Server
|
|
378
|
+
app, startServer, BASE_SEPOLIA, USDC_BASE_SEPOLIA,
|
|
379
|
+
|
|
380
|
+
// Scoring
|
|
381
|
+
computeTrustScore, getSpendingLimits,
|
|
382
|
+
identityScore, onChainScore, behaviorScore,
|
|
383
|
+
complianceScore, networkScore, riskPenalty,
|
|
384
|
+
|
|
385
|
+
// Store
|
|
386
|
+
getOrCreateAgent, getAgent, getAllAgents, getTopAgents,
|
|
387
|
+
recordApproval, recordDenial, recordOverride,
|
|
388
|
+
addVerifiedHuman, isVerifiedHuman, setOWSWallet, setWebBotAuthVerified,
|
|
389
|
+
|
|
390
|
+
// Config
|
|
391
|
+
loadConfig, getConfig,
|
|
392
|
+
|
|
393
|
+
// Events
|
|
394
|
+
emitEvent, startWebSocketServer, attachWebSocketToServer,
|
|
395
|
+
|
|
396
|
+
// Web Bot Auth (RFC 9421)
|
|
397
|
+
verifyWebBotAuth, registerAgentPublicKey, parseSignatureInput,
|
|
398
|
+
|
|
399
|
+
// Types & Constants
|
|
400
|
+
getTierForScore, SPENDING_TIERS, updateSpendingTiers,
|
|
401
|
+
} from 'triage-ows'
|
|
402
|
+
|
|
403
|
+
import type {
|
|
404
|
+
PolicyContext, PolicyResult, TrustBreakdown, SpendingTier,
|
|
405
|
+
AgentProfile, TriageConfig,
|
|
406
|
+
PolicyDecisionEvent, TrustChangeEvent, BudgetWarningEvent, TriageEvent,
|
|
407
|
+
} from 'triage-ows'
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Scoring an Agent
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
413
|
+
const agent = getOrCreateAgent('0xAgentAddress')
|
|
414
|
+
const breakdown = computeTrustScore(agent, getAgent)
|
|
415
|
+
const { tier, dailyLimit, perTxLimit } = getSpendingLimits(breakdown.total)
|
|
416
|
+
|
|
417
|
+
console.log(`Score: ${breakdown.total}, Tier: ${tier.name}, Limit: $${dailyLimit}/day`)
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Recording Transactions
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
// Approved transaction
|
|
424
|
+
const updated = recordApproval('0xAgent', '0xRecipient', 25.50)
|
|
425
|
+
|
|
426
|
+
// Denied transaction (stores pending override)
|
|
427
|
+
const denied = recordDenial('0xAgent', tx, 500.00)
|
|
428
|
+
|
|
429
|
+
// Human override (expires after 5 minutes)
|
|
430
|
+
const overridden = recordOverride('0xAgent')
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Custom Scoring Server
|
|
434
|
+
|
|
435
|
+
```typescript
|
|
436
|
+
import { app, startServer } from 'triage-ows'
|
|
437
|
+
import { Hono } from 'hono'
|
|
438
|
+
|
|
439
|
+
// Add custom routes to the Hono app
|
|
440
|
+
app.get('/api/custom', (c) => c.json({ hello: 'world' }))
|
|
441
|
+
|
|
442
|
+
// Start with custom port
|
|
443
|
+
startServer(8080)
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Custom Config
|
|
447
|
+
|
|
448
|
+
```typescript
|
|
449
|
+
import { loadConfig, getConfig, updateSpendingTiers } from 'triage-ows'
|
|
450
|
+
|
|
451
|
+
// Load from custom path
|
|
452
|
+
loadConfig('/path/to/config.json')
|
|
453
|
+
|
|
454
|
+
// Read config values
|
|
455
|
+
const threshold = getConfig().warningThreshold
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### XMTP Notifications
|
|
459
|
+
|
|
460
|
+
XMTP uses native bindings (`@xmtp/node-sdk`). It's loaded lazily to avoid crashes on systems where bindings aren't available. The server handles this automatically — manual import is only needed for advanced library usage.
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
// XMTP requires native bindings — import lazily
|
|
464
|
+
const xmtp = await import('triage-ows/dist/xmtp')
|
|
465
|
+
await xmtp.initXMTP()
|
|
466
|
+
|
|
467
|
+
// Send notifications
|
|
468
|
+
await xmtp.notifyDenial(agent, amount, score, tier, limit, spent, reason, txTo)
|
|
469
|
+
await xmtp.notifyTrustChange(agent, oldScore, newScore, oldTier, newTier, reason)
|
|
470
|
+
await xmtp.notifyBudgetWarning(agent, spent, limit)
|
|
471
|
+
await xmtp.notifyAnomaly(agent, pattern, action, riskPenalty, oldScore, newScore)
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## Types Reference
|
|
477
|
+
|
|
478
|
+
### PolicyContext
|
|
479
|
+
|
|
480
|
+
The input to every policy evaluation. Sent by OWS to `triage-policy` via stdin.
|
|
481
|
+
|
|
482
|
+
| Field | Type | Description |
|
|
483
|
+
|-------|------|-------------|
|
|
484
|
+
| `chain_id` | `string` | Chain identifier (e.g. `eip155:84532`) |
|
|
485
|
+
| `wallet_id` | `string` | OWS wallet UUID |
|
|
486
|
+
| `api_key_id` | `string` | OWS API key UUID (used as agent identifier) |
|
|
487
|
+
| `transaction.to` | `string` | Recipient address |
|
|
488
|
+
| `transaction.value` | `string` | Transaction value in wei |
|
|
489
|
+
| `transaction.raw_hex` | `string` | Raw transaction hex |
|
|
490
|
+
| `transaction.data` | `string` | Transaction data |
|
|
491
|
+
| `spending.daily_total` | `string` | OWS-reported daily total |
|
|
492
|
+
| `spending.date` | `string` | Date string (ISO) |
|
|
493
|
+
| `timestamp` | `string` | Request timestamp (ISO) |
|
|
494
|
+
| `policy_config` | `Record<string, unknown>` | Optional policy-level config |
|
|
495
|
+
|
|
496
|
+
### AgentProfile
|
|
497
|
+
|
|
498
|
+
Complete agent state tracked by the store.
|
|
499
|
+
|
|
500
|
+
| Field | Type | Description |
|
|
501
|
+
|-------|------|-------------|
|
|
502
|
+
| `address` | `string` | Agent identifier (api_key_id) |
|
|
503
|
+
| `walletId` | `string?` | OWS wallet UUID |
|
|
504
|
+
| `apiKeyId` | `string?` | OWS API key UUID |
|
|
505
|
+
| `isOWSWallet` | `boolean` | Whether registered as OWS wallet |
|
|
506
|
+
| `worldIdVerified` | `boolean` | World ID human proof verified |
|
|
507
|
+
| `webBotAuthVerified` | `boolean` | RFC 9421 signature verified |
|
|
508
|
+
| `nullifierHash` | `string?` | World ID nullifier hash |
|
|
509
|
+
| `trustScore` | `number` | Current trust score (0-100) |
|
|
510
|
+
| `breakdown` | `TrustBreakdown` | Per-factor score breakdown |
|
|
511
|
+
| `tier` | `string` | Current spending tier name |
|
|
512
|
+
| `totalRequests` | `number` | Lifetime request count |
|
|
513
|
+
| `successfulRequests` | `number` | Lifetime approved count |
|
|
514
|
+
| `failedRequests` | `number` | Lifetime denied count |
|
|
515
|
+
| `dailySpent` | `number` | Today's spending in USD |
|
|
516
|
+
| `dailyDate` | `string` | Date of current daily tracking |
|
|
517
|
+
| `consecutiveApprovals` | `number` | Current approval streak |
|
|
518
|
+
| `consecutiveDenials` | `number` | Current denial streak |
|
|
519
|
+
| `totalApproved` | `number` | Lifetime approved transactions |
|
|
520
|
+
| `totalDenied` | `number` | Lifetime denied transactions |
|
|
521
|
+
| `humanOverrides` | `number` | Total human override count |
|
|
522
|
+
| `counterparties` | `string[]` | Unique transaction targets |
|
|
523
|
+
| `pendingOverride` | `object?` | Pending override data with `createdAt` timestamp |
|
|
524
|
+
| `requestTimestamps` | `number[]` | Last 100 request timestamps |
|
|
525
|
+
| `lastActive` | `number` | Last activity timestamp |
|
|
526
|
+
| `consecutiveCleanDays` | `number` | Days with only approved transactions |
|
|
527
|
+
| `cleanDayDate` | `string` | Date of last clean day check |
|
|
528
|
+
| `createdAt` | `number` | Agent creation timestamp |
|
|
529
|
+
|
|
530
|
+
### TrustBreakdown
|
|
531
|
+
|
|
532
|
+
| Field | Type | Range | Description |
|
|
533
|
+
|-------|------|-------|-------------|
|
|
534
|
+
| `identity` | `number` | 0-35 | Identity verification score |
|
|
535
|
+
| `onChain` | `number` | 0-20 | On-chain history score |
|
|
536
|
+
| `behavior` | `number` | 0-20 | Transaction behavior score |
|
|
537
|
+
| `compliance` | `number` | 0-15 | Policy compliance score |
|
|
538
|
+
| `network` | `number` | 0-5 | Network trust score |
|
|
539
|
+
| `risk` | `number` | 0-30 | Risk penalty (subtracted) |
|
|
540
|
+
| `total` | `number` | 0-100 | Final composite score |
|
|
541
|
+
|
|
542
|
+
### TriageConfig
|
|
543
|
+
|
|
544
|
+
| Option | Type | Default | Description |
|
|
545
|
+
|--------|------|---------|-------------|
|
|
546
|
+
| `scoreBands` | `Array` | 6 tiers | Custom tier definitions (name, min, dailyLimit, perTxLimit, color) |
|
|
547
|
+
| `warningThreshold` | `number` | `0.8` | Budget warning threshold (0-1) |
|
|
548
|
+
| `xmtp.enabled` | `boolean` | `true` | Enable XMTP notifications |
|
|
549
|
+
| `worldId.enabled` | `boolean` | `true` | Enable World ID verification |
|
|
550
|
+
| `webBotAuth.enabled` | `boolean` | `true` | Enable RFC 9421 signature verification |
|
|
551
|
+
| `networkScore.enabled` | `boolean` | `true` | Enable network trust scoring |
|
|
552
|
+
| `scoring.overrideBoost` | `number` | `3` | Trust score boost per human override |
|
|
553
|
+
| `scoring.maxFrequencyPenalty` | `number` | `10` | Max penalty for request frequency spikes |
|
|
554
|
+
| `scoring.inactivityDecayRate` | `number` | `0.5` | Trust decay per hour of inactivity |
|
|
555
|
+
| `port` | `number` | `4021` | Server port |
|
|
556
|
+
| `dashboardEnabled` | `boolean` | `true` | Serve dashboard static files |
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
## Configuration
|
|
561
|
+
|
|
562
|
+
### triage.config.json
|
|
563
|
+
|
|
564
|
+
Create with `triage-ows init` or manually:
|
|
565
|
+
|
|
566
|
+
```json
|
|
567
|
+
{
|
|
568
|
+
"warningThreshold": 0.8,
|
|
569
|
+
"scoreBands": [
|
|
570
|
+
{ "name": "Sovereign", "min": 80, "dailyLimit": 1000, "perTxLimit": 500 },
|
|
571
|
+
{ "name": "Trusted", "min": 60, "dailyLimit": 200, "perTxLimit": 100 },
|
|
572
|
+
{ "name": "Building", "min": 40, "dailyLimit": 50, "perTxLimit": 25 },
|
|
573
|
+
{ "name": "Cautious", "min": 20, "dailyLimit": 10, "perTxLimit": 5 },
|
|
574
|
+
{ "name": "Restricted", "min": 1, "dailyLimit": 2, "perTxLimit": 1 },
|
|
575
|
+
{ "name": "Frozen", "min": 0, "dailyLimit": 0, "perTxLimit": 0 }
|
|
576
|
+
],
|
|
577
|
+
"scoring": {
|
|
578
|
+
"overrideBoost": 3,
|
|
579
|
+
"maxFrequencyPenalty": 10,
|
|
580
|
+
"inactivityDecayRate": 0.5
|
|
581
|
+
},
|
|
582
|
+
"xmtp": { "enabled": true },
|
|
583
|
+
"worldId": { "enabled": true },
|
|
584
|
+
"webBotAuth": { "enabled": true },
|
|
585
|
+
"networkScore": { "enabled": true },
|
|
586
|
+
"port": 4021,
|
|
587
|
+
"dashboardEnabled": true
|
|
588
|
+
}
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
Config is loaded from (in order):
|
|
592
|
+
1. Path passed to `loadConfig(path)`
|
|
593
|
+
2. `TRIAGE_CONFIG_PATH` environment variable
|
|
594
|
+
3. `./triage.config.json` in the current working directory
|
|
595
|
+
4. Built-in defaults (if no file found)
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
## Environment Variables
|
|
600
|
+
|
|
601
|
+
| Variable | Required | Default | Description |
|
|
602
|
+
|----------|----------|---------|-------------|
|
|
603
|
+
| `PORT` | No | `4021` | Server port |
|
|
604
|
+
| `POLICY_SECRET` | No | - | Shared secret for policy endpoint authentication |
|
|
605
|
+
| `WORLD_ID_RP_ID` | No | - | World ID relying party ID |
|
|
606
|
+
| `WORLD_ID_SIGNING_KEY` | No | - | World ID signing key (hex) |
|
|
607
|
+
| `XMTP_PRIVATE_KEY` | No | - | Private key for XMTP notifications |
|
|
608
|
+
| `HUMAN_XMTP_ADDRESS` | No | - | Wallet address for XMTP DM notifications |
|
|
609
|
+
| `PAY_TO_ADDRESS` | No | - | Address for x402 payment requirements |
|
|
610
|
+
| `BASE_SEPOLIA_RPC_URL` | No | `https://sepolia.base.org` | Base Sepolia RPC endpoint |
|
|
611
|
+
| `SCORING_SERVER_URL` | No | `http://localhost:4021` | Scoring server URL (used by triage-policy) |
|
|
612
|
+
| `TRIAGE_CONFIG_PATH` | No | `./triage.config.json` | Path to config file |
|
|
613
|
+
|
|
614
|
+
Generate a `.env.example` with `triage-ows init`.
|
|
615
|
+
|
|
616
|
+
---
|
|
617
|
+
|
|
618
|
+
## Override Flow
|
|
619
|
+
|
|
620
|
+
```
|
|
621
|
+
1. Agent sends transaction
|
|
622
|
+
2. Policy evaluation: DENY (exceeds limit)
|
|
623
|
+
3. Server records pendingOverride with 5-minute TTL
|
|
624
|
+
4. XMTP notification sent to human owner:
|
|
625
|
+
|
|
626
|
+
"Transaction denied
|
|
627
|
+
Agent: 0xAgent...
|
|
628
|
+
Amount: $50.00 USDC -> 0xRecipient...
|
|
629
|
+
Trust score: 42 (Building tier)
|
|
630
|
+
Reason: Exceeds per-transaction limit ($25)
|
|
631
|
+
|
|
632
|
+
Reply 'override' to approve this transaction."
|
|
633
|
+
|
|
634
|
+
5. Human replies "override" in XMTP DM
|
|
635
|
+
6. Message listener detects reply, POSTs to /api/override/:address
|
|
636
|
+
7. Transaction approved, trust score boosted by +3
|
|
637
|
+
8. TRUST_CHANGE event emitted to dashboard
|
|
638
|
+
9. Override expires after 5 minutes if not acted on
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
---
|
|
642
|
+
|
|
643
|
+
## Dashboard
|
|
644
|
+
|
|
645
|
+
The dashboard is a React SPA served from `/` on the scoring server.
|
|
646
|
+
|
|
647
|
+
**Panels:**
|
|
648
|
+
|
|
649
|
+
- **Stat Cards** -- Total agents, policy decisions (with approval rate), active wallets, daily volume
|
|
650
|
+
- **Signing Decisions** -- Canvas particle visualization with 3 lanes (APPROVE green, DENY red, OVERRIDE gold). Particle size scales with transaction amount. Shows running $ volume per lane.
|
|
651
|
+
- **Agent Budgets** -- Top 5 agents with progress bars showing daily spend vs limit. 80% tick marker. Tier labels.
|
|
652
|
+
- **Policy Decisions** -- Real-time feed of every transaction decision with agent, score, amount, budget usage, and denial reasons
|
|
653
|
+
- **Trust Leaderboard** -- Top 8 agents ranked by score with tier badges, score bars, daily limits, trend arrows, and World ID / Web Bot Auth verification icons
|
|
654
|
+
|
|
655
|
+
---
|
|
656
|
+
|
|
657
|
+
## Security
|
|
658
|
+
|
|
659
|
+
- **Policy Secret** -- Optional shared secret (`POLICY_SECRET` env) authenticates the policy evaluation endpoint. Both the executable and server must share the same secret.
|
|
660
|
+
- **World ID** -- Nullifier hashes are verified server-side via the World API. The client never self-reports verification status.
|
|
661
|
+
- **Override Timeout** -- Pending overrides expire after 5 minutes. Stale overrides cannot be replayed.
|
|
662
|
+
- **Input Validation** -- Policy evaluation validates JSON structure, handles malformed BigInt values gracefully (falls back to 0).
|
|
663
|
+
- **XMTP Graceful Fallback** -- XMTP is lazy-loaded. If native bindings are unavailable, the server starts normally with notifications disabled.
|
|
664
|
+
- **Web Bot Auth** -- Ed25519 signature verification follows RFC 9421. Public keys must be pre-registered via the API.
|
|
665
|
+
|
|
666
|
+
---
|
|
667
|
+
|
|
668
|
+
## Features
|
|
669
|
+
|
|
670
|
+
- **5-factor trust scoring** -- Identity, On-Chain, Behavior, Compliance, Network minus Risk
|
|
671
|
+
- **6 spending tiers** -- Sovereign through Frozen with configurable limits
|
|
672
|
+
- **Real-time dashboard** -- Canvas particle flow, live feed, leaderboard, budget tracking
|
|
673
|
+
- **XMTP notifications** -- Denial alerts, budget warnings, trust changes via DM
|
|
674
|
+
- **Human override** -- Reply "override" in XMTP to approve denied transactions (+3 trust boost)
|
|
675
|
+
- **Override timeout** -- 5-minute expiry on pending overrides
|
|
676
|
+
- **Web Bot Auth** -- RFC 9421 HTTP Message Signatures for cryptographic agent identity
|
|
677
|
+
- **World ID** -- Human verification via World ID proof-of-personhood
|
|
678
|
+
- **x402 payments** -- Payment verification via x402 facilitator
|
|
679
|
+
- **ETH price oracle** -- Live CoinGecko price feed with 5-minute cache and $2,500 fallback
|
|
680
|
+
- **On-chain balance** -- Base Sepolia balance lookup via viem with 10-minute cache
|
|
681
|
+
- **Configurable** -- `triage.config.json` for tiers, thresholds, feature flags, scoring tuning
|
|
682
|
+
- **CLI** -- init, dev, register, attach, seed, status commands
|
|
683
|
+
- **Policy secret** -- Optional shared secret for endpoint authentication
|
|
684
|
+
- **Budget warnings** -- Configurable threshold (default 80%) with XMTP alerts
|
|
685
|
+
- **WebSocket events** -- Real-time POLICY_DECISION, TRUST_CHANGE, BUDGET_WARNING streams
|
|
686
|
+
|
|
687
|
+
---
|
|
688
|
+
|
|
689
|
+
## Technologies
|
|
690
|
+
|
|
691
|
+
| Technology | Role |
|
|
692
|
+
|-----------|------|
|
|
693
|
+
| [Hono](https://hono.dev) | HTTP framework |
|
|
694
|
+
| [viem](https://viem.sh) | On-chain queries (Base Sepolia) |
|
|
695
|
+
| [XMTP](https://xmtp.org) | Agent-to-human messaging (`@xmtp/node-sdk`) |
|
|
696
|
+
| [World ID](https://worldcoin.org/world-id) | Human proof-of-personhood |
|
|
697
|
+
| [x402](https://x402.org) | Payment verification protocol |
|
|
698
|
+
| [ws](https://github.com/websockets/ws) | WebSocket server |
|
|
699
|
+
| [React](https://react.dev) | Dashboard UI |
|
|
700
|
+
| [Tailwind CSS](https://tailwindcss.com) | Dashboard styling |
|
|
701
|
+
| [CoinGecko](https://www.coingecko.com) | ETH/USD price feed |
|
|
702
|
+
| Node.js `crypto` | Ed25519 signature verification (RFC 9421) |
|
|
703
|
+
|
|
704
|
+
---
|
|
705
|
+
|
|
706
|
+
## OWS Integration
|
|
707
|
+
|
|
708
|
+
### Register the Policy
|
|
709
|
+
|
|
710
|
+
```bash
|
|
711
|
+
# Registers triage-trust policy with OWS
|
|
712
|
+
triage-ows register
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
This copies `policy-template.json` to `~/.ows/policies/triage-trust.json` and runs `ows policy create`.
|
|
716
|
+
|
|
717
|
+
### Attach an Agent
|
|
718
|
+
|
|
719
|
+
```bash
|
|
720
|
+
# Create an OWS API key with Triage governance
|
|
721
|
+
triage-ows attach --wallet my-agent --key my-agent-key
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
This runs `ows key create --name <key> --wallet <wallet> --policy triage-trust`.
|
|
725
|
+
|
|
726
|
+
### Policy Template
|
|
727
|
+
|
|
728
|
+
```json
|
|
729
|
+
{
|
|
730
|
+
"id": "triage-trust",
|
|
731
|
+
"name": "Triage Reputation-Gated Policy",
|
|
732
|
+
"version": 1,
|
|
733
|
+
"rules": [
|
|
734
|
+
{ "type": "allowed_chains", "chain_ids": ["eip155:84532"] }
|
|
735
|
+
],
|
|
736
|
+
"executable": "./node_modules/.bin/triage-policy",
|
|
737
|
+
"config": {
|
|
738
|
+
"scoring_server": "http://localhost:4021"
|
|
739
|
+
},
|
|
740
|
+
"action": "deny"
|
|
741
|
+
}
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
The `action: "deny"` means transactions are blocked by default if the policy executable fails or times out.
|
|
745
|
+
|
|
746
|
+
---
|
|
747
|
+
|
|
748
|
+
## Demo & Simulation
|
|
749
|
+
|
|
750
|
+
### Seed Demo Agents
|
|
751
|
+
|
|
752
|
+
```bash
|
|
753
|
+
npm run seed
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
Creates 5 agents at different trust levels: Sovereign (~81), Trusted (~72), Building (~53), Cautious (~23), Restricted (~17).
|
|
757
|
+
|
|
758
|
+
### Run Live Simulation
|
|
759
|
+
|
|
760
|
+
```bash
|
|
761
|
+
# Start server in one terminal
|
|
762
|
+
triage-ows dev
|
|
763
|
+
|
|
764
|
+
# Run simulation in another
|
|
765
|
+
npm run simulate
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
The simulator fires policy evaluations every 2-3 seconds with randomized amounts, occasionally triggering denials and new agent registrations.
|
|
769
|
+
|
|
770
|
+
---
|
|
771
|
+
|
|
772
|
+
## What's Next
|
|
773
|
+
|
|
774
|
+
- **Persistence** -- SQLite or Postgres backend for agent state
|
|
775
|
+
- **Multi-chain** -- Extend beyond Base Sepolia to mainnet and other chains
|
|
776
|
+
- **Full network scoring** -- Graph-based trust propagation across agent networks
|
|
777
|
+
- **Trust portability** -- Export/import agent trust scores across Triage instances
|
|
778
|
+
- **Policy marketplace** -- Share and compose policy configurations
|
|
779
|
+
- **Anomaly detection** -- ML-based pattern detection triggering `notifyAnomaly`
|
|
780
|
+
- **Rate limiting** -- Per-agent request rate limits on the API
|
|
781
|
+
|
|
782
|
+
---
|
|
783
|
+
|
|
784
|
+
## License
|
|
785
|
+
|
|
786
|
+
MIT
|