Skip to Content

Events

The event log every run writes, and how to read it.

Every run writes one ordered log of events. Studio's timeline, replay, evals, streaming and the HTTP API are all views of that log, so the log is the source of truth for what an agent did.

The shape of an event

{
  "schemaVersion": 1,
  "streamType": "run",
  "streamId": "run-096c2fa2-814b-49a8-ac26-8b64c930d8a9",
  "runId": "run-096c2fa2-814b-49a8-ac26-8b64c930d8a9",
  "id": "…",
  "sequence": 5,
  "timestamp": "2026-11-09T12:07:17.039Z",
  "type": "tool.call",
  "payload": { "toolName": "create_ticket", "arguments": { "title": "VPN down" } }
}

sequence orders events within a run and is what you pass as a cursor. schemaVersion is the version of the saved event, not of the HTTP API. The types are in @plico-ai/contracts as PlicoEvent.

Event types

EventWhen it is written
run.startedA run begins. Carries the project name and any host metadata and context.
instructions.composedagent.md and the skills are combined. Records the exact text the run uses.
tools.discoveredThe project's tools are loaded, with their schemas and approval policy.
input.receivedThe user message a model-backed run starts from.
model.requestPlico sends messages and tool definitions to the model.
model.attemptA model call starts. A retry is a new attempt.
model.deltaA streamed piece of the reply.
model.responseThe model's full reply, with token usage and any tool calls.
assistant.outputText the agent says to the user.
tool.callThe agent calls a tool, with its arguments.
tool.resultThe tool's result.
approval.requestedA tool needs a decision. See Approvals.
approval.decidedA person approved or denied. May record who decided.
artifact.workspace.createdThe run gets an artifact workspace.
artifact.file.writtenA file version is written, with its path, hash and version.
artifact.snapshot.createdA workspace snapshot is recorded, with its file count.
run.waitingThe run is parked on a decision.
run.completedThe run finished, with its final output.
run.cancelledThe run was cancelled.
run.errorSomething went wrong, with its phase and a message.
run.failedThe run ended in failure. Follows run.error.

Not every run writes every type. A dry run has no model.* events, and a run with no tools has no tool.* or approval.* events.

Read the log

From the command line:

plico runs .               # list saved runs
plico events <run-id> .    # print one run's events

Over HTTP:

  • GET /v1/runs/<run-id>/events returns the events as JSON. Add ?after=<sequence> to get only newer ones.
  • GET /v1/runs/<run-id>/events/stream is a Server-Sent Events stream. A reconnecting client sends Last-Event-ID, or ?after=, and gets the events it missed.

From your backend, plico.runs.events(runId, { after }) is an async iterator over the same events. See Use Plico from your backend.

In Studio, the run view shows them as a timeline, with the raw JSON beside it and replay controls to step through a finished run. See Studio.

Stored data and stability

Runs are stored in SQLite at .plico/plico.sqlite in the project, or wherever --db points. The log is append-only: Plico adds events and never edits one.

The HTTP API under /v1 takes additive changes only, so a new event type or payload field can appear in a minor release. Write consumers that ignore types and fields they do not know. See Upgrading for what else can change in a 0.x release.

Events can include tool arguments, results and host context. Keep secrets out of all three.

On this page