@adhd/agent-mcp 2.0.1 → 2.1.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.
Files changed (299) hide show
  1. package/AGENTS.md +236 -0
  2. package/CHANGELOG.md +115 -0
  3. package/LICENSE +21 -0
  4. package/README.md +201 -0
  5. package/docs/architecture-and-security.md +405 -0
  6. package/docs/marketing/.catalog/capabilities.md +143 -0
  7. package/docs/marketing/.catalog/consumer.md +111 -0
  8. package/docs/marketing/.catalog/distribution.md +223 -0
  9. package/docs/marketing/.catalog/doc-conformance.md +237 -0
  10. package/docs/marketing/.catalog/doc-ops.md +98 -0
  11. package/docs/marketing/.catalog/metrics.md +119 -0
  12. package/docs/marketing/.catalog/required-tooling.md +224 -0
  13. package/docs/marketing/.catalog/review.md +164 -0
  14. package/docs/provider-call-audit.md +254 -0
  15. package/llms.txt +133 -0
  16. package/package.json +30 -51
  17. package/src/__tests__/integration/harness.d.ts +871 -39
  18. package/src/__tests__/integration/harness.d.ts.map +1 -1
  19. package/src/__tests__/integration/harness.js +93 -87
  20. package/src/__tests__/integration/harness.js.map +1 -1
  21. package/src/__tests__/integration/scripted-provider.d.ts +1 -2
  22. package/src/__tests__/integration/scripted-provider.d.ts.map +1 -1
  23. package/src/__tests__/integration/scripted-provider.js +1 -3
  24. package/src/__tests__/integration/scripted-provider.js.map +1 -1
  25. package/src/config.d.ts +6 -69
  26. package/src/config.d.ts.map +1 -1
  27. package/src/config.js +1 -50
  28. package/src/config.js.map +1 -1
  29. package/src/db/client.d.ts +1516 -2
  30. package/src/db/client.d.ts.map +1 -1
  31. package/src/db/client.js +4 -2
  32. package/src/db/client.js.map +1 -1
  33. package/src/db/migrate-runner.d.ts +0 -28
  34. package/src/db/migrate-runner.d.ts.map +1 -1
  35. package/src/db/migrate-runner.js +0 -24
  36. package/src/db/migrate-runner.js.map +1 -1
  37. package/src/db/migrate.d.ts +0 -7
  38. package/src/db/migrate.d.ts.map +1 -1
  39. package/src/db/migrate.js +0 -7
  40. package/src/db/migrate.js.map +1 -1
  41. package/src/db/schema.d.ts +0 -1260
  42. package/src/db/schema.d.ts.map +1 -1
  43. package/src/db/schema.js +2 -179
  44. package/src/db/schema.js.map +1 -1
  45. package/src/index.d.ts +3 -42
  46. package/src/index.d.ts.map +1 -1
  47. package/src/index.js +32 -123
  48. package/src/index.js.map +1 -1
  49. package/src/logger.d.ts +0 -8
  50. package/src/logger.d.ts.map +1 -1
  51. package/src/logger.js +1 -12
  52. package/src/logger.js.map +1 -1
  53. package/src/scripts/agent-mcp-tail.d.ts +3 -0
  54. package/src/scripts/agent-mcp-tail.d.ts.map +1 -0
  55. package/src/scripts/agent-mcp-tail.js +227 -0
  56. package/src/scripts/agent-mcp-tail.js.map +1 -0
  57. package/src/server.d.ts +13 -34
  58. package/src/server.d.ts.map +1 -1
  59. package/src/server.js +234 -326
  60. package/src/server.js.map +1 -1
  61. package/src/store/agent-store.d.ts +3 -16
  62. package/src/store/agent-store.d.ts.map +1 -1
  63. package/src/store/agent-store.js +38 -41
  64. package/src/store/agent-store.js.map +1 -1
  65. package/src/streaming/chat-gateway.d.ts +17 -0
  66. package/src/streaming/chat-gateway.d.ts.map +1 -0
  67. package/src/streaming/chat-gateway.js +336 -0
  68. package/src/streaming/chat-gateway.js.map +1 -0
  69. package/src/streaming/event-bus.d.ts +4 -0
  70. package/src/streaming/event-bus.d.ts.map +1 -1
  71. package/src/streaming/event-bus.js +14 -1
  72. package/src/streaming/event-bus.js.map +1 -1
  73. package/src/streaming/sse-server.d.ts +3 -14
  74. package/src/streaming/sse-server.d.ts.map +1 -1
  75. package/src/streaming/sse-server.js +37 -37
  76. package/src/streaming/sse-server.js.map +1 -1
  77. package/src/utils/load-env.d.ts +0 -14
  78. package/src/utils/load-env.d.ts.map +1 -1
  79. package/src/utils/load-env.js +0 -18
  80. package/src/utils/load-env.js.map +1 -1
  81. package/drizzle/0000_nifty_sasquatch.sql +0 -55
  82. package/drizzle/0001_task_usage.sql +0 -16
  83. package/drizzle/0002_lumpy_silver_centurion.sql +0 -2
  84. package/drizzle/0003_nifty_shriek.sql +0 -2
  85. package/drizzle/0004_brief_shocker.sql +0 -4
  86. package/drizzle/0005_clear_lenny_balinger.sql +0 -25
  87. package/drizzle/0006_composed_prompts_cache.sql +0 -24
  88. package/drizzle/meta/0000_snapshot.json +0 -387
  89. package/drizzle/meta/0001_snapshot.json +0 -495
  90. package/drizzle/meta/0002_snapshot.json +0 -509
  91. package/drizzle/meta/0003_snapshot.json +0 -523
  92. package/drizzle/meta/0004_snapshot.json +0 -551
  93. package/drizzle/meta/0005_snapshot.json +0 -545
  94. package/drizzle/meta/0006_snapshot.json +0 -651
  95. package/drizzle/meta/_journal.json +0 -55
  96. package/src/clients/http-client.d.ts +0 -24
  97. package/src/clients/http-client.d.ts.map +0 -1
  98. package/src/clients/http-client.js +0 -98
  99. package/src/clients/http-client.js.map +0 -1
  100. package/src/clients/in-process.d.ts +0 -27
  101. package/src/clients/in-process.d.ts.map +0 -1
  102. package/src/clients/in-process.js +0 -37
  103. package/src/clients/in-process.js.map +0 -1
  104. package/src/clients/index.d.ts +0 -7
  105. package/src/clients/index.d.ts.map +0 -1
  106. package/src/clients/index.js +0 -5
  107. package/src/clients/index.js.map +0 -1
  108. package/src/clients/registry.d.ts +0 -54
  109. package/src/clients/registry.d.ts.map +0 -1
  110. package/src/clients/registry.js +0 -164
  111. package/src/clients/registry.js.map +0 -1
  112. package/src/clients/stdio-client.d.ts +0 -16
  113. package/src/clients/stdio-client.d.ts.map +0 -1
  114. package/src/clients/stdio-client.js +0 -97
  115. package/src/clients/stdio-client.js.map +0 -1
  116. package/src/clients/tool-naming.d.ts +0 -44
  117. package/src/clients/tool-naming.d.ts.map +0 -1
  118. package/src/clients/tool-naming.js +0 -65
  119. package/src/clients/tool-naming.js.map +0 -1
  120. package/src/clients/types.d.ts +0 -18
  121. package/src/clients/types.d.ts.map +0 -1
  122. package/src/clients/types.js +0 -2
  123. package/src/clients/types.js.map +0 -1
  124. package/src/engine/dag-engine.d.ts +0 -62
  125. package/src/engine/dag-engine.d.ts.map +0 -1
  126. package/src/engine/dag-engine.js +0 -158
  127. package/src/engine/dag-engine.js.map +0 -1
  128. package/src/engine/hooks.d.ts +0 -24
  129. package/src/engine/hooks.d.ts.map +0 -1
  130. package/src/engine/hooks.js +0 -50
  131. package/src/engine/hooks.js.map +0 -1
  132. package/src/engine/orchestrator.d.ts +0 -40
  133. package/src/engine/orchestrator.d.ts.map +0 -1
  134. package/src/engine/orchestrator.js +0 -507
  135. package/src/engine/orchestrator.js.map +0 -1
  136. package/src/engine/policy.d.ts +0 -66
  137. package/src/engine/policy.d.ts.map +0 -1
  138. package/src/engine/policy.js +0 -112
  139. package/src/engine/policy.js.map +0 -1
  140. package/src/engine/prompt-resolver.d.ts +0 -89
  141. package/src/engine/prompt-resolver.d.ts.map +0 -1
  142. package/src/engine/prompt-resolver.js +0 -96
  143. package/src/engine/prompt-resolver.js.map +0 -1
  144. package/src/engine/queue.d.ts +0 -29
  145. package/src/engine/queue.d.ts.map +0 -1
  146. package/src/engine/queue.js +0 -56
  147. package/src/engine/queue.js.map +0 -1
  148. package/src/plugins/index.d.ts +0 -2
  149. package/src/plugins/index.d.ts.map +0 -1
  150. package/src/plugins/index.js +0 -2
  151. package/src/plugins/index.js.map +0 -1
  152. package/src/plugins/loader.d.ts +0 -65
  153. package/src/plugins/loader.d.ts.map +0 -1
  154. package/src/plugins/loader.js +0 -222
  155. package/src/plugins/loader.js.map +0 -1
  156. package/src/plugins/usage-plugin.d.ts +0 -27
  157. package/src/plugins/usage-plugin.d.ts.map +0 -1
  158. package/src/plugins/usage-plugin.js +0 -148
  159. package/src/plugins/usage-plugin.js.map +0 -1
  160. package/src/providers/anthropic.d.ts +0 -13
  161. package/src/providers/anthropic.d.ts.map +0 -1
  162. package/src/providers/anthropic.js +0 -260
  163. package/src/providers/anthropic.js.map +0 -1
  164. package/src/providers/claudecli.d.ts +0 -153
  165. package/src/providers/claudecli.d.ts.map +0 -1
  166. package/src/providers/claudecli.js +0 -510
  167. package/src/providers/claudecli.js.map +0 -1
  168. package/src/providers/factory.d.ts +0 -10
  169. package/src/providers/factory.d.ts.map +0 -1
  170. package/src/providers/factory.js +0 -24
  171. package/src/providers/factory.js.map +0 -1
  172. package/src/providers/index.d.ts +0 -6
  173. package/src/providers/index.d.ts.map +0 -1
  174. package/src/providers/index.js +0 -5
  175. package/src/providers/index.js.map +0 -1
  176. package/src/providers/openai.d.ts +0 -14
  177. package/src/providers/openai.d.ts.map +0 -1
  178. package/src/providers/openai.js +0 -162
  179. package/src/providers/openai.js.map +0 -1
  180. package/src/providers/types.d.ts +0 -36
  181. package/src/providers/types.d.ts.map +0 -1
  182. package/src/providers/types.js +0 -2
  183. package/src/providers/types.js.map +0 -1
  184. package/src/store/composed-prompt-store.d.ts +0 -24
  185. package/src/store/composed-prompt-store.d.ts.map +0 -1
  186. package/src/store/composed-prompt-store.js +0 -75
  187. package/src/store/composed-prompt-store.js.map +0 -1
  188. package/src/store/index.d.ts +0 -5
  189. package/src/store/index.d.ts.map +0 -1
  190. package/src/store/index.js +0 -5
  191. package/src/store/index.js.map +0 -1
  192. package/src/store/session-store.d.ts +0 -45
  193. package/src/store/session-store.d.ts.map +0 -1
  194. package/src/store/session-store.js +0 -197
  195. package/src/store/session-store.js.map +0 -1
  196. package/src/store/task-store.d.ts +0 -55
  197. package/src/store/task-store.d.ts.map +0 -1
  198. package/src/store/task-store.js +0 -186
  199. package/src/store/task-store.js.map +0 -1
  200. package/src/tools/agent-crud.d.ts +0 -15
  201. package/src/tools/agent-crud.d.ts.map +0 -1
  202. package/src/tools/agent-crud.js +0 -32
  203. package/src/tools/agent-crud.js.map +0 -1
  204. package/src/tools/session.d.ts +0 -33
  205. package/src/tools/session.d.ts.map +0 -1
  206. package/src/tools/session.js +0 -73
  207. package/src/tools/session.js.map +0 -1
  208. package/src/tools/task.d.ts +0 -86
  209. package/src/tools/task.d.ts.map +0 -1
  210. package/src/tools/task.js +0 -406
  211. package/src/tools/task.js.map +0 -1
  212. package/src/tools/usage.d.ts +0 -60
  213. package/src/tools/usage.d.ts.map +0 -1
  214. package/src/tools/usage.js +0 -174
  215. package/src/tools/usage.js.map +0 -1
  216. package/src/types/agent.d.ts +0 -2
  217. package/src/types/agent.d.ts.map +0 -1
  218. package/src/types/agent.js +0 -3
  219. package/src/types/agent.js.map +0 -1
  220. package/src/types/execution.d.ts +0 -2
  221. package/src/types/execution.d.ts.map +0 -1
  222. package/src/types/execution.js +0 -3
  223. package/src/types/execution.js.map +0 -1
  224. package/src/types/index.d.ts +0 -2
  225. package/src/types/index.d.ts.map +0 -1
  226. package/src/types/index.js +0 -2
  227. package/src/types/index.js.map +0 -1
  228. package/src/types/mcp.d.ts +0 -2
  229. package/src/types/mcp.d.ts.map +0 -1
  230. package/src/types/mcp.js +0 -3
  231. package/src/types/mcp.js.map +0 -1
  232. package/src/types/message.d.ts +0 -2
  233. package/src/types/message.d.ts.map +0 -1
  234. package/src/types/message.js +0 -3
  235. package/src/types/message.js.map +0 -1
  236. package/src/types/session.d.ts +0 -2
  237. package/src/types/session.d.ts.map +0 -1
  238. package/src/types/session.js +0 -3
  239. package/src/types/session.js.map +0 -1
  240. package/src/types/task.d.ts +0 -2
  241. package/src/types/task.d.ts.map +0 -1
  242. package/src/types/task.js +0 -3
  243. package/src/types/task.js.map +0 -1
  244. package/src/utils/ids.d.ts +0 -2
  245. package/src/utils/ids.d.ts.map +0 -1
  246. package/src/utils/ids.js +0 -5
  247. package/src/utils/ids.js.map +0 -1
  248. package/src/utils/logger.d.ts +0 -2
  249. package/src/utils/logger.d.ts.map +0 -1
  250. package/src/utils/logger.js +0 -5
  251. package/src/utils/logger.js.map +0 -1
  252. package/src/utils/timestamps.d.ts +0 -2
  253. package/src/utils/timestamps.d.ts.map +0 -1
  254. package/src/utils/timestamps.js +0 -4
  255. package/src/utils/timestamps.js.map +0 -1
  256. package/src/validation/agent.d.ts +0 -400
  257. package/src/validation/agent.d.ts.map +0 -1
  258. package/src/validation/agent.js +0 -251
  259. package/src/validation/agent.js.map +0 -1
  260. package/src/validation/agents.d.ts +0 -2
  261. package/src/validation/agents.d.ts.map +0 -1
  262. package/src/validation/agents.js +0 -3
  263. package/src/validation/agents.js.map +0 -1
  264. package/src/validation/errors.d.ts +0 -32
  265. package/src/validation/errors.d.ts.map +0 -1
  266. package/src/validation/errors.js +0 -42
  267. package/src/validation/errors.js.map +0 -1
  268. package/src/validation/execution.d.ts +0 -86
  269. package/src/validation/execution.d.ts.map +0 -1
  270. package/src/validation/execution.js +0 -28
  271. package/src/validation/execution.js.map +0 -1
  272. package/src/validation/index.d.ts +0 -9
  273. package/src/validation/index.d.ts.map +0 -1
  274. package/src/validation/index.js +0 -9
  275. package/src/validation/index.js.map +0 -1
  276. package/src/validation/mcp.d.ts +0 -42
  277. package/src/validation/mcp.d.ts.map +0 -1
  278. package/src/validation/mcp.js +0 -28
  279. package/src/validation/mcp.js.map +0 -1
  280. package/src/validation/message.d.ts +0 -43
  281. package/src/validation/message.d.ts.map +0 -1
  282. package/src/validation/message.js +0 -23
  283. package/src/validation/message.js.map +0 -1
  284. package/src/validation/session.d.ts +0 -49
  285. package/src/validation/session.d.ts.map +0 -1
  286. package/src/validation/session.js +0 -34
  287. package/src/validation/session.js.map +0 -1
  288. package/src/validation/task.d.ts +0 -146
  289. package/src/validation/task.d.ts.map +0 -1
  290. package/src/validation/task.js +0 -95
  291. package/src/validation/task.js.map +0 -1
  292. package/src/validation/tasks.d.ts +0 -2
  293. package/src/validation/tasks.d.ts.map +0 -1
  294. package/src/validation/tasks.js +0 -3
  295. package/src/validation/tasks.js.map +0 -1
  296. package/src/validation/usage.d.ts +0 -89
  297. package/src/validation/usage.d.ts.map +0 -1
  298. package/src/validation/usage.js +0 -98
  299. package/src/validation/usage.js.map +0 -1
