Customer enrichment (recommended)
The plugin owns the same-origin agent relay, preserves JSON and server-rendered HTML on Epode failure, and
exposes customer.context.get, customer.personalization.decide, and customer.outcomes.track.
The same request records final status and handler duration. Optional session/runtime extractors must read only
product-issued or verified server state, never caller parameters or agent-authored content.
The selected response waits at most timeoutMs (250 ms by default) for the enrichment request, then fails open
to the original payload. Use customer.contextFor(request) to combine company identity with a validated,
interaction-scoped Epode-Context-Interaction continuation when the caller has no stable reference.
authenticate runs only on included business routes and cannot intercept the two exact capability-authenticated
relay routes. Do not register a rejecting global authentication hook above this plugin.
Server-rendered HTML
For an included route, return a bounded string with Content-Type: text/html. The onSend hook injects a
non-executable <meta name="epode-customer-context"> marker containing base64url JSON while preserving CSP and
visible content. Buffers, streams, oversized pages, and pages with an existing marker remain unchanged.
Run the subscription-media example
Legacy structured outcome feedback
Install
Async jobs and polling
Use shouldInstrument to wait until the response contains an outcome the agent can evaluate:
The authentication and tenant-authorization hooks from the first example must remain global and run first.
Use the server-loaded, authorized job for sessionRef; never accept an arbitrary grouping handle from a caller.
The default cacheMode: "safe" skips explicitly shared-cacheable responses instead of overwriting their
cache policy. Use cacheMode: "request" when only callers sending Agent-Feedback-Request: 1 should be
instrumented, or cacheMode: "private" when every included response is already private. Request mode adds
Vary: Agent-Feedback-Request to both ordinary and opted-in responses so shared caches keep them separate.
Eligible ordinary 2xx GET and HEAD responses also advertise a same-path-and-query Link for one
authenticated Companion refetch; redirects and non-safe methods never advertise it.
* matches one path segment. Use ** when the route family can be nested more deeply.
Server-rendered HTML
Include your server HTML path. JSON objects receive _agentFeedback; HTML receives an embedded machine
contract; arrays and scalars use headers.
Verify
Customer-agent coverage
Your Fastify plugin creates the HTTP/HTML feedback contract; it cannot make an independent customer agent act
on it. For reliable Codex and Claude Code handling, customers install
Epode Companion once for all Epode-instrumented products. This is a user-side plugin,
not another company SDK or product key. Generic agents without the Companion can still use the product normally,
but feedback remains best effort.
Keep the plugin global and narrow include to product surfaces that customer agents actually use.
View the runnable Fastify example
View the async crawl example