Agent providers

An agent provider recognizes the foreground CLI in one terminal, finds its journal through brokered observation, and maps records into Terminay lifecycle events. It observes a running process; it does not start, control, or receive a raw terminal stream.

Manifest contribution

Request agent-observation and declare an agentProviders entry. The registered providerId must match that contribution’s id.

Contribution fieldType and meaning
id, displayNameStable provider identity and user-facing name.
description, icon, platformsOptional presentation and OS availability metadata.
processMatchersSafe declarative matchers: executableName plus optional exact arguments tokens.
mappingsDeclared mappingVersion / providerVersionRange pairs for a provider release.
requiredEnvironmentVariablesNames that observation.processes.environment() may request from the exact foreground process or a descendant.
requiredEnvironmentCapabilitiesOne or more of process-observation, filesystem-observation, and agent-journal.

Runtime contract

TypeScript
import { defineAgentProvider, jsonlSession } from '@terminay/extension-api';

export const codex = defineAgentProvider({
  mappingVersion: '1',
  matchesForeground(process) {
    return process.executableName === 'codex';
  },
  async observe(terminal) {
    const journal = await terminal.observation.files.resolveHomeRelative(
      '.codex/session.jsonl',
    );
    if (!journal) return { state: 'not-bound' };

    const binding = await terminal.bindSession({
      providerSessionId: 'session-from-journal',
      mappingVersion: '1',
      journal,
      fingerprint: { kind: 'codex-journal', file: journal },
    });
    return jsonlSession({
      binding,
      source: terminal.observation.files.follow(journal, { signal: terminal.signal }),
      mapRecord(record, session) {
        // Map a provider record and call session.publish.* when appropriate.
      },
    });
  },
});
MemberSignaturePurpose
mappingVersionstringVersion of this journal-to-event mapping. It is stored in the session binding.
matchesForeground(process: AgentForegroundProcess) => booleanFast, side-effect-free recognition of the terminal’s foreground process.
observe(terminal: AgentTerminalContext) => Promise<AgentObservationResult>Find and bind one session, or report why this terminal has none.
defineAgentProvider(provider) => AgentProviderDefinitionIdentity helper for a provider definition.
context.agents.registerProvider(providerId, runtime) => AgentProviderRegistrationRegisters the runtime; add the returned disposable to context.subscriptions.

Observation results

Return valueWhen to use it
AgentJsonlSessionA bound JSONL session. jsonlSession(options) constructs this form and returns { state: 'bound', ...options }.
{ state: 'not-bound' }The process belongs to the provider but a usable session is not present yet.
{ state: 'unavailable', reason }The provider cannot observe this terminal. Reasons are environment-capability-missing, process-not-recognized, session-not-found, session-not-bound, unsupported-provider-version, malformed-observation, observation-limit-exceeded, or cancelled.

AgentTerminalContext provides opaque terminal, project, environment, and process handles; foreground-process facts; an optional TTY fact; granted capabilities; a cancellation signal; and observation. See Terminal observation for that broker.

Bind a session

Call terminal.bindSession(request) before returning a bound session. The request contains a provider-owned providerSessionId, the provider mappingVersion, optional journal handle, optional display-safe primitive metadata, and a fingerprint.

Fingerprint fieldAllowed value
kindA provider-defined string describing the binding strategy.
process, fileOnly the opaque process or file handles issued for this terminal context.
metadataA record of bounded JSON primitives; no paths, credentials, or raw records.

The host returns an opaque AgentSessionBinding. It carries the provider session ID, mapping version, and optional journal handle, but is valid only in the terminal context that issued it.

JSONL sessions

An AgentJsonlSession has a root binding, a root AgentFileWatcher, and mapRecord(record, session). It may also include fixed childSources or asynchronous childSourceDiscovery; every child has a stable childId, its own journal handle, and watcher, but shares the root binding.

The mapper receives the binding, journal role (root or a child ID), a lifecycle publisher, and a cancellation signal. See Lifecycle events for the publisher contract.