feat(agentic): adopt hero_router agentic-calling pattern; replace MCP framing in vision (final pre-customer engineering item) #8
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Adopt the hero_router agentic calling pattern as hero_assistance's programmable surface for AI-driven workflows. The vision doc currently says "v0.4 will register every method as an MCP tool" (§2.5) and "AI-driven triage and first-pass resolution via MCP tool surface" (§5.4) — that language predates the Hero stack's chosen architecture. hero_router has standardised on OpenRPC spec → router-generated Python interface + sandboxed Python client, not MCP. This issue tracks the work to align hero_assistance with that pattern.
Reference contract: https://forge.ourworld.tf/lhumina_code/hero_router/src/branch/development/docs/agentic_calling.md
Why this matters
Per hero_router's
agentic_calling.md:The router consumes each service's OpenRPC spec, generates two Python artifacts per service (a small interface file sent to the LLM; a full client file executed in a sandbox), MD5-fingerprints the spec to skip regeneration, and routes user-intent requests to the relevant interface(s). The LLM produces a workflow script from interface signatures only; the sandbox executes it; service data never reaches the LLM.
hero_assistance is the natural first non-trivial hero_router consumer:
crates/hero_assistance_server/openrpc.json(~92 KiB, 17 namespaces).Scope
What hero_assistance must contribute
OpenRPC spec conformance audit. Walk every method block in
crates/hero_assistance_server/openrpc.jsonand confirm:paramsschemas are complete (no missingrequiredlists, noadditionalProperties: truewhere the handler actually rejects extras).resultschemas describe what the handler returns, not what an earlier draft thought it returned. (Phase 13b found at least one drift —presence.listreturnsnamewithout it being declared.)descriptionis informative enough for an LLM to choose between sibling methods (channel.createvsticket.create,message.sendvscomment.create).errorsenumerate the codes the handler actually emits (-32002 PermissionDenied,-32003 NotFound,-32602 InvalidParams, etc.) — D-16's structuredRpcCallErrordiscrimination depends on this.Per-method intent metadata (additive — does not change wire shape). For each method, add an
x-hero-intentextension block describing:read/mutate-own/mutate-others/admin). Sandbox can use this to gate execution paths or require confirmation.self/workspace/project/cross-project). Mirrors the presence-fanout audience model.anonymous-ok/enrolled-user/support-role/admin-role).safe/idempotent/unsafe). Distinguishespresence.set_status_text(idempotent, replays cheap) fromcomment.create(unsafe, replays duplicate).Identity-pinning contract for sandboxed calls. The router's sandbox runs as some identity; the hero_assistance privacy invariant (D-04 three-layer identity + D-20 per-recipient
/eventsfilter) requires that every RPC call carry acaller_idthat the LLM cannot forge. Document the contract:caller_idfrom the human-user identity that hero_router authenticated, never from LLM output./eventsTCP route's per-recipient server-side filter (D-20) is the regression gate — any agentic call that subscribes to events MUST hit/eventswithX-Hero-User: <human-user>, not<sandbox-service-account>.OpenRPC publishing endpoint. hero_router needs a way to fetch the spec. Decide between:
_uiservescrates/hero_assistance_server/openrpc.jsonat/openrpc.json(simplest; spec is already build-time-stable).rpc.discoverreturns the spec inline (OpenRPC 1.3 standard; needs a handler).rpc.discoverfor in-protocol introspection.Recommended: (c), mirror what hero_router expects (open question — needs router-side confirmation).
Sandbox-friendly workflow examples. Ship 3–5 example workflows in
docs/dev/agentic_workflows.mdmatching theagentic_calling.mdstyle — e.g., "find every open ticket in this workspace older than 7 days and post a follow-up comment from the assigned support agent." These double as integration-test fixtures and as documentation for what the router-side sandbox must support.Vision doc + roadmap update. Replace MCP language with hero_router-pattern language:
decisions/D-21-agentic-calling-via-hero-router.mdrecording (a) the choice (hero_router pattern over MCP), (b) the security invariant (LLM sees interface only; sandbox holds identity), (c) the wire contribution (audit +x-hero-intentextension; no new RPC methods).What hero_assistance does NOT do
rpc.discover.Acceptance criteria
crates/hero_assistance_server/openrpc.jsonaudited end-to-end; every drift between handler behaviour and spec recorded as a fix or as an explicitx-hero-known-driftannotation.x-hero-intentpopulated with side-effect class, audience scope, identity requirement, idempotency._uiserves the spec at/openrpc.json(or whatever path hero_router expects — confirm with router maintainer); response isapplication/json,Content-Typecorrect, cacheable with the same MD5 hero_router uses.rpc.discoverhandler returns the embedded spec; covered by a hermetic integration test.docs/dev/agentic_calling.md(hero_assistance side; complements hero_router's doc) with the D-04 + D-20 invariants front-and-centre.docs/dev/agentic_workflows.mdcovering: read-only triage, single-user mutate, multi-user fanout, cross-method (presence + comment), error-path ("user not enrolled in workspace").docs/vision/HERO_ASSISTANCE.md§2.5 + §5.4 + roadmap updated; MCP language replaced with hero_router-pattern language.decisions/D-21-agentic-calling-via-hero-router.mdfiled.docs/dev/e2e_checklist.mdSection L (programmable surface) extended with row(s) covering the spec-publish endpoint and thex-hero-intentextension. M2/M3 milestone tag depending on prioritisation.prompt.md§1 + tracking issue #1 updated at session-end.Roadmap framing
Per
prompt.md§3, hero_assistance is engineering-complete pre-customer. M3 / v1.0 is customer-gated. This issue is the last engineering-complete item — once it lands:After this issue closes, hero_assistance can credibly be called engineering-complete full-stop — including the AI-amenable programmable surface that vision §2.5 promises. Anything beyond is customer-driven (M3) or M4+ aspirational.
Estimated work: 1–2 sessions if hero_router's discovery endpoint contract is already nailed down; 2–3 sessions if router-side coordination surfaces wire shape disagreements.
Open questions
agentic_calling.md§16 shows aservices:YAML registry but doesn't say who writes it.agentic_calling.md§3 says the router computes the MD5. Does it want raw bytes ofopenrpc.json, or a canonicalised form? Critical for cache stability.x-hero-intentschema. Is this extension already specified somewhere in the Hero stack? If yes, conform. If no, hero_assistance becomes the reference implementation — file the schema as part of D-21.caller_idper call, or does that need router-side support? Confirm with hero_router maintainer before committing to the contract in (3) above.References
crates/hero_assistance_server/openrpc.jsondocs/vision/HERO_ASSISTANCE.md§2.5, §5.4decisions/D-04-three-layer-identity.mddecisions/D-20-events-over-tcp-transport.mdClosed in session 37 (2026-05-06). Two source commits:
62a7fb3(Phase 23 part 1 — spec audit + 3 phase23 regression tests + D-21) +d2d0cac(Phase 23 part 2 —docs/dev/agentic_calling.md+docs/dev/agentic_workflows.md+ vision-doc MCP-language reframe + e2e_checklist Section L update) +857e52e(handoff).Acceptance-criteria walk
summary(one-line lift) + structurederrors[](framework codes -32600/-32601/-32602/-32603 always; identity-bearing methods add -32001/-32002/-32005; lookup-shaped .get/.update/.delete add -32003; conflict-prone heuristically -32004) +x-hero-intentblock.{side_effect_class, audience_scope, identity_requirement, idempotency}on all 91 methods. Schema declared atinfo.x-hero-intent-schemain the spec itself; consumers tolerate unknown values (open enums) so future hero_router-side rework is non-breaking. Distribution: 41 read / 40 mutate-others / 6 mutate-self / 4 admin; 82 enrolled-user / 6 anonymous / 3 admin-role; 41 safe / 30 replay-safe / 20 replay-unsafe.rpc.discoverover UDS (Hero convention; matcheshero_supervisor/hero_aibroker/ping/hero_auth/hero_books/hero_indexer) AND HTTPGET /openrpc.json(developer-experience parity). Both pre-existing in the snapshot fromhero_collab; Phase 4 reduced to adding regression tests. Note: original acceptance-criterion text said_uiserves the spec at/openrpc.json; revised to_serverserves it (which is what the router actually consumes via UDS) —_uiHTTP proxy is dev-ergonomic only and tracked as a discretionary follow-up.rpc.discoverhandler returns embedded spec; covered by hermetic integration test — three tests landed:phase23_rpc_discover_returns_openrpc_spec_with_self_listed,phase23_rpc_discover_byte_stable_across_calls(FNV cache invariant),phase23_http_openrpc_returns_spec_over_uds_rpc_sock.docs/dev/agentic_calling.md. Sandbox MUST setX-Hero-Userfrom the human-user identity hero_router authenticated, NEVER from LLM output. Same surface as/rpcand/events(D-04, D-20) — zero new identity code paths. Thephase22_events_tcp_per_user_filter_excludes_non_recipientper-recipient/eventsfilter doubles as the agentic-calling privacy regression gate.docs/dev/agentic_workflows.mdcovering: read-only triage / single-user mutate / multi-user fanout (canonical confirmation flow formutate-others+replay-unsafe) / cross-method (presence + read-cursor + status text) / error-path (-32004Conflict recovery + abort-before-mutation on user-not-enrolled). Each annotated with x-hero-intent classifications + sandbox runtime author guidance. Doubles as router-integration test fixtures.docs/vision/HERO_ASSISTANCE.md§2.5 + §5.4 + roadmap updated — six surgical edits replace inherited "every method as MCP tool" / "OpenRPC + MCP" language with hero_router-pattern language. MCP retained as a post-v1 candidate for non-Hero-stack agents but no longer the primary surface.hero_browserMCP refs (visual-regression tooling) preserved — those are unrelated.decisions/D-21-agentic-calling-via-hero-router.mdfiled — locks: (a) hero_router pattern over MCP; (b) wire facts settled by precedent + upstream doc (rpc.discoverover UDS, FNV-1a-64 hash over raw bytes, unauthenticated by Hero convention); (c)x-hero-intentschema as reference impl with open-enum semantics; (d) identity-pinning contract preserving D-04 + D-20 invariants.docs/dev/e2e_checklist.mdSection L extended — full s37 audit-log entry; "MCP?" column doc broadened to include hero_router agentic-calling sandbox scripts (column name kept stable to avoid 90+ row churn); M1-L-88 (rpc.discover) Wired? flips from[skip: NO-COVERAGE-YET]to ✅ via the 3 phase23 tests; Section L summary updated (wired count 26 → 27).prompt.md§1 + tracking issue #1 updated at session-end —857e52elands the handoff doc updates; tracking issue #1 §0 patched in-place via Forgejo API._ui/openrpc.jsonHTTP proxy is documented as a discretionary DX follow-up in D-21 + prompt.md §3.B.5 adversarial review
Ran at session-start. Caught 3 load-bearing problems before code landed:
/openrpc.jsonon_ui(HTTP) — but router fetches via UDSrpc.discoveron_server._uiroute would have bypassed D-04's identity surface if implementation drifted. Corrected: pre-existingrpc.discoveratrpc.rs:46+state.openrpc_specviainclude_str!atmain.rs:375+ HTTP/openrpc.jsonatmain.rs:486are sufficient.x-hero-intent. Would have been invented unilaterally without open-enum semantics, risking cache poisoning if hero_router later defined its own shape. Corrected: D-21 documents the schema as an open-enum reference impl with explicit "consumers tolerate unknown values" semantics; future tightening is non-breaking.Mechanical pre-deploy checks all clear: (1) no time-sensitive RPC params added; (2) no test-script phase mirroring concern; (3) no cross-node state-locality concern.
Cost of B.5: 1 subagent + 1 WebFetch. Saved cost: ≥1 session of post-merge cleanup + cache-poisoning recovery.
Open follow-ups (NOT v1.0-gating)
_ui/openrpc.jsonHTTP proxy — developer-experience nicety (router uses UDS so this is dev-ergonomic only).x-hero-intent.identity_requirementper-method — today's audit ships every authenticated method asenrolled-user; future deployments may wantsupport-roleforchannel.delete/attachment.cleanup_pending/group.rights.set/ etc. Schema permits this additive change; do it when a customer policy surfaces.x-hero-known-driftannotation surface — this session's audit found no per-method drift requiring deferred annotation. If a future audit surfaces one, the convention is"x-hero-known-drift": "<one-line description with file:line>"at the method level.errors[].dataschemas — today's audit ships framework codes; per-method-specific error messages still live in description prose. A future audit can promote them; not load-bearing for v1.Test posture
222 → 225 native passing (+3 phase23 tests) / 32
_ui_wasmlib unchanged / 13 ignored unchanged / 0 net failed.cargo build --releasegreen;cargo test --no-fail-fastgreen end-to-end.Session manifest
Full s37 manifest at
sessions/37.yml.