The ShurIQ Report Engine is now a Claude Managed Agent — Anthropic runs the loop, a per-session container does the work, and every artifact writes straight back into the ShurIQ Report Studio system of record. This is the build record and the first end-to-end validation run, executed against a fresh American Heart Association brief.
ShurIQ used to generate reports inline — one Claude call inside the studio's generate.ts. The Managed Agent replaces that with a parameterized agent that runs the full gold-standard pipeline autonomously and writes its output directly into the live shuriq D1 database. The dashboard reads D1 natively, so a correct run closes the intelligence loop with no glue.
Anthropic runs the agent loop. A per-session container executes the agent's tools. Three of the four tools are fulfilled host-side — so the studio's service key, the InfraNodus key, and the Cloudflare token never enter the sandbox.
Writes reports, sections, KG layers and scored deltas into D1, and clears the fact-check gate. Authenticates back to the studio with a service bearer the studio validates — no session cookie, no secret in the sandbox.
Builds an InfraNodus knowledge graph per layer and returns modularity, top-betweenness concepts and named structural gaps — confirmed against the live API.
Web search + fetch for outside-in research, plus read access to the mounted system-of-record contract files (grammar.ts, types.ts).
Optional — publishes the editorial site + viz hub to Cloudflare Pages and records the live URL when an archetype ships a public artifact.
We chose the American Heart Association as the first run — a report ShurIQ knows well — and staged a clean report row (rpt-aha-agent-val, Editorial Brief — Sales) for the agent to populate, preserving the existing AHA pressure-test to compare against. Then the agent was handed one instruction: an outcome to satisfy, graded against the "Done" rubric.
The agent ran the real pipeline: 54 web-research calls, 38 reasoning steps, and 23 custom-tool round-trips — each one surfaced to the host, fulfilled against the studio or InfraNodus, and returned to the agent. The fact-check gate fired between research and scoring; SBPI only ran once it cleared; sections were composed and written back one by one. Every write landed in the live shuriq D1.
The full 18-section brief — Letter, Context, Numbers Spine, Topology Map, Stack Rank, Reframe, Structural Gaps, a 1,281-word Gap Analysis, Competitive Lens, Method Audit, Structural Advantage Score, Action Set, Ask, Bridge, Appendix — was written section by section into the live system of record. Open the full generated brief →
| Field | Value |
|---|---|
| Agent | agent_011zHwRK227kpyYuUMXSzcdx — "ShurIQ Report Engine" |
| Model | claude-opus-4-8 (agent + every phase) |
| Tools | agent_toolset_20260401 · studio_write · infranodus_graph · deploy_editorial |
| Skills | 6 @latest — intelligence-brief · competitive-intel · anti-slop · ontology-management · value-flow-ontology · evidence-trail |
| System prompt | 2,763 chars — voice anchors, anti-slop hard rules, the phase contract, IP-layer protection |
| Environment | env_01MZBXJc… — cloud, limited networking |
| Org / workspace | Sense Collective · Default workspace |
The code referenced linter_status / linter_failures everywhere, but no migration ever created the columns — any linter write would 500. Authored 0005_v06_grammar_linter.sql and applied it to remote + local.
The studio's InfraNodus client read raw.statistics / topInfluentialNodes — paths that don't exist in the live envelope, so graph grounding silently came back empty. Confirmed the real shape live and repointed it at extendedGraphSummary + graph.graphologyGraph.attributes.
Every write endpoint required a session cookie, so the agent couldn't write at all. Added requireUserOrService (cookie OR a service bearer) and the two missing routes — /kg-layers and /kg-deltas.
Extended PATCH /reports/:id so the agent can set graph_status, graph_ref, graph_data, linter_status and published_url — the fields the "Done" rubric requires.
Most of the build was learning the exact shapes the beta accepts — confirmed live, not guessed. These are baked into the reproducible setup.sh.
| Thing | Reality |
|---|---|
| Skill upload | curl with folder-qualified multipart filenames where the folder == the name: in SKILL.md (the CLI basenames paths and is unusable) |
| Agent ↔ skills | The agent must be created with a workspace API key — an OAuth-login agent can't resolve workspace skills |
| model field | {"id":"claude-opus-4-8"} (model_config) or a bare string — not {"model":…} |
| prebuilt tool | bare {"type":"agent_toolset_20260401"} — no tool sub-array |
| skill ref | {"type":"custom","skill_id":"…","version":"latest"} |
| session kickoff | user.define_outcome with description + a text rubric, sent via events.send(id, {events}) — not a create param |
| tool result | user.custom_tool_result with custom_tool_use_id + content as an array of blocks |
| file resource | mounted per-session as {type:"file",file_id,mount_path} |
runtime.ts is host-agnostic — the same loop runs under a Node host (server.ts) or a Cloudflare Worker (worker/worker.ts), both implementing the studio's dormant trigger contract. Flip the studio's AGENT_ENDPOINT_URL to either and the Generate button hands the run to the agent. The whole harness is committed and tagged managed-agent-v0.1.