Skip to content

Compile semantic Agent event routes into native host hooks #97

Description

@ScriptedAlchemy

Summary

Extend Agent Bundle's existing host-neutral hook names and adapter-owned native
translation into filesystem event routes with a broader capability-aware
vocabulary. The compiler maps each semantic event onto the selected host's native event,
matcher, input decoder, synchronous deadline, output envelope, and delivery
capabilities.

Authors write application behavior once. Host adapters own translation.

Problem

Agent Bundle currently normalizes four hook events: sessionStart,
beforeTool, afterTool, and stop. TraceDecay-class applications also need
session completion, prompt submission, subagent start, file saved, workspace
open, compaction, shell completion, test lifecycle, idle, and host-specific
receipts.

Copying JSON hook documents or branching on host names inside handlers does
not scale. Hosts differ in event names, fields, matchers, synchronous response
formats, deadlines, trust prompts, and whether directed feedback is possible.

Filesystem convention

src/events/
  session/start.tsx
  session/end.tsx
  prompt/submit.tsx
  agent/start.tsx
  tool/before.tsx
  tool/after.tsx
  file/saved.tsx
  workspace/open.tsx
  compact/before.tsx
  stop.tsx

Each route may export static configuration and an RSC result component:

export const config = {
  tools: ['file.write'],
  delivery: ['immediate', 'deferred'],
} satisfies AgentEventRouteConfig;

export default async function AfterTool() {
  const { event, services } = await agent();
  const hint = await services.hints.forEvent(event);
  return hint ? <Agent.Context>{hint}</Agent.Context> : null;
}

Canonical event contract

Every event carries bounded metadata, explicit identity provenance, ordering,
an idempotency key, host contract revision, and an AbortSignal. Sensitive or
unbounded native payload fields are excluded unless an application explicitly
declares and validates them.

Host support is a state, not a Boolean:

type HostEventSupport =
  | { state: 'supported'; source: 'native' | 'receipt' }
  | { state: 'degraded'; reason: string }
  | { state: 'unavailable'; reason: string }
  | { state: 'prohibited'; reason: string };

The compiler refuses routes that require an unavailable capability unless the
route is explicitly restricted to supported targets.

Projection

The adapter registry owns:

  • native event names and matchers;
  • input decoding and canonical identity extraction;
  • synchronous deadline and payload budgets;
  • immediate output encoding (additionalContext, hook-specific output,
    denial, toast, or no response);
  • trust/activation requirements;
  • event fixtures and provenance.

Application routes never emit host-native JSON directly.

Failure and timing

  • Hook processes acknowledge within the host deadline.
  • An unavailable provider or backend produces a truthful empty/no-guidance
    result, not a fabricated success.
  • Slow work is handed to an explicit state/task backend and later delivery
    route; a short-lived hook does not silently continue unowned work.
  • Duplicate events are idempotent when a state provider is configured.
  • Native payloads are size bounded before user code runs.

Non-goals

  • Claiming event support from another host's similar payload.
  • Built-in hint or collision algorithms.
  • A mandatory event database.
  • Arbitrary raw native-hook documents as the primary authoring model.

Acceptance criteria

  • Unsupported and degraded mappings are visible in inspect output and fail
    required routes before packaging.
  • Checked-in host-native fixtures prove schema and adapter conformance for every
    supported mapping; they are not evidence that a commercial host dispatched
    the event.
  • The handler receives canonical context and never branches on host JSON.
  • Immediate output is rendered through the Agent Document projector.
  • The event process never holds open for deferred output. Before the delivery
    feature exists, a deferred-delivery request fails with a typed unsupported
    outcome rather than pretending work will continue.
  • One tool/after route compiles into two genuinely supported native formats;
    a separate file/saved fixture is reported unavailable on targets that do
    not expose that event.

Design references

Stack position

Full meta-framework stack

Flight-backed event-route execution

The intended default architecture is a thin native hook client calling the
shared Agent Bundle render runtime, not a generated shell process that loads the
whole application and renderer for every event.

native hook stdin/event
  -> host decoder
  -> AgentEventProps { canonical, native, provenance, signal }
  -> shared runtime render request
  -> event route Server Component
  -> Flight stream
  -> Agent Document decoder/projector
  -> native hook stdout/result

canonical contains the cross-host event identity used by application code.
native retains every field the host actually supplied after schema and size
validation, so an application can use host-specific evidence without receiving
fabricated fields. Both are immutable typed props and are also available through
the request context established around the Flight render.

The generated client selects a real transport per host:

  • use a native mcp_tool hook only where the host contract proves it can call
    the generated server with the required input, output, cancellation, and
    deadline semantics;
  • otherwise use compiler-owned local IPC to the host-managed MCP/runtime
    process;
  • use a standalone in-process wrapper only as an explicit degraded mode when
    shared runtime/state is not required.

The MCP/runtime process can amortize application startup and expose
process-lifetime providers or state across hook invocations. This is optional:
event routes that need only their props still work without durable storage, and
routes requiring shared/durable state declare that capability explicitly.

Additional acceptance criteria:

  • One real generated hook sends the complete validated native envelope as
    typed props through Flight and receives a valid native response before the
    host deadline.
  • Claude, Codex, and Cursor adapters prove their selected runtime transport or
    report it degraded/unavailable; similarly named events are not evidence.
  • Two consecutive events can observe the same process-lifetime provider when
    the shared runtime is active without reloading the application per hook.
  • Runtime absence, restart, timeout, cancellation, and artifact-epoch mismatch
    have fail-closed or explicitly configured fallback behavior.
  • The public hook protocol never receives raw Flight bytes or non-native output.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthost-integrationAgent host capabilities, projection, discovery, and lifecyclemeta-frameworkAgent Bundle compiler-coupled meta-frameworkruntimeRuntime context, state, rendering, or execution

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions