Files
PaperClipAI/packages/paperclip-runner/protocol/schemas/event-v3.schema.json
T
Nicky LeachandPaperclip 80a2b9284b Define durable runtime activity events (#18129)
## Thinking Path

> - Paperclip manages agents and tasks.
> - Runner reports durable run events through PRP.
> - Runtime clients need a typed record of reported activity.
> - The event must keep the normal run authority and read boundaries.
> - This pull request adds the generic runtime activity event contract.
> - Later PRs can publish and consume this contract without private
plugin coupling.

## Linked Issues or Issue Description

First feature prerequisite extracted from #18050. Runner publishing is
#18050; the dependent consumer is #18131. Related independent test
stability work: #18128. The parent search and review history is
preserved in [the verification
archive](https://github.com/paperclipai/paperclip/pull/18050#issuecomment-6489369676).

**Subsystem affected**

Runner event protocol, server run-event persistence and redaction, and
UI event taxonomy.

**Problem or motivation**

Core needs a durable, typed activity record tied to the authenticated
run. A text marker is not an event contract.

**Proposed solution**

Add `runtime.activity.recorded` as a P1 event with a closed `{
namespace, activityKey }` payload. Runner knows no plugin or panel
identity. Run/session identity, sequence and emission time stay in the
outer envelope; Core resolves company, task and agent through the
authorized run binding. Use the existing authenticated persistence,
acknowledgement, replay and redaction paths.

## What Changed

- Define and validate the event in PRP v1, v2 and v3. Update the
generated protocol artifacts and event catalog.
- Preserve saved and live event redaction. Test persistence, replay
deduplication and the existing run-read boundary.
- Register the event in the UI taxonomy without changing panel display
behavior.
- Advance the source-bound Copilot identity to 78. Retain all published
historical identity fixtures without changing their bytes.

## Verification

- Root `pnpm typecheck` and `pnpm build`: passed for the revised
activity contract.
- Node protocol checks: 14 passed. Provider identity and registry tests:
185 passed. Server tests: 103 passed. UI event registry: five passed.
- Maintained Grok and Copilot identity generator checks and `git diff
--check`: passed.
- The first activity-contract review scored 4/5 because the dependent
producer and readers still used the earlier contract. Both dependent PRs
are now updated and restacked; the finding is resolved and review is
running again.
- Initial extraction retained a consumer-only import in one server
suite. That suite failed to load. The consumer case and import were
moved out; the final three server files passed all 103 cases.
- Earlier panel-specific head `6137c50bc` had green CI and standard/Apex
5/5. Those scores do not qualify this revised activity contract. Fresh
CI and reviews are pending. Earlier combined results in the archive
apply only to their recorded source revisions.

## Risks

This change is additive. It adds no route, publisher, filesystem
transport, provider sandbox grant, or panel display behavior. Activation
hints grant no permission to read a plugin view. Provider identities
bind the changed protocol source; historical identities remain
decode-only. No schema migration or dependency change is required.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository tools and code
execution. The exact serving snapshot is not exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-29 00:32:12 -07:00

738 lines
20 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://paperclip.dev/schemas/prp/v3/event.schema.json",
"title": "PRP v3 native event",
"type": "object",
"required": [
"schema",
"sourceEventId",
"sourceSeq",
"sourceInstanceId",
"sourceKind",
"runId",
"eventType",
"schemaVersion",
"priority",
"emittedAt",
"payload"
],
"properties": {
"schema": {
"const": "paperclip.prp.event.v3"
},
"sourceEventId": {
"type": "string",
"minLength": 1,
"maxLength": 160
},
"sourceSeq": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
"sourceInstanceId": {
"type": "string",
"minLength": 1,
"maxLength": 160
},
"sourceKind": {
"enum": [
"runner",
"control_plane"
]
},
"runId": {
"type": "string",
"minLength": 1,
"maxLength": 160
},
"normalizedSessionId": {
"type": "string",
"minLength": 1,
"maxLength": 160
},
"turnId": {
"type": "string",
"minLength": 1,
"maxLength": 160
},
"itemId": {
"type": "string",
"minLength": 1,
"maxLength": 160
},
"eventType": {
"enum": [
"runner.connected",
"runner.reconnected",
"runner.reconciled",
"runner.disconnected",
"runner.draining",
"runner.suspending",
"runner.suspended",
"runner.stopped",
"runner.diagnostic",
"runtime.phase.changed",
"sandbox.metric",
"workspace.ready",
"workspace.change.updated",
"workspace.diff.recorded",
"workspace.file.referenced",
"harness.starting",
"harness.ready",
"harness.exited",
"harness.diagnostic",
"plan.updated",
"tool.execution.started",
"tool.execution.progressed",
"tool.execution.completed",
"research.started",
"research.progressed",
"research.completed",
"delegation.started",
"delegation.updated",
"delegation.completed",
"model.route.changed",
"model.verification.updated",
"context.compacted",
"artifact.viewed",
"artifact.generated",
"review.mode.changed",
"hook.started",
"hook.completed",
"memory.citation.referenced",
"safety.review.started",
"safety.review.completed",
"terminal.input.sent",
"wait.started",
"wait.completed",
"provider.notice.recorded",
"session.starting",
"session.started",
"session.resuming",
"session.resumed",
"session.reconciled",
"session.updated",
"session.closed",
"session.failed",
"session.capabilities.updated",
"session.goal.snapshot",
"session.goal.updated",
"session.goal.cleared",
"turn.submitted",
"turn.accepted",
"turn.started",
"turn.completed",
"turn.failed",
"turn.interrupted",
"turn.cancelled",
"item.started",
"item.delta",
"item.completed",
"item.failed",
"usage.reported",
"semantic_tool.input",
"semantic_tool.result",
"mcp_app.discovered",
"mcp_app.resource.resolved",
"mcp_app.initializing",
"mcp_app.ready",
"mcp_app.tool_input",
"mcp_app.tool_result",
"mcp_app.action.requested",
"mcp_app.action.resolved",
"mcp_app.host_context.changed",
"mcp_app.failed",
"mcp_app.teardown",
"runtime_request.created",
"runtime_request.resolved",
"runtime_request.expired",
"runtime_request.cancelled",
"interaction.request.proposed",
"interaction.request.materialized",
"interaction.request.rejected",
"interaction.response.progressed",
"interaction.response.resolved",
"interaction.response.delivered",
"run.attached",
"run.detached",
"run.result.proposed",
"run.result.accepted",
"run.result.rejected",
"attention.request.proposed",
"attention.request.routed",
"attention.request.resolved",
"attention.request.expired",
"attention.request.superseded",
"work.assessment.recorded",
"issue.status.decision.recorded",
"issue.status.decision.applied",
"issue.status.decision.rejected",
"issue.status.decision.superseded",
"run.terminal",
"external_provider.dispatch_requested",
"external_provider.operation_settled",
"external_provider.input_available",
"auth.credentials.updated",
"runtime.activity.recorded"
]
},
"schemaVersion": {
"const": 3
},
"priority": {
"enum": [
0,
1,
2
]
},
"emittedAt": {
"type": "string",
"format": "date-time"
},
"observedAt": {
"type": "string",
"format": "date-time"
},
"payload": {
"type": "object",
"additionalProperties": true
},
"debug": {
"type": "object",
"additionalProperties": true
}
},
"allOf": [
{
"if": {
"properties": {
"eventType": {
"enum": [
"session.goal.snapshot",
"session.goal.updated"
]
}
},
"type": "object"
},
"then": {
"properties": {
"payload": {
"type": "object",
"required": [
"goal"
],
"properties": {
"goal": {
"oneOf": [
{
"$ref": "https://paperclip.dev/schemas/prp/v2/session-goal.schema.json#/$defs/snapshot"
},
{
"type": "null"
}
]
}
},
"additionalProperties": true
}
},
"type": "object"
}
},
{
"if": {
"properties": {
"eventType": {
"const": "session.capabilities.updated"
}
},
"type": "object"
},
"then": {
"properties": {
"payload": {
"type": "object",
"required": [
"sessionGoals"
],
"properties": {
"sessionGoals": {
"$ref": "https://paperclip.dev/schemas/prp/v2/session-goal.schema.json#/$defs/capability"
},
"turnControls": {
"$ref": "https://paperclip.dev/schemas/prp/v1/provider-descriptor.schema.json#/$defs/turnControls"
}
},
"additionalProperties": true
}
},
"type": "object"
}
},
{
"if": {
"properties": {
"eventType": {
"const": "external_provider.dispatch_requested"
}
},
"type": "object"
},
"then": {
"properties": {
"payload": {
"oneOf": [
{
"type": "object",
"properties": {
"binding": {
"type": "object",
"properties": {
"companyId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"agentId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"bindingId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"runId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"normalizedSessionId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"turnId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"bindingGeneration": {
"type": "integer",
"minimum": 1
},
"assignmentRevision": {
"type": "integer",
"minimum": 1
}
},
"additionalProperties": false,
"required": [
"companyId",
"agentId",
"bindingId",
"runId",
"normalizedSessionId",
"turnId",
"bindingGeneration",
"assignmentRevision"
]
},
"text": {
"type": "string",
"minLength": 1,
"maxLength": 1048576
},
"instructions": {
"type": "string",
"maxLength": 1048576
},
"acceptByUnixMs": {
"type": "integer",
"minimum": 1
},
"expiresAtUnixMs": {
"type": "integer",
"minimum": 1
},
"completionContract": {
"type": "object",
"properties": {
"revision": {
"type": "string",
"minLength": 1
},
"criterionIds": {
"type": "array",
"minItems": 1,
"maxItems": 256,
"uniqueItems": true,
"items": {
"type": "string",
"minLength": 1
}
}
},
"required": [
"revision",
"criterionIds"
],
"additionalProperties": false
},
"tools": {
"type": "array",
"items": {
"type": "object"
},
"maxItems": 512
}
},
"additionalProperties": false,
"required": [
"binding",
"text",
"instructions",
"acceptByUnixMs",
"expiresAtUnixMs",
"completionContract",
"tools"
]
},
{
"type": "object",
"properties": {
"binding": {
"type": "object",
"properties": {
"companyId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"agentId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"bindingId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"runId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"normalizedSessionId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"turnId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"bindingGeneration": {
"type": "integer",
"minimum": 1
},
"assignmentRevision": {
"type": "integer",
"minimum": 1
}
},
"additionalProperties": false,
"required": [
"companyId",
"agentId",
"bindingId",
"runId",
"normalizedSessionId",
"turnId",
"bindingGeneration",
"assignmentRevision"
]
},
"kind": {
"const": "authority_revoked"
},
"reason": {
"type": "string"
},
"externalStopConfirmed": {
"const": false
}
},
"required": [
"binding",
"kind",
"externalStopConfirmed"
],
"additionalProperties": false
}
]
}
},
"type": "object"
}
},
{
"if": {
"properties": {
"eventType": {
"const": "external_provider.operation_settled"
}
},
"type": "object"
},
"then": {
"properties": {
"payload": {
"type": "object",
"properties": {
"binding": {
"type": "object",
"properties": {
"companyId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"agentId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"bindingId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"runId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"normalizedSessionId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"turnId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"bindingGeneration": {
"type": "integer",
"minimum": 1
},
"assignmentRevision": {
"type": "integer",
"minimum": 1
}
},
"additionalProperties": false,
"required": [
"companyId",
"agentId",
"bindingId",
"runId",
"normalizedSessionId",
"turnId",
"bindingGeneration",
"assignmentRevision"
]
},
"requestId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"outcome": {
"type": "object"
}
},
"required": [
"binding",
"requestId",
"outcome"
],
"additionalProperties": false
}
},
"type": "object"
}
},
{
"if": {
"properties": {
"eventType": {
"const": "external_provider.input_available"
}
},
"type": "object"
},
"then": {
"properties": {
"payload": {
"type": "object",
"properties": {
"binding": {
"type": "object",
"properties": {
"companyId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"agentId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"bindingId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"runId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"normalizedSessionId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"turnId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"bindingGeneration": {
"type": "integer",
"minimum": 1
},
"assignmentRevision": {
"type": "integer",
"minimum": 1
}
},
"additionalProperties": false,
"required": [
"companyId",
"agentId",
"bindingId",
"runId",
"normalizedSessionId",
"turnId",
"bindingGeneration",
"assignmentRevision"
]
},
"requestId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"turnId": {
"type": "string",
"minLength": 1,
"maxLength": 240
},
"inputDigest": {
"type": "string",
"pattern": "^sha256:[0-9a-f]{64}$"
},
"response": {
"$ref": "https://paperclip.dev/schemas/prp/v1/question-response.schema.json"
}
},
"required": [
"binding",
"requestId",
"turnId",
"inputDigest",
"response"
],
"additionalProperties": false
}
},
"type": "object"
}
},
{
"if": {
"properties": {
"eventType": {
"const": "auth.credentials.updated"
}
}
},
"then": {
"properties": {
"sourceKind": {
"const": "runner"
},
"priority": {
"const": 0
},
"payload": {
"$ref": "https://paperclip.dev/schemas/prp/v1/auth-credentials.schema.json"
}
}
}
},
{
"if": {
"properties": {
"eventType": {
"const": "runtime.activity.recorded"
}
}
},
"then": {
"properties": {
"sourceKind": {
"const": "runner"
},
"priority": {
"const": 1
},
"payload": {
"type": "object",
"required": [
"namespace",
"activityKey"
],
"properties": {
"namespace": {
"type": "string",
"minLength": 1,
"maxLength": 160,
"pattern": "^[^\\u0000-\\u001f\\u007f]+$"
},
"activityKey": {
"type": "string",
"minLength": 1,
"maxLength": 160,
"pattern": "^[^\\u0000-\\u001f\\u007f]+$"
}
},
"additionalProperties": false
}
}
}
}
],
"additionalProperties": true
}