Extensions / Guides

Publish lifecycle events

Your provider translates its CLI’s private journal format into a small, validated lifecycle vocabulary that Terminay can show consistently across agents.

Map records at the edge

Keep parsing specific to your agent. Publish only safe titles, prompts, summaries, and IDs; omit a field when it is not present instead of inventing it.

TypeScript
function mapRecord(record: unknown, session: AgentRecordContext) {
  if (!isRecord(record)) return;

  switch (record.type) {
    case "session":
      session.publish.sessionStarted({ title: text(record.title) });
      break;
    case "prompt":
      if (id(record.turnId)) {
        session.publish.turnStarted({ turnId: id(record.turnId)!, promptText: text(record.text) });
      }
      break;
    case "tool_started":
      if (id(record.toolId)) {
        session.publish.toolStarted({ toolId: id(record.toolId)!, name: text(record.name) ?? "Tool" });
      }
      break;
    case "approval_needed":
      if (id(record.requestId)) {
        session.publish.waitStarted({ waitId: id(record.requestId)!, state: "waiting", reason: "Approval requested" });
      }
      break;
    case "approval_resolved":
      if (id(record.requestId)) session.publish.waitFinished({ waitId: id(record.requestId)! });
      break;
    case "complete":
      session.publish.done({ outcome: record.ok === false ? "error" : "success", summary: text(record.summary) });
      break;
  }
}

Event vocabulary

EventConvenience publisherUse for
session.startedsessionStarted()The bound session becomes known.
agent.metadatametadataChanged()Title, prompt, agent ID, or model changes.
turn.startedturnStarted()A user request begins.
tool.started / tool.finishedtoolStarted() / toolFinished()A tool invocation and its outcome.
wait.started / wait.finishedwaitStarted() / waitFinished()Approval, input, or other blocked work.
agent.donedone()The agent completed, failed, or was cancelled.
agent.exitedexited()The process ended, with an optional exit code or signal.
subagent.started / subagent.donesubagentStarted() / subagentDone()A child agent’s work.
session.stoppedpublish()The session observation ends; this event has no shorthand.

Model waiting and completion accurately

A wait has a stable waitId and must finish with the same ID. Use state: "waiting" when an agent awaits input or approval and state: "blocked" when it cannot continue for another reason. Completion outcomes are success, error, or cancelled.

Report subagents from their own evidence

Use the provider’s native child ID, and only emit child events when the journal or record establishes the parent relationship. Do not create a second root binding for a subagent.

TypeScript
session.publish.subagentStarted({
  subagentId: child.id,
  parentAgentId: rootAgentId,
  title: text(child.title),
});

session.publish.subagentDone({
  subagentId: child.id,
  outcome: child.failed ? "error" : "success",
  summary: text(child.summary),
});

// Use publish() for the event that has no convenience helper.
session.publish.publish({ kind: "session.stopped", reason: "terminal closed" });

Good event hygiene

  • Use stable IDs from the agent’s records for turns, tools, waits, and subagents.
  • Include occurredAt only when the agent provides a trustworthy timestamp.
  • Never publish credentials, raw journal lines, absolute paths, or unbounded prompt text.
  • Use publish() for a valid event without a helper; the host validates every event.

Next: observe JSONL journals or return to the Extensions API overview.