Includes AirPlan design documents, AircOding-alpha1-plan, AirPlanV2, AirPlan-ParaV2, AirPlan-Para V1 reference docs, and all working code changes across packages. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
26 KiB
Executable File
AirCoding Event Payload Registry V1
Date: 2026-05-27 Status: Canonical event and payload registry for V1.0.0 Alpha skeleton
This document defines the V1 RuntimeEvent type registry, persistence policy, payload shapes, and producer/consumer rules.
Event envelope is defined in baselineV1.md and packages/contracts/event.ts:
interface RuntimeEvent<T = unknown> {
id: string
type: string
version: number
timestamp: string
session_id: string
project_id?: string
source: EventSource
route: string[]
payload: T
}
Registry rule:
event_type → payload schema → persistence policy → domain transaction → producer → consumers
Event producers must not decide persistence ad hoc. EventStore owns persistence policy by event type.
1. Common Payload Conventions
All payloads use snake_case JSON keys to match persisted DB column names and artifact metadata.
Common aliases:
type ISOTimeString = string
type JsonObject = Record<string, unknown>
type EventPersistence = "durable" | "ephemeral"
type EventDelivery = "eventbus" | "eventbus_and_db"
Common lightweight references:
EntityRef is defined in interface-contracts-v1.md §4 with the canonical EntityType enum (12 values including capability and provider). This document uses EntityRef by reference.
interface EvidenceLink {
evidence_ref_id?: string
artifact_id?: string
diagnostic_id?: string
claim: string
}
interface FailurePayload {
error: AirError
evidence_refs?: EvidenceLink[]
metadata?: JsonObject
}
Payloads should contain identifiers needed for routing/querying even when the same identifiers are also extracted into top-level event columns and domain tables.
2. Persistence and Transaction Rules
Persistence categories:
durable → inserted into events table and applied to domain tables in one transaction
ephemeral → published on EventBus only, not required for crash recovery
Rules:
- Durable event insert and corresponding domain table update must happen in the same SQLite transaction.
- Ephemeral events may be throttled or coalesced by EventBus/ProjectionStore.
- Ephemeral events that become important for diagnosis should be captured as artifacts or durable summaries, not promoted ad hoc.
- Streaming deltas are ephemeral; completed message/tool/command records are durable.
routeis append-only. Forwarders append their route segment; they never rewrite earlier route entries.route_textin SQLite is derived fromroute.join("/")for indexing.- Payload schema changes require incrementing the event
versionfor that event type.
3. Durable Event Registry
3.1 Session Events
session.created v1
Persistence: durable.
Producer: Main Agent / CLI startup.
Domain update: insert sessions row.
interface SessionCreatedPayload {
session_id: string
project_id: string
project_root: string
title?: string
model_provider_id?: string
model_id?: string
metadata?: JsonObject
}
session.archived v1
Persistence: durable.
Domain update: update sessions.status = archived.
interface SessionArchivedPayload {
session_id: string
reason?: string
}
session.deleted v1
Persistence: durable.
Domain update: update sessions.status = deleted.
interface SessionDeletedPayload {
session_id: string
reason?: string
}
3.2 Message Events
user.message.created v1
Persistence: durable.
Domain update: insert messages row.
interface UserMessageCreatedPayload {
message_id: string
canonical_format: "anthropic"
content_json: unknown
parent_message_id?: string
token_estimate?: number
metadata?: JsonObject
}
assistant.message.started v1
Persistence: durable.
Domain update: insert/update message_drafts row with status = streaming.
interface AssistantMessageStartedPayload {
message_id: string
canonical_format: "anthropic"
parent_message_id?: string
route?: string[]
metadata?: JsonObject
}
assistant.message.created v1
Persistence: durable.
Domain update: insert messages row and delete matching message_drafts row.
interface AssistantMessageCreatedPayload {
message_id: string
canonical_format: "anthropic"
content_json: unknown
parent_message_id?: string
route?: string[]
token_estimate?: number
metadata?: JsonObject
}
assistant.message.failed v1
Persistence: durable.
Domain update: update message_drafts.status = error or create failure artifact if draft is absent.
interface AssistantMessageFailedPayload extends FailurePayload {
message_id: string
partial_content_json?: unknown
}
3.3 Agent Events
agent.started v1
Persistence: durable.
Domain update: insert agents row with status = running or starting.
interface AgentStartedPayload {
agent_id: string
agent_type: "executor" | "reviewer" | "debugger" | "compactor" | "experience_miner"
task_id?: string
pid?: number
model_provider_id?: string
model_id?: string
workspace_id?: string
metadata?: JsonObject
}
agent.completed v1
Persistence: durable.
Domain update: update agents.status = completed.
interface AgentCompletedPayload {
agent_id: string
task_id?: string
summary: string
worker_result_ref?: string
metadata?: JsonObject
}
agent.failed v1
Persistence: durable.
Domain update: update agents.status = failed.
interface AgentFailedPayload extends FailurePayload {
agent_id: string
task_id?: string
}
agent.lost v1
Persistence: durable.
Domain update: update agents.status = lost.
interface AgentLostPayload {
agent_id: string
task_id?: string
last_heartbeat_at?: ISOTimeString
detection_reason: "heartbeat_timeout" | "process_exit_without_result" | "ipc_broken"
}
agent.cancelled v1
Persistence: durable.
Domain update: update agents.status = cancelled.
interface AgentCancelledPayload {
agent_id: string
task_id?: string
reason: string
}
3.4 Task Events
task.created v1
Persistence: durable.
Domain update: insert tasks row and optional task_dependencies rows.
interface TaskDependencySpec {
depends_on_task_id: string
dependency_type: "hard" | "soft" | "conflict" | "serialization"
reason?: string
source?: "architecture" | "scheduler" | "worker" | "user" | "system"
}
interface TaskCreatedPayload {
task_id: string
type: "execute" | "review" | "debug" | "compact" | "mine_experience"
title: string
task_spec_json: unknown
dependencies?: TaskDependencySpec[]
metadata?: JsonObject
}
task.started v1
Persistence: durable.
Domain update: update tasks.status = running, set started_at, assigned_agent_id, workspace_id; insert task_attempts row.
interface TaskStartedPayload {
task_id: string
agent_id: string
attempt_id: string
attempt_index: number
workspace_id?: string
}
task.completed v1
Persistence: durable.
Domain update: update tasks.status = completed, set worker_result_json, completed_at; update task_attempts.
interface TaskCompletedPayload {
task_id: string
agent_id?: string
attempt_id?: string
worker_result_json: unknown
summary: string
changed_files?: string[]
evidence_refs?: EvidenceLink[]
}
task.blocked v1
Persistence: durable.
Domain update: update tasks.status = blocked; update task_attempts if applicable.
interface TaskBlockedPayload {
task_id: string
agent_id?: string
reason: string
blocker_kind: "user_decision" | "architecture_decision" | "environment" | "permission" | "dependency" | "external"
evidence_refs?: EvidenceLink[]
suggested_next_step?: string
}
task.failed v1
Persistence: durable.
Domain update: update tasks.status = failed; update task_attempts.failure_*.
interface TaskFailedPayload extends FailurePayload {
task_id: string
agent_id?: string
attempt_id?: string
}
task.cancelled v1
Persistence: durable.
Domain update: update tasks.status = cancelled.
interface TaskCancelledPayload {
task_id: string
reason: string
cancelled_by: "user" | "main" | "scheduler" | "system"
}
task.interrupted v1
Persistence: durable.
Domain update: update tasks.status = interrupted.
interface TaskInterruptedPayload {
task_id: string
reason: string
resumable: boolean
resume_ref?: string
}
task.removed v1
Persistence: durable.
Domain update: delete tasks row (only for pending status); insert event record.
interface TaskRemovedPayload {
task_id: string
reason: string
removed_by: string
}
task.invalidated v1
Persistence: durable.
Domain update: update tasks.status = invalidated; insert event record.
interface TaskInvalidatedPayload {
task_id: string
adr_id: string
reason: string
rollback_ref?: string
}
3.5 Tool Events
tool.started v1
Persistence: durable.
Domain update: insert tool_runs row with status = running.
interface ToolStartedPayload {
tool_run_id: string
tool_name: string
task_id?: string
agent_id?: string
origin_message_id?: string
input_json: unknown
metadata?: JsonObject
}
tool.completed v1
Persistence: durable.
Domain update: update tool_runs.status = ok, set output/artifacts/evidence/duration.
interface ToolCompletedPayload {
tool_run_id: string
output_json?: unknown
duration_ms?: number
artifact_ids?: string[]
evidence_refs?: EvidenceLink[]
metadata?: JsonObject
}
tool.failed v1
Persistence: durable.
Domain update: update tool_runs.status = error.
interface ToolFailedPayload extends FailurePayload {
tool_run_id: string
duration_ms?: number
}
tool.cancelled v1
Persistence: durable.
Domain update: update tool_runs.status = cancelled.
interface ToolCancelledPayload {
tool_run_id: string
reason: string
}
3.6 Command Events
command.started v1
Persistence: durable.
Domain update: insert command_runs row.
interface CommandStartedPayload {
command_run_id: string
task_id?: string
agent_id?: string
origin_message_id?: string
tool_run_id?: string
command: string
cwd: string
metadata?: JsonObject
}
command.completed v1
Persistence: durable.
Domain update: update command_runs.exit_code, artifact refs, diagnostics, duration.
interface CommandCompletedPayload {
command_run_id: string
exit_code: number
duration_ms?: number
stdout_artifact_id?: string
stderr_artifact_id?: string
combined_artifact_id?: string
diagnostic_ids?: string[]
parsed_diagnostics_json?: unknown
metadata?: JsonObject
}
command.failed v1
Persistence: durable.
Domain update: update command_runs.exit_code when available and create failure artifacts.
interface CommandFailedPayload extends FailurePayload {
command_run_id: string
exit_code?: number
duration_ms?: number
stdout_artifact_id?: string
stderr_artifact_id?: string
combined_artifact_id?: string
}
3.7 Artifact, Diagnostic, and Evidence Events
artifact.created v1
Persistence: durable.
Domain update: insert artifacts row after file has been written temp → atomic rename.
interface ArtifactCreatedPayload {
artifact_id: string
type: string
uri: string
path: string
original_name?: string
size_bytes?: number
sha256?: string
task_id?: string
agent_id?: string
tool_run_id?: string
command_run_id?: string
associated_entity_type?: string
associated_entity_id?: string
metadata?: JsonObject
}
diagnostic.created v1
Persistence: durable.
Domain update: insert diagnostics row.
interface DiagnosticCreatedPayload {
diagnostic_id: string
task_id?: string
agent_id?: string
command_run_id?: string
artifact_id?: string
language?: string
toolchain?: string
severity?: string
file?: string
line?: number
column?: number
code?: string
message: string
semantic_signature: string
metadata?: JsonObject
}
evidence.created v1
Persistence: durable.
Domain update: insert evidence_refs row.
interface EvidenceCreatedPayload {
evidence_ref_id: string
kind: string
ref: string
location_json?: unknown
claim: string
task_id?: string
agent_id?: string
tool_run_id?: string
command_run_id?: string
artifact_id?: string
diagnostic_id?: string
message_id?: string
}
3.8 Context and Summary Events
context.compaction.requested v1
Persistence: durable.
Domain update: insert compaction task if Scheduler accepts it.
interface ContextCompactionRequestedPayload {
reason: "token_budget" | "user_request" | "session_checkpoint" | "manual"
range_start_message_id?: string
range_end_message_id?: string
target_budget_tokens?: number
}
context.compaction.started v1
Persistence: durable.
Domain update: mark compaction task running.
interface ContextCompactionStartedPayload {
task_id: string
agent_id: string
range_start_message_id?: string
range_end_message_id?: string
}
context.compaction.completed v1
Persistence: durable.
Domain update: mark compaction task complete. The summaries row is inserted by summary.created, not by this event.
interface ContextCompactionCompletedPayload {
task_id?: string
agent_id?: string
summary_id: string
range_start_message_id?: string
range_end_message_id?: string
token_estimate_before?: number
token_estimate_after?: number
}
context.compaction.failed v1
Persistence: durable.
Domain update: mark compaction task failed or blocked.
interface ContextCompactionFailedPayload extends FailurePayload {
task_id?: string
agent_id?: string
range_start_message_id?: string
range_end_message_id?: string
}
summary.created v1
Persistence: durable.
Domain update: insert summaries row.
interface SummaryCreatedPayload {
summary_id: string
type: string
range_start_message_id?: string
range_end_message_id?: string
content_json: unknown
metadata?: JsonObject
}
3.9 Permission Events
permission.decision.recorded v1
Persistence: durable.
Domain update: append permission decision record to events; optional future projection table.
interface PermissionDecisionRecordedPayload {
decision_id: string
subject: "tool" | "command" | "path" | "network" | "dependency" | "migration"
action: "allow" | "deny" | "ask_user" | "block" | "refuse" | "announce_then_run"
grant_scope: "none" | "once" | "session" | "project" | "global"
reason?: string
risk_level: "low" | "medium" | "high" | "critical"
decided_by: "user" | "policy" | "high_permission_mode" | "system"
scope_json?: unknown
expires_at?: ISOTimeString
}
permission.prompt.requested v1
Persistence: durable.
Domain update: append event; optional UI projection.
interface PermissionPromptRequestedPayload {
prompt_id: string
subject: string
risk_level: "low" | "medium" | "high" | "critical"
reason: string
options: string[]
default_option?: string
request_ref?: EntityRef
}
permission.prompt.resolved v1
Persistence: durable.
Domain update: append event and create permission.decision.recorded if applicable.
interface PermissionPromptResolvedPayload {
prompt_id: string
selected_option: string
decision_id?: string
resolved_by: "user" | "timeout" | "system"
}
3.10 Doctor and Dependency Events
doctor.run.started v1
Persistence: durable.
Domain update: append event and create optional report artifact later.
interface DoctorRunStartedPayload {
run_id: string
mode: "read_only" | "fix"
trigger: "startup" | "manual" | "dependency_request" | "release_gate"
}
doctor.issue.found v1
Persistence: durable.
Domain update: append event and optional diagnostic/report artifact.
interface DoctorIssueFoundPayload {
run_id: string
issue_id: string
severity: "info" | "warning" | "error" | "blocking"
capability?: string
dependency?: string
message: string
fix_available: boolean
fix_requires_confirmation?: boolean
}
doctor.fix.started v1
Persistence: durable.
Domain update: append event and optional command/tool run rows.
interface DoctorFixStartedPayload {
run_id: string
issue_id: string
fix_id: string
strategy: string
}
doctor.fix.completed v1
Persistence: durable.
Domain update: append event and update report artifact.
interface DoctorFixCompletedPayload {
run_id: string
issue_id: string
fix_id: string
evidence_refs?: EvidenceLink[]
}
doctor.fix.failed v1
Persistence: durable.
Domain update: append event and update report artifact.
interface DoctorFixFailedPayload extends FailurePayload {
run_id: string
issue_id: string
fix_id: string
}
doctor.run.completed v1
Persistence: durable.
Domain update: append event and create doctor report artifact.
interface DoctorRunCompletedPayload {
run_id: string
status: "passed" | "issues_found" | "fixed" | "failed"
issue_count: number
blocking_issue_count: number
report_artifact_id?: string
}
3.11 Requirement and Architecture Events
requirement.changed v1
Persistence: durable.
Domain update: append event and mark impacted tasks when Scheduler applies it.
interface RequirementChangedPayload {
change_id: string
origin_message_id: string
summary: string
change_type: "clarification" | "scope_change" | "architecture_change" | "constraint_change" | "cancellation"
affected_refs?: EntityRef[]
}
architecture.plan.updated v1
Persistence: durable.
Domain update: append event and artifact/plan references.
interface ArchitecturePlanUpdatedPayload {
plan_ref: string
update_kind: "created" | "revised" | "superseded"
summary: string
affected_task_ids?: string[]
adr_refs?: string[]
c4_refs?: string[]
}
architecture.impact.completed v1
Persistence: durable.
Domain update: append event; Scheduler consumes to continue/replan/block.
interface ArchitectureImpactCompletedPayload {
assessment_id: string
requirement_change_id?: string
impact_level: "implementation" | "interface" | "architecture" | "product"
decision: "silent_continue" | "requires_user_confirmation" | "requires_replan" | "reject_or_escalate"
summary: string
affected_task_ids?: string[]
evidence_refs?: EvidenceLink[]
}
3.12 Workspace and Merge Events
workspace.created v1
Persistence: durable.
Domain update: insert workspaces row.
interface WorkspaceCreatedPayload {
workspace_id: string
task_id?: string
agent_id?: string
path: string
strategy: "main" | "worktree" | "isolated_copy"
base_ref?: string
branch_name?: string
}
workspace.merge.started v1
Persistence: durable.
Domain update: append event and mark workspace merge in progress in metadata.
interface WorkspaceMergeStartedPayload {
workspace_id: string
task_id?: string
strategy: "fast_forward" | "patch_apply" | "manual_merge" | "copy_back"
target_ref?: string
}
workspace.merge.completed v1
Persistence: durable.
Domain update: update workspaces.status = merged, set merged_at.
interface WorkspaceMergeCompletedPayload {
workspace_id: string
task_id?: string
merged_ref?: string
diff_artifact_id?: string
}
workspace.merge.conflicted v1
Persistence: durable.
Domain update: update workspaces.status = conflicted.
interface WorkspaceMergeConflictedPayload {
workspace_id: string
task_id?: string
conflict_files: string[]
conflict_artifact_id?: string
suggested_resolution?: "retry_serial" | "debugger" | "architecture_review" | "user_decision"
}
workspace.cleaned v1
Persistence: durable.
Domain update: update workspaces.status = cleaned or append cleanup metadata.
interface WorkspaceCleanedPayload {
workspace_id: string
reason: "merged" | "cancelled" | "abandoned" | "manual"
}
3.13 Memory and Debug Knowledge Events
memory.candidate.created v1
Persistence: durable.
Domain update: append event; future memory table may project it.
interface MemoryCandidateCreatedPayload {
candidate_id: string
source_ref: EntityRef
memory_type: "project_rule" | "toolchain_rule" | "skill_update" | "debug_experience"
summary: string
evidence_refs?: EvidenceLink[]
}
memory.promoted v1
Persistence: durable.
Domain update: append event and update .air/shared/rules, skill, or learned-memory.db through the owning subsystem.
interface MemoryPromotedPayload {
candidate_id: string
target_ref: string
promoted_by: "user" | "curator" | "system"
summary: string
}
memory.archived v1
Persistence: durable.
Domain update: append event and mark memory inactive in owning subsystem.
interface MemoryArchivedPayload {
candidate_id?: string
memory_ref?: string
reason: string
}
debug.record.created v1
Persistence: durable.
Domain update: insert/update debug-records.db and append event in session DB.
interface DebugRecordCreatedPayload {
debug_record_id: string
task_id?: string
failure_signature: string
summary: string
evidence_refs?: EvidenceLink[]
verification_refs?: EvidenceLink[]
}
4. Ephemeral Event Registry
Ephemeral events are for live rendering, streaming, and heartbeat. They are not required for crash recovery.
agent.heartbeat v1
Producer: child agent process.
Consumer: Scheduler, ProjectionStore.
interface AgentHeartbeatPayload {
agent_id: string
task_id?: string
status: "starting" | "running"
progress_text?: string
current_step?: string
resource_snapshot?: {
pid?: number
cpu_percent?: number
memory_bytes?: number
}
}
task.progress v1
Producer: Scheduler or worker agent.
Consumer: ProjectionStore, Main Agent summaries.
interface TaskProgressPayload {
task_id: string
agent_id?: string
phase?: string
progress_text: string
percent?: number
}
assistant.message.delta v1
Producer: Main Agent / provider adapter.
Consumer: ProjectionStore; message_drafts may be periodically flushed by draft writer.
interface AssistantMessageDeltaPayload {
message_id: string
delta: unknown
sequence: number
}
tool.progress v1
Producer: streaming tool.
Consumer: ProjectionStore, command/tool monitor.
interface ToolProgressPayload {
tool_run_id: string
message: string
progress_json?: unknown
}
command.stdout.delta v1 and command.stderr.delta v1
Producer: shell/command runner.
Consumer: ProjectionStore, artifact writer.
interface CommandStreamDeltaPayload {
command_run_id: string
chunk: string
sequence: number
truncated?: boolean
}
hud.frame.rendered v1
Producer: TUI/HUD.
Consumer: local performance/debug logging only.
interface HudFrameRenderedPayload {
frame_id: string
duration_ms?: number
dropped_frame_count?: number
}
5. Producer and Consumer Boundaries
Producer responsibilities:
- Emit valid RuntimeEvent envelopes.
- Provide IDs generated by the subsystem that owns the entity.
- Append route segment when forwarding.
- Never update SQLite domain tables directly unless the producer is the owning store/service.
EventStore responsibilities:
- Validate event version and payload schema.
- Apply durable events and domain table updates transactionally.
- Derive query columns such as
task_id,agent_id,tool_run_id,command_run_id,route_text. - Publish committed durable events to EventBus after commit.
- Reject unknown durable event types unless explicitly allowed by development-mode config.
ProjectionStore responsibilities:
- Hydrate from DB at startup/resume.
- Apply live durable and ephemeral events.
- Coalesce noisy deltas for TUI/HUD.
- Never become the source of truth for scheduling or recovery.
Scheduler responsibilities:
- Consume task/agent/workspace/architecture events.
- Drive retries, dependency unblocking, merge waves, and escalation.
- Treat missing heartbeat as
agent.lostand persist that durable event.
6. V1 Event Type Index
Durable:
session.created
session.archived
session.deleted
user.message.created
assistant.message.started
assistant.message.created
assistant.message.failed
agent.started
agent.completed
agent.failed
agent.lost
agent.cancelled
task.created
task.started
task.completed
task.blocked
task.failed
task.cancelled
task.interrupted
tool.started
tool.completed
tool.failed
tool.cancelled
command.started
command.completed
command.failed
artifact.created
diagnostic.created
evidence.created
context.compaction.requested
context.compaction.started
context.compaction.completed
context.compaction.failed
summary.created
permission.decision.recorded
permission.prompt.requested
permission.prompt.resolved
doctor.run.started
doctor.issue.found
doctor.fix.started
doctor.fix.completed
doctor.fix.failed
doctor.run.completed
requirement.changed
architecture.plan.updated
architecture.impact.completed
workspace.created
workspace.merge.started
workspace.merge.completed
workspace.merge.conflicted
workspace.cleaned
memory.candidate.created
memory.promoted
memory.archived
debug.record.created
Ephemeral:
agent.heartbeat
task.progress
assistant.message.delta
tool.progress
command.stdout.delta
command.stderr.delta
hud.frame.rendered
7. V1.0.0 Alpha Cut Line
The V1.0.0 Alpha skeleton must implement schema validation and EventStore handling for all durable event names in the V1 index, even if some subsystem producers are initially stubs.
The first implementation may keep payload schemas in TypeScript with runtime validation generated from the same definitions. Unknown plugin/capability events must use a namespaced prefix and must not be durable until registered.