Skip to main content
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

Configure once

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