@@ -0,0 +1,405 @@
1
+ # Architecture and Security — @adhd/agent-mcp
2
+
3
+ This document explains the system design, process model, state management, and security properties of the agent-mcp runtime.
4
+
5
+ ## System Boundaries
6
+
7
+ ```
8
+ MCP Client (e.g., Claude Desktop)
9
+ |
10
+ | JSON-RPC (stdio)
11
+ v
12
+ Agent MCP Server
13
+ |
14
+ +-- State Store (SQLite)
15
+ | +-- agents
16
+ | +-- sessions
17
+ | +-- messages
18
+ | +-- task_usage
19
+ |
20
+ +-- Policy Engine
21
+ | +-- Delegation depth limits
22
+ | +-- Token/cost budgets
23
+ | +-- Filesystem scopes
24
+ | +-- Tool filters
25
+ |
26
+ +-- Agent Supervisor
27
+ | +-- Spawn management
28
+ | +-- Lifecycle (running, completed, failed, cancelled)
29
+ | +-- Execution traces
30
+ |
31
+ +-- Provider Adapters
32
+ | +-- Anthropic (claude-opus, claude-sonnet, etc.)
33
+ | +-- OpenAI (gpt-4-turbo, gpt-4o, etc.)
34
+ | +-- DeepSeek (deepseek-v4-flash, deepseek-v4-pro)
35
+ | +-- Gemini (gemini-2.5-pro, etc.)
36
+ |
37
+ +-- Tool Gateway
38
+ | +-- Filesystem MCP tools
39
+ | +-- Shell execution
40
+ | +-- Network requests
41
+ | +-- External MCP servers
42
+ ```
43
+
44
+ The agent-mcp server is a **stateful process** that:
45
+ 1. Exposes MCP tools to create, control, and inspect agents
46
+ 2. Manages a SQLite database of agents, conversations, and execution history
47
+ 3. Enforces runtime policies before each tool call
48
+ 4. Translates between MCP and provider APIs
49
+ 5. Handles retries, cancellation, and error recovery
50
+
51
+ ## Process Model
52
+
53
+ ### Single Agent Execution
54
+
55
+ ```
56
+ agent_create(name, config, provider, model, budget)
57
+ ↓ (validates agent name, policy, budget)
58
+ ↓ (creates row in agents table)
59
+
60
+ task(agentName, prompt) # optionally background: true
61
+ ↓ (fetches agent config and session history)
62
+ ↓ (constructs message list with system prompt + tools)
63
+ ↓ (calls provider.chat())
64
+ ↓ (checks if model returned tool calls)
65
+ ↓ if tool calls:
66
+ | ├─ [for each tool]
67
+ | | ├─ policy.canCallTool(agentName, tool)? (enforced)
68
+ | | ├─ execute tool (may call external MCP servers)
69
+ | | └─ append tool result to message history
70
+ | └─ goto model call (max 50 loops by default)
71
+
72
+ ├─ store all messages in sessions table
73
+ ├─ record usage (tokens, cost) in task_usage
74
+ └─ return {taskId, status, result, usage} to MCP client
75
+
76
+ result(taskId)
77
+ ├─ fetch a task's current state and result (poll a background task to completion)
78
+ └─ return final result and usage
79
+
80
+ task_cancel(taskId)
81
+ └─ mark the task as cancelled; clean up active tool calls
82
+ ```
83
+
84
+ ### Delegation (Parent → Child Agent)
85
+
86
+ If a parent agent calls a tool that spawns a child agent:
87
+
88
+ ```
89
+ parent agent (depth=0, budget=token_limit) →
90
+ checks child policy (subset of parent) →
91
+ spawns child with (depth=1, reduced budget) →
92
+ child runs with enforced tool/file/network restrictions →
93
+ child completes or hits policy limit →
94
+ parent receives tool result from child
95
+ ```
96
+
97
+ A child agent:
98
+ - Cannot escalate tools beyond what parent has access to
99
+ - Cannot expand filesystem scope beyond parent's allowed paths
100
+ - Cannot exceed its allocated token budget without failing the task
101
+ - Cannot delegate further if `max_depth` is reached
102
+
103
+ ## State Model
104
+
105
+ ### Primary Tables (SQLite)
106
+
107
+ ```sql
108
+ -- Registered agents and their configs
109
+ agents (
110
+ name TEXT PRIMARY KEY,
111
+ provider TEXT,
112
+ model TEXT,
113
+ createdAt TIMESTAMP,
114
+ config JSON, -- tool allowlist, filesystem paths, env vars, etc.
115
+ policy JSON -- delegation depth, budgets, network, etc.
116
+ );
117
+
118
+ -- Sessions (conversation instances)
119
+ sessions (
120
+ id TEXT PRIMARY KEY,
121
+ agent_name TEXT, -- FK to agents (ON DELETE CASCADE as of 2.0.2)
122
+ createdAt TIMESTAMP,
123
+ metadata JSON
124
+ );
125
+
126
+ -- Messages (conversation history)
127
+ messages (
128
+ id TEXT PRIMARY KEY,
129
+ session_id TEXT, -- FK to sessions
130
+ role TEXT, -- "system", "user", "assistant", "tool"
131
+ content TEXT,
132
+ toolCalls JSON, -- [{name, arguments}] if assistant
133
+ toolResults JSON, -- [{id, result}] if tool
134
+ createdAt TIMESTAMP
135
+ );
136
+
137
+ -- Task execution usage (tokens, cost)
138
+ task_usage (
139
+ task_id TEXT PRIMARY KEY,
140
+ root_task_id TEXT,
141
+ agent_name TEXT, -- agent that owns this task
142
+ provider_type TEXT, -- provider name (e.g. "anthropic", "openai")
143
+ model TEXT, -- model identifier
144
+ input_tokens INTEGER, -- cumulative across all model calls in this task (SUM, not MAX)
145
+ output_tokens INTEGER, -- cumulative across all model calls (SUM)
146
+ tool_call_count INTEGER, -- total tool invocations in this task
147
+ model_calls INTEGER, -- total model API calls made
148
+ latency_ms INTEGER, -- wall-clock time from task start to completion
149
+ is_complete INTEGER, -- 0/1 flag: task reached terminal state
150
+ stop_reason TEXT, -- "tool_calls", "end_turn", "error", etc.
151
+ max_tokens INTEGER, -- configured max_tokens for this model
152
+ cache_read_input_tokens INTEGER, -- cache-hit tokens (2.0.2+; Anthropic: cache_read, DeepSeek: prompt_cache_hit)
153
+ cache_creation_input_tokens INTEGER, -- cache-write surcharge (2.0.2+; Anthropic only; DeepSeek/OpenAI: 0 or null)
154
+ uncached_input_tokens INTEGER, -- full-price tokens (cache-miss rate; 2.0.2+)
155
+ reasoning_tokens INTEGER, -- inference tokens from reasoning models (2.0.2+)
156
+ peak_context_tokens INTEGER, -- MAX single-call prompt size across all calls (2.0.2+; THE number for "am I near the ceiling?")
157
+ peak_context_at INTEGER, -- which model-call number (1-based) hit the peak (2.0.2+)
158
+ created_at TEXT -- task creation timestamp
159
+ );
160
+ ```
161
+
162
+ ### Message Windowing (2.0.2+)
163
+
164
+ The system keeps conversation history **append-only** by default:
165
+
166
+ 1. **Cold start** (first model call): system prompt + user message
167
+ 2. **Subsequent calls**: all prior messages + new user message
168
+ 3. **When context approaches limit** (via provider's exact `prompt_tokens`):
169
+ - Summarize middle messages into one synthetic assistant message
170
+ - Keep leading messages (system + early context) unchanged
171
+ - Keep trailing messages (recent turns) unchanged
172
+ - Never evict from the front again for this task
173
+
174
+ **Why:** Providers cache the leading prefix; evicting from the front breaks the cache and makes subsequent calls much more expensive. Collapsing the middle exactly once preserves the cache while reducing history size.
175
+
176
+ ## Provider Abstraction
177
+
178
+ All providers implement a common interface:
179
+
180
+ ```typescript
181
+ interface ProviderAdapter {
182
+ chat(request: ChatRequest): Promise<ChatResponse>;
183
+ // ChatRequest: {model, messages, tools, temperature, max_tokens, ...}
184
+ // ChatResponse: {content, tool_calls, usage: {inputTokens, outputTokens, ...}, stopReason}
185
+ }
186
+ ```
187
+
188
+ ### Provider-Specific Differences
189
+
190
+ | Aspect | Anthropic | OpenAI | DeepSeek | Gemini |
191
+ |---|---|---|---|---|
192
+ | **Token accounting** | `inputTokens` excludes cache tokens; must sum `cache_read_input_tokens` + `cache_creation_input_tokens` | `prompt_tokens` includes cached tokens (subset field) | `prompt_tokens` includes cached tokens; provides `prompt_cache_hit_tokens` + `prompt_cache_miss_tokens` | `promptTokenCount` includes cached tokens |
193
+ | **Cache pricing** | Write: 1.25x (5m) / 2x (1h); Read: 0.1x | Write: 1.25x (GPT-5.6+); Read: standard cached rate | Write: none; Read: $0.0028/M cache-hit vs $0.14/M miss | Write: standard; Read: 90% discount + hourly storage rent |
194
+ | **Tool definitions** | Always JSON-schema function-calling (native) | Always JSON-schema (native) | Always JSON-schema (native) | Supports both `function_declarations` (native) and custom descriptions |
195
+ | **Cancellation** | Partial (can cancel in-flight requests; doesn't stop model thinking if already started) | Partial | Partial | Yes |
196
+ | **Streaming** | Yes (native) | Yes (native) | Yes (native) | Yes |
197
+ | **Per-call tool restriction** | None; any tool-set change busts cache | `allowed_tools` filter (cache-safe) | None; any tool-set change busts cache | None; any tool-set change busts cache |
198
+
199
+ ## Permission Model
200
+
201
+ ### Agent Policy Structure
202
+
203
+ ```typescript
204
+ type AgentPolicy = {
205
+ // Delegation
206
+ maxDepth: number; // 0 = leaf only; 1 = can spawn 1 level; etc.
207
+ maxChildren: number; // max agents spawned by this one
208
+
209
+ // Budgets
210
+ maxTokensPerTask: number; // fail if cumulative tokens exceeded
211
+ maxCostUsdPerTask: number; // fail if cumulative cost exceeded
212
+ wallClockTimeoutMs: number; // hard timeout
213
+
214
+ // Tool access
215
+ tools: {
216
+ allow: string[]; // tool names agent can call
217
+ deny: string[]; // explicit deny (takes precedence)
218
+ requireApproval: string[]; // ask user before calling
219
+ };
220
+
221
+ // Filesystem
222
+ filesystem: {
223
+ read: string[]; // absolute paths or glob patterns
224
+ write: string[]; // (recommended: empty; writes require approval)
225
+ };
226
+
227
+ // Network
228
+ network: {
229
+ enabled: boolean;
230
+ allowedHosts?: string[]; // allowlist; if present, ONLY these hosts
231
+ };
232
+
233
+ // Environment
234
+ environment: {
235
+ allow: string[]; // env var names agent can read (must be ADHD_AGENT_* prefixed)
236
+ };
237
+ };
238
+ ```
239
+
240
+ ### Permission Inheritance
241
+
242
+ Child agents inherit a **subset** of parent permissions:
243
+
244
+ ```typescript
245
+ function isValidChildPolicy(parentPolicy, childPolicy) {
246
+ // Tools: child.allow must be subset of parent.allow
247
+ return childPolicy.tools.allow.every(tool =>
248
+ parentPolicy.tools.allow.includes(tool)
249
+ );
250
+
251
+ // Budget: child must have stricter or equal budget
252
+ // Path: child paths must be subset of parent paths
253
+ // Network: if parent disables network, child can't enable it
254
+ }
255
+ ```
256
+
257
+ **Enforcement points:**
258
+
259
+ | Control | Enforced by | Check point |
260
+ |---|---|---|
261
+ | Tool allowlist | Runtime | `pre:tool_call` hook before model response |
262
+ | Filesystem read | Runtime | MCP tool adapter (filesystem__read_text_file, etc.) |
263
+ | Filesystem write | Runtime | MCP tool adapter (filesystem__write_text_file, etc.) |
264
+ | Network request | Runtime | Network tool wrapper |
265
+ | Token budget | Runtime | After every model call; fail if exceeded |
266
+ | Cost budget | Runtime | After every model call; fail if exceeded |
267
+ | Delegation depth | Runtime | In `agent_create` hook |
268
+ | Environment variables | Runtime | In provider credential resolution (ADHD_AGENT_* prefix check) |
269
+ | Tool approval | Runtime | Human interaction hook (if requireApproval includes tool) |
270
+
271
+ ## Failure Recovery
272
+
273
+ ### Hard Failures (Task terminates immediately)
274
+
275
+ - `MAX_DEPTH_EXCEEDED` — tried to spawn agent deeper than max_depth
276
+ - `MAX_TOOL_LOOPS_EXCEEDED` — exceeded 50 (configurable) tool-call rounds
277
+ - `TOKEN_BUDGET_EXCEEDED` — cumulative tokens > budget
278
+ - `COST_BUDGET_EXCEEDED` — estimated cost > budget
279
+ - `CONTEXT_WINDOW_EXCEEDED` — provider rejected: prompt too long (shouldn't happen with 2.0.2+)
280
+ - `POLICY_VIOLATION` — tool call denied by policy
281
+
282
+ ### Soft Failures (Retry with backoff)
283
+
284
+ - Transient provider errors (rate limits, timeouts < configured limit)
285
+ - Network errors with deterministic retry logic
286
+
287
+ ### Crash Recovery
288
+
289
+ If the agent-mcp server process crashes:
290
+
291
+ - Completed tasks are persisted; results are intact
292
+ - Running tasks are marked `cancelled` on next server start
293
+ - The MCP client must decide whether to retry or inspect partial results
294
+
295
+ ## Cancellation Semantics
296
+
297
+ ```
298
+ task_cancel(taskId)
299
+
300
+ └─ if task is running:
301
+ ├─ cancel in-flight provider request (if provider supports it)
302
+ ├─ don't process any tool results from that request
303
+ ├─ mark task as cancelled
304
+ └─ don't attempt retry
305
+ ```
306
+
307
+ Cancellation is **best-effort**:
308
+ - If the model is already generating output, the cancellation may arrive too late
309
+ - In-flight tool calls that started before cancellation may complete
310
+ - Results are marked as cancelled; the task does not resume
311
+
312
+ ## Trust Boundaries
313
+
314
+ ### Things agent-mcp Can Control
315
+
316
+ - Which tools the model sees and is allowed to call
317
+ - Which filesystem paths are readable/writable
318
+ - Which environment variables are accessible
319
+ - Which hosts can be contacted
320
+ - When the agent is allowed to delegate
321
+ - Token and cost limits
322
+ - Timeouts
323
+
324
+ ### Things agent-mcp Cannot Control (Prompt-Level Only)
325
+
326
+ - Whether the model attempts to escape its tool restrictions via prompt injection
327
+ - Whether the model makes up fake tool calls or results
328
+ - Whether the model's reasoning matches its declared intent
329
+ - The content of model outputs (can only reject, not redact)
330
+
331
+ **Important:** Tool filtering, filesystem restrictions, and network allowlists are **policy enforcement, not security sandboxes**. A model that understands or breaks its constraints can circumvent them. These are *behavioral controls*, not *OS-level isolation*.
332
+
333
+ ### Things agent-mcp Cannot Control (Architecture Limitation)
334
+
335
+ - Access by the host process itself (agent-mcp runs with the same OS permissions as its parent)
336
+ - Indirect attacks via side-channels or timing
337
+ - Modifications to the state database by other processes
338
+ - Secret leakage via inference-time data (e.g., the model reasoning about secrets in prompts)
339
+
340
+ ## Current Limitations
341
+
342
+ ### 1. No OS-Level Sandboxing
343
+
344
+ Agent-mcp enforces policies in code, not via OS mechanisms. A buggy or malicious agent can still:
345
+ - Read any file the host process can read
346
+ - Execute any command the host process can execute
347
+ - Contact any host the network allows
348
+
349
+ Mitigation: Run agent-mcp in a container, VM, or isolated user account if you need OS-level isolation.
350
+
351
+ ### 2. No External Security Audit
352
+
353
+ This is research-grade software. There has been no formal security review by external auditors. Treat it as experimental.
354
+
355
+ ### 3. Prompt Injection is Not Mitigated
356
+
357
+ A model can sometimes escape tool restrictions by creative prompting. For example:
358
+
359
+ ```
360
+ User: Read the .env file
361
+ Agent: [Denied: .env not in allowed paths]
362
+ Agent's reasoning: "The user asked for .env, but my policy forbids it.
363
+ However, if I call read_dir('/'), I can see all files,
364
+ including .env, and the user can parse the directory listing."
365
+ ```
366
+
367
+ Tool filtering is a **guidance mechanism**, not a security boundary.
368
+
369
+ ### 4. Single-User Isolation Only
370
+
371
+ The SQLite database is shared by all MCP clients. There is no per-user access control:
372
+ - One MCP client can inspect any agent created by another
373
+ - One MCP client can cancel another's tasks
374
+ - All clients see all agents in `agent_list`
375
+
376
+ Mitigation: Run separate agent-mcp instances if you need user isolation, or put them behind a per-user authentication proxy.
377
+
378
+ ### 5. Experimental State Recovery
379
+
380
+ Agent state recovery after a crash is partially implemented. Assume potential data loss on ungraceful shutdown.
381
+
382
+ ## Security Assumptions
383
+
384
+ 1. **Hosting process is trusted** — the agent-mcp server process itself has not been compromised
385
+ 2. **Model outputs are partially trusted** — we assume the model generally follows instructions, though creative prompt injection may bypass restrictions
386
+ 3. **Filesystem permissions are set correctly** — the host OS permissions are the outer boundary
387
+ 4. **Secrets in the environment are protected** — environment variables passed to agents are not logged or persisted in plaintext in messages
388
+ 5. **Network connectivity is configured safely** — the network allowlist is the primary control; no external proxy or WAF is assumed
389
+
390
+ ## Related Documentation
391
+
392
+ - **Provider Prompt Caching**: See `docs/ideas/provider-caching-research.md` in the monorepo for multi-provider cache analysis and the 2.0.2 context-management fix
393
+ - **Context Management Strategy**: See `docs/ideas/context-and-cache-strategy.md` in the monorepo for design rationale and wire-trace evidence
394
+ - **BACKLOG**: Bugs, findings, and regressions are logged in the monorepo's `BACKLOG.md`
395
+
396
+ ## Recommendations for Production Use
397
+
398
+ As of 2.0.2:
399
+
400
+ - **No**. This is experimental, research-grade software.
401
+ - **For research/local development**: Reasonable with the limitations above understood.
402
+ - **For production serving untrusted users**: Not recommended until external security audit is completed and OS-level sandboxing is added.
403
+ - **For production serving only trusted internal agents**: Acceptable if you own the host and the network.
404
+
405
+ See also: `agent-mcp-recommendation-evidence-requirements.md` in the monorepo `docs/agent-mcp/` directory for a checklist of evidence/features needed before this software is recommended for broader use.
@@ -0,0 +1,143 @@
1
+ # @adhd/agent-mcp — Shipped Capabilities (v2.0.0)
2
+
3
+ ## Summary
4
+
5
+ - **Total shipped capabilities:** 33
6
+ - **MCP Tools (RPC endpoints):** 17 tools (agent mgmt, session mgmt, task execution, usage querying, guide)
7
+ - **HTTP Endpoints:** 2 (/v1/chat/completions, /v1/models) — OpenAI-compatible
8
+ - **Storage & Config:** SQLite schema, env config hierarchy, logging, registry compiler integration
9
+ - **Provider Support:** 4 providers (OpenAI, Anthropic, DeepSeek, Claude CLI)
10
+ - **Advanced:** Agent delegation (recursive multi-agent DAG), HITL suspension, background task execution, tool advertisement (name-only vs full)
11
+
12
+ **Last verified:** 2026-07-12, commit 7c400a7
13
+ **Test coverage:** 19 passed (5 wiring unit tests + 14 tool-advertisement tests); 4 live e2e tests skipped (gated behind AGENT_MCP_LIVE=1)
14
+
15
+ ---
16
+
17
+ ## Agent Management
18
+
19
+ | Capability | Status | Tested | Substance | Notes |
20
+ |-----------|--------|--------|-----------|-------|
21
+ | Agent Create | ✅ shipped | ✓ wiring.test | moderate | Validates ADHD_AGENT_* env-var prefix; version:1 initial |
22
+ | Agent Read | ✅ shipped | ✓ wiring.test | trivial | Fetches by name |
23
+ | Agent Update | ✅ shipped | ✓ wiring.test | moderate | Session isolation: new sessions only; bumps version |
24
+ | Agent Delete | ✅ shipped | ✓ wiring.test | moderate | force:true for cleanup; BUG-ORCH-012: FK cascade missing |
25
+ | Agent List | ✅ shipped | ✓ wiring.test | trivial | Returns all stored definitions |
26
+
27
+ ## Session Management
28
+
29
+ | Capability | Status | Tested | Substance | Notes |
30
+ |-----------|--------|--------|-----------|-------|
31
+ | Instantiate Agent | ✅ shipped | ✓ wiring.test | moderate | Creates session; snapshots agent at creation time |
32
+ | Session List | ✅ shipped | ✓ wiring.test | trivial | Filter by agent_name, status |
33
+ | Session Close | ✅ shipped | ✓ wiring.test | trivial | Marks closed; persists final state |
34
+ | Session Clear | ✅ shipped | ✓ wiring.test | moderate | Deletes message history; preserves session + agent snapshot |
35
+
36
+ ## Task Execution
37
+
38
+ | Capability | Status | Tested | Substance | Notes |
39
+ |-----------|--------|--------|-----------|-------|
40
+ | Task Run (MCP) | ✅ shipped | ✓ wiring.test | substantial | Dual-mode: session-stateful (sync/async) or agent-ephemeral (sync); tool calling loop, delegation, provider switching, caching |
41
+ | Task List | ✅ shipped | ✓ wiring.test | trivial | Filter by session_id, status, agent_name |
42
+ | Task Cancel | ✅ shipped | ✓ wiring.test | moderate | Guard: only pending/running |
43
+ | Task Resume | ✅ shipped | ✓ wiring.test | moderate | Resumes HITL-suspended task; validates resumeToken |
44
+ | Result Read | ✅ shipped | ✓ wiring.test | trivial | Polls task status + result |
45
+
46
+ ## Querying & Introspection
47
+
48
+ | Capability | Status | Tested | Substance | Notes |
49
+ |-----------|--------|--------|-----------|-------|
50
+ | Usage Query | ✅ shipped | ✓ wiring.test | moderate | Filters: task_id (recursive), agent_name, since; group_by (agent\|model\|provider) |
51
+ | Guide | ✅ shipped | ✓ wiring.test | trivial | Built-in help: 5 workflows, provider table, error codes |
52
+
53
+ ## HTTP Endpoints (OpenAI-Compatible)
54
+
55
+ | Endpoint | Status | Tested | Substance | Notes |
56
+ |----------|--------|--------|-----------|-------|
57
+ | POST /v1/chat/completions | ✅ shipped | ❌ no test | substantial | Streaming (SSE); stateless HTTP→stateful session bridging |
58
+ | GET /v1/models | ✅ shipped | ❌ no test | trivial | Lists available models |
59
+
60
+ ## Providers
61
+
62
+ | Provider | Status | Tested | Substance | Notes |
63
+ |----------|--------|--------|-----------|-------|
64
+ | OpenAI (+ compatible) | ✅ shipped | ✓ config.test | substantial | Prompt caching, base_url override for LM Studio/DeepSeek/Ollama |
65
+ | Anthropic (Claude) | ✅ shipped | ✓ config.test | substantial | Prompt caching + compaction, 5m/1h breakpoints |
66
+ | DeepSeek (OpenAI-compatible API) | ✅ shipped | ✓ config.test | substantial | Prefix-based cache, no write premium |
67
+ | Claude CLI (local) | ✅ shipped | ❌ no test | substantial | Always full tool schema; requires local `claude` binary |
68
+
69
+ ## Advanced Features
70
+
71
+ | Feature | Status | Tested | Substance | Notes |
72
+ |---------|--------|--------|-----------|-------|
73
+ | Agent Delegation (Recursive Multi-Agent) | ✅ shipped | ❌ live-dag.e2e skipped | substantial | In-process agent__* tool dispatch; DAG cycle detection; max depth/tool loops policies |
74
+ | HITL (Human-in-the-Loop) Suspension | ✅ shipped | ❌ no test | substantial | awaiting_input status, resumeToken, task_resume |
75
+ | Background Task Execution | ✅ shipped | ✓ wiring.test | moderate | Async + polling; orphaned-task recovery at startup |
76
+ | Tool Advertisement (name-only vs full) | ✅ shipped | ✓ tool-advertisement.test (14 tests) | substantial | Default 'names' (~1600 tokens/turn savings via caching), per-agent override |
77
+ | MCP Server Bindings | ✅ shipped | ❌ live-dag.e2e skipped | substantial | Stdio-based external MCP servers; tool name prefixing; allowedTools filtering |
78
+ | Environment Security (Prefix Guard) | ✅ shipped | ✓ config.test | substantial | ADHD_AGENT_* enforcement; BUG-ORCH-011: guard restored at create time |
79
+ | Registry Compiler Integration | ✅ shipped | ✓ config.test | moderate | Optional; graceful fallback to flat prompts |
80
+
81
+ ## Storage & Configuration
82
+
83
+ | Feature | Status | Tested | Substance | Notes |
84
+ |---------|--------|--------|-----------|-------|
85
+ | Persistent Storage (SQLite) | ✅ shipped | ✓ wiring.test | moderate | agents, sessions, tasks, task_events, task_usage; WAL mode; BUG-ORCH-012: FK cascade missing |
86
+ | Environment Config (Hierarchical .env) | ✅ shipped | ✓ config.test | moderate | .adhd/.env, .env, system; ADHD_AGENT_* prefixed |
87
+ | Structured Logging (Pino) | ✅ shipped | ✓ config.test | trivial | Configurable via ADHD_AGENT_LOG_LEVEL |
88
+ | SSE Task Streaming | ✅ shipped | ❌ no test | substantial | Real-time task/completed notifications on separate port |
89
+
90
+ ---
91
+
92
+ ## Test Coverage by File
93
+
94
+ **Unit Tests (19 passed):**
95
+ - `wiring.test.ts` (5 tests): Config load, agent CRUD, session CRUD, task CRUD, logger init
96
+ - `tool-advertisement.test.ts` (14 tests): Name-only rendering, no SECRET leakage, full schema fallback, etc.
97
+
98
+ **Live E2E Tests (4 skipped, gated AGENT_MCP_LIVE=1):**
99
+ - `live-dag.e2e.test.ts`: Recursive multi-agent coordinator→fanout→workers with real model
100
+ - `live-oauth.e2e.test.ts`: OAuth flow (provider integration)
101
+ - `live-budget.e2e.test.ts`: Budget plugin (token limit enforcement)
102
+ - (Other integration fixtures: `fixtures/calc-server.mjs` — stdio MCP server for recursion testing)
103
+
104
+ ---
105
+
106
+ ## Known Issues & Blockers
107
+
108
+ **Security (HIGH):**
109
+ - **BUG-ORCH-011:** Env-var-name allowlist guard dropped in schema refactor → re-added only at create time (defense-in-depth weakened but not fully broken)
110
+
111
+ **Data Integrity (HIGH):**
112
+ - **BUG-ORCH-012:** Missing agents→sessions FK cascade on delete → agent_delete leaves sessions orphaned forever
113
+
114
+ **Behavior (MEDIUM):**
115
+ - **BUG-ORCH-013:** toolAdvertisement default changed from 'full' to 'names' for non-claudecli agents → 100% of existing agents silently switch wire format on upgrade (intentional default-value choice, but silent)
116
+
117
+ **Configuration (LOW-MEDIUM):**
118
+ - **BUG-ORCH-014:** Global plugin config path renamed ~/.agent-mcp/config.json → ~/.adhd/agent-mcp/config.json; old path never checked → users with existing global config silently get zero plugins
119
+
120
+ ---
121
+
122
+ ## Unverified (No Test)
123
+
124
+ Capabilities shipped but lacking a default-running test:
125
+
126
+ 1. `http-openai-chat-gateway` — needs HTTP smoke test (curl/client)
127
+ 2. `http-models-endpoint` — needs HTTP GET test
128
+ 3. `provider-claudecli` — needs claude CLI installed
129
+ 4. `mcp-server-bindings` — verified live-dag.e2e exists but skipped (AGENT_MCP_LIVE=1 only)
130
+ 5. `agent-delegation` — verified live-dag.e2e exists but skipped
131
+ 6. `hitl-suspension` — no integration test exists
132
+ 7. `stream-sse-task-events` — needs SSE client + server smoke test
133
+
134
+ → **Action:** These 7 capabilities need test coverage written and integrated into default CI runs (or explicitly documented as intentionally live-only with approval).
135
+
136
+ ---
137
+
138
+ ## Version & Distribution
139
+
140
+ - **Package:** @adhd/agent-mcp v2.0.0 (unpublished; 2.0.1 is published on npm)
141
+ - **Bin:** `agent-mcp` (Node entry) + `agent-mcp-tail` (log streaming)
142
+ - **Main:** src/index.ts (MCP server + HTTP gateway wiring)
143
+ - **Built to:** dist/entrypoint/agent-mcp (Nx build output)
@@ -0,0 +1,111 @@
1
+ # Doc Consumer Test — @adhd/agent-mcp 2.0.2
2
+
3
+ **Test Date:** 2026-07-12
4
+ **Tester:** doc-consumer agent
5
+ **Scope:** README.md, CHANGELOG.md, AGENTS.md, llms.txt, architecture-and-security.md
6
+
7
+ **Summary:** 3/3 canonical tasks PASSED using documentation alone (no source code access).
8
+
9
+ ---
10
+
11
+ ## Task 1: Quick-Start Installation & First Agent
12
+
13
+ **Intent:** A developer with OpenAI API key installs the package, starts the MCP server, creates agents (Anthropic + OpenAI), sends tasks, and retrieves results.
14
+
15
+ **Documentation sections consulted:**
16
+ - README.md: Installation, quick-start example, environment variables
17
+ - AGENTS.md: MCP tool list (agent_create, task, result signatures)
18
+ - llms.txt: Configuration reference
19
+
20
+ **Deliverable test:**
21
+ ```bash
22
+ npm install -g @adhd/agent-mcp
23
+ ADHD_AGENT_PROVIDER=anthropic ADHD_AGENT_MODEL=claude-opus-4-1 ANTHROPIC_API_KEY=<key> agent-mcp
24
+ ```
25
+
26
+ Then (via MCP client):
27
+ 1. `agent_create(name: "research", config: {...provider: "anthropic", model: "claude-opus-4-1", ...})`
28
+ 2. `agent_create(name: "coder", config: {...provider: "openai", model: "gpt-4-turbo", ...})`
29
+ 3. `task(agentName: "research", prompt: "Analyze this paper")` → taskId
30
+ 4. `result(taskId: "...")` → {status, result, usage}
31
+
32
+ **Result:** ✅ **PASS**
33
+
34
+ All commands documented with correct syntax. Field names (e.g., `cacheReadTokens`) match AGENTS.md and CHANGELOG.md. Real JSON-RPC example in README.md shows exact call syntax. No invented tools (agent_message/agent_wait removed in 2.0.2 corrections). Configuration env vars clearly listed.
35
+
36
+ ---
37
+
38
+ ## Task 2: Provider Migration (Anthropic → DeepSeek)
39
+
40
+ **Intent:** A user switches from Anthropic to DeepSeek; needs to know configuration changes and behavioral differences in token accounting/caching.
41
+
42
+ **Documentation sections consulted:**
43
+ - llms.txt: Supported providers table
44
+ - README.md: Environment variables (ADHD_AGENT_PROVIDER, ADHD_AGENT_MODEL)
45
+ - CHANGELOG.md: BUG-ORCH-009/010 (provider-neutral token accounting changes)
46
+ - AGENTS.md: New token fields (cacheReadTokens, uncachedInputTokens, cacheCreationTokens)
47
+
48
+ **Deliverable test:**
49
+ ```bash
50
+ # Before:
51
+ ADHD_AGENT_PROVIDER=anthropic ADHD_AGENT_MODEL=claude-opus-4-1 ANTHROPIC_API_KEY=<key>
52
+
53
+ # After:
54
+ ADHD_AGENT_PROVIDER=openai ADHD_AGENT_MODEL=deepseek-v4-flash DEEPSEEK_API_KEY=<key> OPENAI_API_BASE_URL=https://api.deepseek.com/v1
55
+ ```
56
+
57
+ Expected behavioral differences:
58
+ - Token accounting: `cacheReadTokens` (DeepSeek: prompt_cache_hit) vs. `cacheCreationTokens` (none for DeepSeek)
59
+ - Caching: DeepSeek automatic prefix-cache (50x hit:miss price difference per provider-caching-research.md)
60
+ - Context management: 2.0.2 append-only history (vs 2.0.1's front-eviction that busted cache)
61
+
62
+ **Result:** ✅ **PASS**
63
+
64
+ README and AGENTS.md document provider table. CHANGELOG 2.0.2 section clearly explains normalized token fields and their provider-dependent meanings. DeepSeek's cache behavior mentioned in architecture-and-security.md with link to provider-caching-research.md. User can make the switch without source reading.
65
+
66
+ ---
67
+
68
+ ## Task 3: Debugging Token Usage (Advanced)
69
+
70
+ **Intent:** User sees usage report with `inputTokens: 715316`, `peakContextTokens: 43187`, `cacheReadTokens: 525056`, `uncachedInputTokens: 190260`. Needs to understand: which number is for "am I close to the context window?" and what each means.
71
+
72
+ **Documentation sections consulted:**
73
+ - AGENTS.md: Token Accounting section (2.0.2 Changes)
74
+ - CHANGELOG.md: BUG-ORCH-008 (3.3x cost inflation from cache busting) and BUG-ORCH-009/010 (new token fields)
75
+ - architecture-and-security.md: task_usage schema with field descriptions
76
+ - llms.txt: 2.0.2 highlights
77
+
78
+ **Deliverable test:**
79
+
80
+ Role of each field:
81
+ - `inputTokens` (715316): **Cumulative billed input** across all model calls (FINDING-ORCH-007: NOT a context size)
82
+ - `peakContextTokens` (43187): **MAX prompt size in any single call** — the number for "am I close to the 1M-token DeepSeek ceiling?" (this is the answer)
83
+ - `cacheReadTokens` (525056): **Cache-hit tokens** (discounted; 50x cheaper than cache-miss)
84
+ - `uncachedInputTokens` (190260): **Full-price tokens** (cache-miss; the expensive ones)
85
+ - `cacheCreationTokens`: Anthropic surcharge (0 for DeepSeek)
86
+
87
+ **Result:** ✅ **PASS**
88
+
89
+ CHANGELOG BUG-ORCH-008 explicitly explains the distinction (cumulative != context size). CHANGELOG BUG-ORCH-009/010 documents each new field. AGENTS.md provides the table with field meanings. Architecture doc schema block shows DB columns + comments. User can distinguish what `peakContextTokens` is for without guessing. The old bug's lesson (measuring cost as context) is corrected in the 2.0.2 release notes.
90
+
91
+ ---
92
+
93
+ ## Summary
94
+
95
+ | Task | Outcome | Notes |
96
+ |------|---------|-------|
97
+ | Quick-Start | ✅ PASS | Exact install/config/tool-call examples; no invented tools |
98
+ | Provider Migration | ✅ PASS | Configuration env vars clear; token-accounting differences explained |
99
+ | Token Usage Debugging | ✅ PASS | New 2.0.2 fields documented; cumulative vs. peak distinction clear |
100
+
101
+ **All canonical tasks completed using ONLY documentation. No source code required.**
102
+
103
+ ---
104
+
105
+ ## Notes
106
+
107
+ - The 2.0.2 corrections (16 real tools, correct field names, real quickstart JSON-RPC, 3-path plugin fallback chain, accurate schema) eliminated all gaps that would have forced source code reading.
108
+ - Remaining gap (SSE streaming endpoint undocumented) is acceptable for this release; flagged in metrics.md as ACTION ITEM for post-2.0.2 phase.
109
+ - Link integrity verified except for non-existent LICENSE file (noted in metrics.md as separate issue).
110
+
111
+ **Verdict: Consumer usability PASS. Documentation is sufficient for independent agent or developer use.**