duckbrain-http-401-auth-json-hash-only-use-token-files
All three Python blocks compile cleanly and the solution is written.
I diagnosed the DuckBrain 401 problem and wrote the solution to /workspace/solution.md (325 lines).
Key findings (live-confirmed against localhost:3000):
- Keyless requests → 401 "API key required"; bogus keys → 401 "Invalid API key"; Authorization: Bearer is rejected; only /health is unauthenticated. So an empty items list from an unauthenticated call proves nothing.
- ~/.duckbrain/auth.json is hash-only (name + keyHash) — no plaintext key can be recovered. I verified only keyHash/name are the expected fields.
- auth.json and ~/.hermes/.env are dead ends for :3000; the working credentials are the per-project ~/.duckbrain/*.token sidecar files.
Fix delivered:
- A drop-in duckbrain_http.py that globs ~/.duckbrain/*.token, probes each with GET /api/memories?namespace=…&prefix=… + X-API-Key header, caches the first that returns 200, then writes via POST with {key, domain, content} and re-reads the exact key requiring items >= 1.
- Shell/curl equivalents, the domain enum (person|event|concept|message|config|raw_note; foreman → VALIDATION_ERROR; use event for ticks), and hard rules.
- Verification section with live failure-mode reproductions plus the recorded fleet result (POST 201, GET /tick/353 → items:1, 3 token files authenticated).
Caveat: the sandbox's ~/.duckbrain/*.token files were not mounted (home is stripped), so I could not re-run a successful authenticated write here; the auth semantics and failure modes were reproduced directly, and the successful-write evidence is from the recorded fleet tick.
# Evidence - Problem class: duckbrain-http-401-auth-json-hash-only-use-token-files - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-18T06:43:48.863Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "SYMPTOM: every DuckBrain HTTP write/read from a fleet tick returned HTTP 401 Unauthorized: API key required, even though ~/.duckbrain/auth.json existed with 18 apiKeys entries and two DUCKBRAIN keys were present in ~/.hermes/.env. A keyless GET also returns 401, so an empty items list is NOT proof of absence unless a working key was used.\nROOT CAUSE (two independent ones): (1) auth.json is now HASH-ONLY - each apiKeys entry has just keyHash (a sha256 string) and name, so no usable plaintext key can be extracted from it at all; the older extract-the-key-from-auth.json recipe is dead. (2) The DUCKBRAIN values in ~/.hermes/.env (DEEPSEEK_PAYG_DUCKBRAIN_KEY, DEEPSEEK_DUCKBRAIN_SYNC_API_KEY) are not valid on the :3000 daemon (401), and Authorization: Bearer is also rejected - the header must be X-API-Key.\nFIX: the working credentials are the per-project token files under ~/.duckbrain/*.token. Glob them and use the first one that authenticates: GET /api/memories?namespace=<ns>&prefix=<prefix> with header X-API-Key: <token from the .token file>. Write with POST /api/memories?namespace=<ns> and a JSON body {key, domain, content} where domain must be one of person|event|concept|message|config|raw_note (domain=foreman is rejected with VALIDATION_ERROR; use event for tick records), then re-GET the exact key and require items >= 1.\nVERIFICATION: 3 token files authenticated (9router-foreman.token, escalation-doctrine-foreman.token, bunker-foreman.token) and the narration write landed (POST 201 + GET /tick/353 -> items:1) after the .env route had 401'd on every attempt.\nLESSON: before declaring a credential store 'empty' or a namespace write 'blocked', probe the .token sidecar files; a 401 is an auth-source problem, not an empty-namespace signal.", "environment": "DuckBrain HTTP daemon on localhost:3000 with x-api-key auth; ~/.duckbrain/auth.json; keys also in ~/.hermes/.env", "language": "python", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "duckbrain-http-401-auth-json-hash-only-use-token-files", "provider": "openrouter", "solved_at": "2026-09-18T06:43:48.863Z", "version": ""}All three Python blocks compile cleanly and the solution is written.
I diagnosed the DuckBrain 401 problem and wrote the solution to /workspace/solution.md (325 lines).
Key findings (live-confirmed against localhost:3000):
- Keyless requests → 401 "API key required"; bogus keys → 401 "Invalid API key"; Authorization: Bearer is rejected; only /health is unauthenticated. So an empty items list from an unauthenticated call proves nothing.
- ~/.duckbrain/auth.json is hash-only (name + keyHash) — no plaintext key can be recovered. I verified only keyHash/name are the expected fields.
- auth.json and ~/.hermes/.env are dead ends for :3000; the working credentials are the per-project ~/.duckbrain/*.token sidecar files.
Fix delivered:
- A drop-in duckbrain_http.py that globs ~/.duckbrain/*.token, probes each with GET /api/memories?namespace=…&prefix=… + X-API-Key header, caches the first that returns 200, then writes via POST with {key, domain, content} and re-reads the exact key requiring items >= 1.
- Shell/curl equivalents, the domain enum (person|event|concept|message|config|raw_note; foreman → VALIDATION_ERROR; use event for ticks), and hard rules.
- Verification section with live failure-mode reproductions plus the recorded fleet result (POST 201, GET /tick/353 → items:1, 3 token files authenticated).
Caveat: the sandbox's ~/.duckbrain/*.token files were not mounted (home is stripped), so I could not re-run a successful authenticated write here; the auth semantics and failure modes were reproduced directly, and the successful-write evidence is from the recorded fleet tick.
# Evidence - Problem class: duckbrain-http-401-auth-json-hash-only-use-token-files - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-18T06:43:48.863Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "SYMPTOM: every DuckBrain HTTP write/read from a fleet tick returned HTTP 401 Unauthorized: API key required, even though ~/.duckbrain/auth.json existed with 18 apiKeys entries and two DUCKBRAIN keys were present in ~/.hermes/.env. A keyless GET also returns 401, so an empty items list is NOT proof of absence unless a working key was used.\nROOT CAUSE (two independent ones): (1) auth.json is now HASH-ONLY - each apiKeys entry has just keyHash (a sha256 string) and name, so no usable plaintext key can be extracted from it at all; the older extract-the-key-from-auth.json recipe is dead. (2) The DUCKBRAIN values in ~/.hermes/.env (DEEPSEEK_PAYG_DUCKBRAIN_KEY, DEEPSEEK_DUCKBRAIN_SYNC_API_KEY) are not valid on the :3000 daemon (401), and Authorization: Bearer is also rejected - the header must be X-API-Key.\nFIX: the working credentials are the per-project token files under ~/.duckbrain/*.token. Glob them and use the first one that authenticates: GET /api/memories?namespace=<ns>&prefix=<prefix> with header X-API-Key: <token from the .token file>. Write with POST /api/memories?namespace=<ns> and a JSON body {key, domain, content} where domain must be one of person|event|concept|message|config|raw_note (domain=foreman is rejected with VALIDATION_ERROR; use event for tick records), then re-GET the exact key and require items >= 1.\nVERIFICATION: 3 token files authenticated (9router-foreman.token, escalation-doctrine-foreman.token, bunker-foreman.token) and the narration write landed (POST 201 + GET /tick/353 -> items:1) after the .env route had 401'd on every attempt.\nLESSON: before declaring a credential store 'empty' or a namespace write 'blocked', probe the .token sidecar files; a 401 is an auth-source problem, not an empty-namespace signal.", "environment": "DuckBrain HTTP daemon on localhost:3000 with x-api-key auth; ~/.duckbrain/auth.json; keys also in ~/.hermes/.env", "language": "python", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "duckbrain-http-401-auth-json-hash-only-use-token-files", "provider": "openrouter", "solved_at": "2026-09-18T06:43:48.863Z", "version": ""}