examples/support-desk demo starts as a plain support inbox: Hono on Node, Vite and React, JSON fixture data, its own cookie session. Adding a Checkfu agent replaces none of that.
This is the brownfield path. Your backend keeps its framework, data model, authentication, and application functions. Checkfu supplies the governed Session, the tool-serving SDK, the durable event log, and the React pieces you compose yourself.
Server boundary
Declare Custom tools over your existing functions and serve explicit Sessions from your backend worker.
React boundary
Proxy the event log through your backend and compose transcript, tool, status, and ActionApproval components.
What the finished journey proves
- The agent and the ticket HTTP routes call the same application functions.
- An agent-authored draft appears in the open ticket without a reload.
- Human and agent writes produce the same domain effect with different attribution.
close_ticketparks on a real Checkfu ActionApproval rendered inside the support app.- The selected ticket is supplied in the drive message; the agent does not scrape browser state.
@checkfu/sdk and @checkfu/ui imports from Checkfu. It rejects internal packages and platform application imports.
Start from the host’s functions
The plain app already ownslookupTicket, draftReply, and closeTicket. Each function accepts the operation input used by both surfaces. An optional serving context distinguishes an agent call from a direct human call for attribution; it does not fork the business behavior.
Declare the same functions as tools
defineTool wraps those exact function references with a name, a description, and an input schema. It does not move execution into Checkfu.
needsActionApproval maps to Checkfu ActionPolicy authority on use_tool:close_ticket. It is not a client-side confirmation flag. Sync updates the Agent and its SDK-managed ActionPolicy; the changed configuration automatically becomes the next immutable Version.
sync returns the current Agent. When the custom-tool set changes, the update
automatically creates the next Version. An unchanged tool set is a no-op.
See Serve tools from your app for validation errors, replay convergence, and approval sequencing.
Create a Session with visible context
When a teammate delegates from an open case, the server creates a normal Session and starts serving that explicit Session:user.message shape has free-text content and attribution but no structured host-context field. The demo therefore prepends a documented, bounded in-band block:
Keep credentials behind the existing backend
The browser never receives a Checkfu Workspace key. The Hono server exposes only the event page and stream routes for an authenticated, authorized Session, attaching its key upstream:Project the log into React
The host bindsuseSessionEvents to its proxy with the Workspace-proxy transport. The hook consumes the stream as data — durable events append by seq, previews replace themselves, gaps get one bounded backfill — and the host’s fetch keeps auth (cookies, sign-in retries) entirely host-owned.
draft_reply therefore appears in the existing reply box without a reload. The ticket store remains application truth; the Session log is the durable truth that the agent action occurred and the live invalidation source.
The right rail composes focused kit exports rather than adopting a Checkfu application shell:
Surface the consequential action
When the agent callsclose_ticket, ActionPolicy emits action_approval.pending and the run waits. The backend lists the pending custom-tool ActionApproval for that Session and passes its frozen context to the kit:
checkfu.actionApprovals.decide. On approval, ToolServing runs the same closeTicket function as the human button; on denial, the function never runs. Both decisions remain in the Session event log.
Run the complete example locally
Start the owned mock stack and use its protected connection file. The file contains the local URL, credential, Workspace, AgentDefinition, and Principal expected by the example.http://127.0.0.1:4174, select TKT-1042, and choose Ask case agent. The visible default prompt uses the mock harness’s deterministic Use <tool> with <JSON> grammar, so the first Session drafts a reply through the host worker. When it completes, choose Start close task. That second Session calls close_ticket and parks on the frozen ActionApproval in the same right rail.
The mock executes one explicitly named Custom tool per Session, which is what makes both steps repeatable; a hosted model picks its tools from ordinary prose instead. Pointing the same application code at hosted Checkfu changes only the server-side connection values.
Verify the customer boundary
run.completed. The other reconciles a delayed ActionApproval and projects a denial without running the host action. A live smoke swaps those two test doubles for checkfu dev and a browser, and the application code does not change.