Skip to main content

Client package surface

@forge/react is the headless client: state, reducers and hooks, with no product styling and no transport assumptions. The host supplies the transport by implementing one interface.

Moved here from the package README, which is a front door rather than a reference.

Modules

ModuleContains
typesRe-exports the wire contract from @forge/agentkit, plus client-only view state. Type-only, erased at build time.
event-bufferImplemented. Orders and de-duplicates run events across a reconnect.
hooksImplemented — all ten: useForgeClient, useConversations, useConversation, useRunSubscription, usePendingInteraction, useSendMessage, useAnswerQuestion, useDecideApproval, useCancelRun, useSessionContext.
clientThe transport port the hooks take. An interface, so the host supplies fetch, SSE or WebSocket and this package assumes none of them.
reducersRun events folded into renderable parts. Pure functions, so the ordering guarantees are testable without a DOM.
context-inspectorWhat the window holds and what is left of it — the view behind the composer's context meter.
localizationLocale and timezone resolution for rendered output.
usage-panelThe spend panel's shaping, separate from its rendering.
citationsCitation view-model and resolution, React-free, so the same rules serve a DOM renderer and a native one.
ui/citationsImplemented. Citation markers and expandable source panels: append-only ordering so a mid-stream citation never moves what is on screen, a grounded/ungrounded treatment that uses no colour, and a shipped hue-free stylesheet.
ui/usageImplemented. The spend panel: rollup-backed periods with breakdowns, a quota bar whose state comes from the server's own guard, an explanatory empty state rather than a zeroed chart, and a mobile-first hue-free stylesheet.

event-buffer came first because it backs a specification acceptance criterion — "subscription reconnect produces no missing or duplicated rendered parts" — and that behaviour is testable before any transport exists.

The split between shaping and rendering is deliberate throughout: citations, usage-panel and context-inspector are React-free, so the rules that decide what a citation marker means or when a quota bar turns amber are held in one place and tested without a DOM. ui/ renders them.

Why the backend dependency is type-only

Every import from @forge/agentkit is an import type, so nothing survives compilation. The client owns no copy of the wire contract, and the two halves cannot drift. TypeScript project references build the backend's declarations first.

Scripts

npm test -w @forge/react
npm run build -w @forge/react # builds @forge/agentkit first

Not yet here

The optional UI component package from specification 06 — chat shell, part renderers, question and approval cards, artifact panel. It depends on this package, never the reverse, and is deliberately not a mobile dependency.

What "headless" costs and buys

The package assumes no fetch, no SSE and no WebSocket — ForgeClient is an interface the host implements. That is why the same hooks drive a DOM renderer and a native one, and why the reducers are pure functions whose event-ordering guarantees are testable without a browser.