Event Types

All event types are defined in foundry-sdk/src/event.rs as the EventType enum. The string representation uses snake_case.

Every event carries these common fields:

FieldTypeDescription
idstringDeterministic SHA-256 derived ID, prefixed evt_
event_typestringSnake-case event type name
projectstringProject this event relates to
occurred_atRFC 3339 timestampWhen the event happened
recorded_atRFC 3339 timestampWhen the event was logged
throttlestringfull or dry_run
payloadJSON objectEvent-type-specific fields (see below)
trace_idstring or nullOTel trace identity
span_idstring or nullCurrent workflow span identity
parent_span_idstring or nullParent span identity
causation_idstring or nullEvent that caused this event
gather_idstring or nullScatter/gather group identity

Hello-World (engine validation)

TypeDescription
greet_requestedRequest to compose and deliver a greeting
greeting_composedGreeting message has been composed
greeting_deliveredGreeting has been delivered (side effect)

greet_requested payload

FieldTypeDescription
namestringName to greet

greeting_composed payload

FieldTypeDescription
greetingstringComposed greeting text

Vulnerability Remediation

TypeDescription
scan_requestedRequest to scan a project for known vulnerabilities
vulnerability_detectedA vulnerability was found (or injected externally)
release_tag_auditedLatest release tag scanned for the vulnerability
main_branch_auditedMain branch checked for the same vulnerability
remediation_startedAutomated fix attempt initiated
remediation_completedFix attempt finished (success or failure)

vulnerability_detected payload

FieldTypeDescription
cvestringCVE or advisory ID (e.g. "CVE-2026-1234")
vulnerableboolWhether the project is affected
dirtybool (optional)Whether the main branch still contains the vulnerability

release_tag_audited payload

FieldTypeDescription
cvestringCVE from the scan or forwarded from the trigger
vulnerableboolWhether the release tag is affected
dirtybool (optional)Forwarded from the upstream trigger for downstream routing

main_branch_audited payload

FieldTypeDescription
cvestringCVE identifier
dirtybooltrue if the vulnerability is still present on main

remediation_completed payload

FieldTypeDescription
cvestringCVE that was remediated
successboolWhether the fix was applied successfully

Release Lifecycle

TypeDescription
release_requestedDecision made to cut a patch release
release_completedRelease tag created and pushed
release_pipeline_completedGitHub Actions build/publish workflow finished

release_completed payload

FieldTypeDescription
cvestringCVE that prompted the release
releasestringRelease type (e.g. "patch")
new_tagstring or nullSemver tag extracted from Claude CLI output
successboolWhether the Claude CLI invocation succeeded

release_pipeline_completed payload

FieldTypeDescription
statusstring"success" or "failure"
conclusionstring (optional)GitHub Actions conclusion label

Project Lifecycle

TypeDescription
project_validation_completedPre-flight checks for a maintenance run
project_iteration_completedIterate workflow finished
project_maintenance_completedMaintain workflow finished
project_changes_committedGit commit created
project_changes_pushedChanges pushed to remote

project_validation_completed payload

FieldTypeDescription
statusstring"ok", "error", or "skipped"
reasonstring (optional)Human-readable explanation when status is not "ok"
has_gatesbool (optional)Whether .hone-gates.json is present (only on "ok")
fast_forwardedint (optional)Commits fast-forwarded from origin/<branch> before work began (only on "ok")
sync_failurestring (optional)Typed reason the checkout sync was refused: "dirty_tree", "diverged", or "remote_unavailable"
dry_runbool (optional)true when the sync was simulated; fast_forwarded is then the count that would be applied

project_iteration_completed payload

FieldTypeDescription
projectstringProject name
workflowstring"iterate"
successboolWhether the iterate workflow succeeded
summarystringHuman-readable summary of the result
changesbool (optional)Whether code changes were made

project_maintenance_completed payload

FieldTypeDescription
projectstringProject name
workflowstring"maintain"
successboolWhether the maintain workflow succeeded
summarystringHuman-readable summary of the result
changesbool (optional)Whether code changes were made

project_changes_committed payload

FieldTypeDescription
cvestringCVE or "unknown" (from remediation path)
messagestringGit commit message used
push_failurestring (optional)Why the commit was not pushed: "push_rejected_diverged" (rebase onto the moved remote conflicted) or "remote_unavailable"

project_changes_pushed payload

FieldTypeDescription
cvestringCVE or "unknown" (from remediation path)

Local Install

TypeDescription
local_install_completedLocal tool reinstallation finished

Maintenance Workflow

TypePayloadDescription
iteration_requested{ project }Triggers the iterate sub-workflow for a validated project
maintenance_requested{ project }Triggers the maintain sub-workflow for a validated project

Task Lifecycle

TypeDescription
task_run_startedIsolated one-shot task execution began
task_reviewedSkeptical review produced a structural verdict
task_run_completedTask work was landed, durably preserved, or completed with no landing required

task_run_completed payload

FieldTypeDescription
projectstringRegistered project name
successbooltrue only for a complete verdict whose landing was not blocked
landedboolWhether complete or safe converging remainder work reached trunk
summarystringHuman-readable terminal summary
verdictstringcomplete, remainder, defect, blocked_on_decision, or runner_error
preservation_refstring (optional)Continuation ref: landed commit SHA, or remote branch / bundle:<path> for preserved work
land_blockedstring (optional)Why work did not land: trunk_moved_conflict, trunk_moved_gates_failed, stale_base_conflict, stale_base_gates_failed, trunk_moved_repeatedly, checkout_not_ready, or git_failed for landing-eligible work; continuation_conflict for a continuation refused before its agent session (with runner_error). The verdict is unchanged
trunk_arrivalsarray (optional)Trunk commits (commit, subject) the task branch lacked at landing, oldest first; absent when trunk did not move
workspace_baseobject (optional)Where the task worktree started: commit (its first HEAD) and trunk (the trunk commit observed while preparing it). Absent for runs that failed before preparation and for runs that predate it
campaignstring (optional)Campaign that dispatched the task
campaign_cycleinteger (optional)Campaign cycle that dispatched the task

Verdict-specific fields are gaps[], diagnosis, finding plus options[], or detail.

Campaign Formation

TypeDescription
campaign_advance_requestedRequest to re-evaluate a durable campaign
campaign_advance_completedFormation chose done, one next objective, or escalation; or the advance stood down because the campaign was stopped
campaign_pausedProvider unavailability paused a non-terminal campaign
campaign_escalatedCampaign halted for budget, failure, rule, or owner judgment
campaign_completedRequired done evidence proved the mission complete
campaign_cancelledAn owner abandoned the mission before its evidence was met

campaign_cancelled payload

Flattens the shared terminal payload (campaign, project, reason, cycles_completed, cycles_landed) so generic terminal observers parse it unchanged, and adds the operator's disposition choices.

FieldTypeDescription
terminated_nowboolThe in-flight workflow was aborted rather than left to finish
discard_workboolThe terminated cycle's uncommitted work was thrown away
aborted_event_idstring?Root event of the aborted workflow; absent for a graceful stop
aborted_trace_idstring?Trace of the aborted workflow; absent for a graceful stop

An aborted run never reaches trace persistence, so aborted_event_id is the only handle onto its partial events in the JSONL log — foundry trace has nothing to show for it. aborted_trace_id is what correlates the cancellation with the work-item ledger: the killed cycle's item was recorded running under that trace, and a --now cancellation settles it cancelled (see The work queue).

Work-Item Ledger

The six events of the work-item ledger. They report the same durable record at different points in its life, so all six share one payload shape; the event type says which point, and state says where the item stands.

TypeDescription
work_item_submittedA unit of work entered the ledger; paced work arrives queued with the reason it waits
work_item_startedAn agent started on a ledger item
work_item_settledA ledger item reached a settled state, with its disposition
work_item_cancelledAn operator stopped a ledger item
work_item_heldAn operator took a queued item out of the scheduler's hands
work_item_releasedAn operator returned a held or dependency-blocked item to the queue

work_item_started pairs with work_item_settled rather than a work_item_completed: an item does not complete, it settles, into a state that may still hold an obligation. work_item_cancelled is emitted by foundry queue close and foundry queue cancel on the exact item's trace, and by foundry campaign cancel --now on the aborted cycle's trace.

Shared payload

FieldTypeDescription
item_idstringThe item's stable wi_… id
projectstringRegistered project name
objectivestringTask description or campaign objective the work serves
kindstringtask, campaign_cycle, maintenance, major_upgrade, release, remediation
lanestringinteractive, campaign, or maintenance
statestringsubmitted, queued, held, running, landed, preserved, needs_decision, failed, cancelled
reasonstringWhy the item is in that state, in one line
originstringOpaque submitter text; Foundry never interprets it
depends_onarray of stringThe items this one waits on (--after); omitted when empty
not_beforestring (optional)The earliest time the scheduler may start it
dispositionobject (optional)How the item ended; present only on a settlement
operator_actionobject (optional)Owner command, hostname/context in origin, previous_state, previous_reason, optional previous_settled_at; original submission origin and disposition retained

disposition fields

FieldTypeDescription
verdictstring (optional)The reviewer's typed verdict tag, for a task-shaped settlement
landed_commitstring (optional)The trunk commit the work landed as
preservation_refstring (optional)Branch or bundle:<path> holding unlanded work
worktreestring (optional)The isolated worktree the work ran in
worktree_removedbool (optional)Whether that worktree was gone by settlement time

Pacing

TypeDescription
pacing_pausedAn operator paused one or more lanes; nothing in them starts
pacing_resumedAn operator resumed one or more lanes

Both are emitted for the project system, durable and on Watch, after the pause state is saved.

Payload

FieldTypeDescription
lanesarray of stringThe lanes the request named, in lane order
pausedarray of stringEvery paused lane after the change, in lane order
operator_originstringThe CLI's hostname and any --origin text

campaign_advance_requested payload

FieldTypeDescription
campaignstringCampaign name
run_event_idstring (optional)Typed task result that triggered the advance
run_resultobject (optional)Full task_run_completed payload

campaign_advance_completed payload

FieldTypeDescription
campaignstringCampaign name
projectstringRegistered project name
cycles_completedintegerTasks dispatched by the campaign
cycles_landedintegerTask results whose task_run_completed.landed field was true
successbooleantrue for a decision or a stand-down; false for a fault. Absent on older events, read as true
decisionstringdone, advance, escalate, or stood_down
campaign_statusstring (stood_down only)Status that stopped the advance: paused, cancelled, completed, or escalated
objectivestring (advance only)Exactly one next task objective
reasonstringEvidence or gap supporting the decision, or why the advance stood down
promptstring (optional)Exact prompt shown to the formation agent
agent_providerstring (optional)Provider used for the formation decision
gate_resultsarrayResults from campaign done-evidence gates

stood_down means the advance applied nothing because the campaign was stopped before its cycle result arrived or while it formed. It dispatches nothing, changes no status and counts no cycle. Its work item settles landed.

Gate Orchestration

TypeDescription
gate_resolution_completedGate definitions loaded from .hone-gates.json
preflight_completedGates passed/failed on unmodified codebase
execution_completedCode changes applied (emitted by future execution blocks)
gate_verification_completedGates passed/failed after execution
retry_requestedGate failure triggers bounded retry

gate_resolution_completed payload

FieldTypeDescription
projectstringProject name
workflowstring"iterate", "maintain", or "validate"
gatesarrayGate definitions (name, command, required, timeout_secs)
actionsobject (optional)Forwarded actions from the trigger event

preflight_completed payload

FieldTypeDescription
projectstringProject name
workflowstringWorkflow that triggered the preflight
all_passedboolWhether every gate passed
required_passedboolWhether all required gates passed
resultsarrayPer-gate results (name, command, passed, required, output, exit_code, duration_ms?, fix_applied?, logs?)

Each results[] entry includes an optional duration_ms field (unsigned integer) recording how long the gate command took in milliseconds. This field is absent when loading results from events persisted before timing instrumentation was added.

A results[] entry also carries an optional fix_applied boolean: true when the gate initially failed but its fix_command repaired the working tree and the re-check then passed (a self-healed gate). The field is omitted when false, so it is absent for gates that passed clean and for events persisted before self-healing gates were added.

The output field is a bounded view: at most 200 lines per command run, with stdout and stderr tailed separately and a --- stderr --- line between them. A failed gate also carries an optional logs array: the absolute paths of the files under ~/.foundry/evidence/gate-logs/ that hold the complete stdout and stderr of each command the gate ran. The field is omitted when empty, so it is absent for passing gates and for events persisted before gate logs were added. See Gate output and full logs.

gate_verification_completed payload

FieldTypeDescription
projectstringProject name
workflowstringOriginating workflow
all_passedboolWhether every gate passed
required_passedboolWhether all required gates passed
retry_countnumberCurrent retry count (0 on first attempt)
resultsarrayPer-gate results (name, command, passed, required, output, exit_code, duration_ms?, fix_applied?, logs?)

Each results[] entry includes an optional duration_ms field (unsigned integer) recording how long the gate command took in milliseconds. This field is absent when loading results from events persisted before timing instrumentation was added.

A results[] entry also carries an optional fix_applied boolean: true when the gate initially failed but its fix_command repaired the working tree and the re-check then passed (a self-healed gate). The field is omitted when false, so it is absent for gates that passed clean and for events persisted before self-healing gates were added.

The output field is a bounded view: at most 200 lines per command run, with stdout and stderr tailed separately and a --- stderr --- line between them. A failed gate also carries an optional logs array: the absolute paths of the files under ~/.foundry/evidence/gate-logs/ that hold the complete stdout and stderr of each command the gate ran. The field is omitted when empty, so it is absent for passing gates and for events persisted before gate logs were added. See Gate output and full logs.

retry_requested payload

FieldTypeDescription
projectstringProject name
workflowstringOriginating workflow
retry_countnumberIncremented retry count
failure_contextstringGate output from the failed verification, with each failed gate's log paths
actionsobject (optional)Forwarded actions

Validation

TypeDescription
validation_requestedRequest to validate a project's gate health
validation_completedTerminal event with per-gate pass/fail results

validation_requested payload

FieldTypeDescription
projectstringProject name

validation_completed payload

FieldTypeDescription
projectstringProject name
successboolWhether all required gates passed
resultsarrayPer-gate results (name, passed, required, output snippet)

Maintenance Run Lifecycle

TypeDescription
maintenance_run_startedA maintenance run was triggered for a project
maintenance_run_completedAll projects processed, summary available

maintenance_run_started payload

FieldTypeDescription
projectstringProject name this run covers

maintenance_run_completed payload

FieldTypeDescription
totalnumberTotal number of projects processed
succeedednumberProjects that completed successfully
failednumberProjects that encountered an error
skippednumberProjects that were skipped (already active or skip=true)
projectsarrayPer-project result objects (name, status, duration_secs)

Dependency Update Policy

TypeDescription
dependency_review_requestedCommand: classify one project's dependency updates and plan its majors, applying nothing. Optional payload { "policy": "major" } previews another policy
dependency_updates_classifiedA project's direct dependencies were classified and the maintain brief decided
major_upgrades_plannedThe majors lane decided each major upgrade: dispatch, deduped, overflow, deferred or proposed

dependency_updates_classified payload

FieldTypeDescription
projectstringRegistered project name
phasestringbefore (the maintain brief), after (maintenance completed) or review
workflowstring (optional)maintain in the before and after phases
successbool (optional)In the after phase, whether maintenance succeeded
classificationobjectoutdated[] (per dependency: ecosystem, manifest, package, current, requirement, in_range, non_major, major, hold, advisories), classified[], unclassified[], lapsed_holds[], holds_warning, transitive_advisories[], advisory_source
briefobjectpolicy, policy_set, apply[], held_by_policy[], held_by_hold[], majors[]

In the before phase the payload also carries the gate-resolution fields (gates, actions and the rest of the chain context) forward to Execute Maintain.

major_upgrades_planned payload

FieldTypeDescription
upgradesarrayOne entry per major: project, ecosystem, manifest, package, from, to, security, objective, command, status, reason
per_project_capnumberFOUNDRY_MAJOR_TASKS_PER_PROJECT in force
per_night_capnumberFOUNDRY_MAJOR_TASKS_PER_NIGHT in force
dispatch_enabledbooltrue only for the nightly run at full throttle
reviewbooltrue for an on-demand review
history_warningstring (optional)Set when earlier tasks could not be read for dedupe

In the nightly run the payload also carries the maintenance_summary_requested fields (project_trace_ids, skipped_projects, total_duration_ms, root_event_id).

Release Tag Audit

TypeDescription
release_tag_auditedLatest release tag scanned (see payload above)

Agent Session Lifecycle

Emitted by foundryd whenever a Foundry-launched Claude Code agent session begins or ends. Used by visualisation tools (e.g. ops-visualizer) to show in-flight and historical agent activity, and to locate the per-session stream-json transcript on disk.

TypeDescription
agent_session_startedAn agent session has begun; transcript file path is included
agent_session_endedThe agent session has finished (success, failure, unavailable, or interrupted)

agent_session_started payload

FieldTypeDescription
session_idstringUUID identifying this session; matches the transcript file basename
agent_typestringAgent runtime (currently always claude-code)
projectstringProject name (may be empty in v1)
working_dirstringAbsolute path of the working directory the agent ran in
source_log_pathstringAbsolute path to the per-session JSONL transcript (~/.foundry/agent-sessions/<session_id>.jsonl)
capabilitystringCapability label: reasoning, coding, or quick
accessstringTool access level: read_only or full
started_atRFC 3339 timestampWhen the session was launched
trace_idstringCorrelating trace ID (may be empty in v1)

agent_session_ended payload

FieldTypeDescription
session_idstringUUID identifying this session (matches agent_session_started)
statusstringOutcome: ok, agent_failed, unavailable, or interrupted
exit_codenumberProcess exit code (omitted when the agent could not be invoked, and for interrupted)
ended_atRFC 3339 timestampWhen the session finished; for interrupted, when the daemon restarted
bytes_writtennumberTotal bytes streamed to the transcript file (0 for interrupted)
errorstringError message when status = unavailable; daemon restarted when status = interrupted (omitted otherwise)

interrupted sessions. An agent session is a child process of foundryd, so it dies when the daemon stops, and nothing records its end at that moment. On the next start, before it accepts work, foundryd reads the last 7 days of the event log (the same lookback as the interrupted maintenance-cycle recovery) for agent_session_started events with no agent_session_ended for the same session_id. Nothing can be running then, so each such session is dead. For each one, foundryd records an agent_session_ended with status interrupted, error daemon restarted, the original session's project and trace_id, and ended_at set to the daemon start time. The event is persisted to the event log and published on the Watch stream like any other. Because the end is in the log, a later start does not end the same session again. Unparseable lines in the log are skipped and do not stop the daemon from starting. usage and cost are absent: nothing measured the session's last moments.

Initiatives and findings

Lifecycle and finding facts belong to the existing span. Steering requests open an admitted workflow; the decision fact and action request retain its causation and initiative source.

TypeMeaning
initiative_advance_requestedRequest one read-only steering assessment
initiative_steeredRetain the assessment prompt, provider and one typed decision
initiative_action_requestedApply the durable admitted steering action
initiative_owner_action_recordedRecord a direct owner hold, milestone or member override
initiative_addedAn initiative and its member references entered the store
initiative_decidedAn owner decision was recorded for applicable members
initiative_completedThe owner affirmed the shared outcome
initiative_cancelledThe owner stopped the initiative and its members
finding_recordedA typed finding became available to initiative members
finding_consumedA member cycle landed after its formation saw a finding

Initiative lifecycle payloads include initiative, outcome, projects, intent_refs, members, status, authorized_by and budget. Owner actions also retain reason, decision or applicable_members as applicable. Readers can render the initiative and its member references directly.

finding_recorded retains id, finding_id, initiative, from, to, kind, text, refs, consumed_by and recorded_at. The source records its kind and ID. Automatic reviewer gaps and defect diagnoses identify the cycle and the result event. The source envelope names the initiative.

finding_consumed includes initiative, finding_id, member, work_item_id and the updated finding with its consumption records. Consumption follows an actual landing. Forming or preserving a cycle emits no consumption fact.

initiative_advance_requested carries initiative, an optional pinned member, operator_origin and trigger_id. A follow-up request also carries follow_up_of, with steer_id (the steer whose step caused it) and step (that steer's decision, such as relay). Foundry requests one only after an applied hold, relay, ask, escalate or stage while a member stays eligible, and never after a follow-up. Roots are paced on the campaign lane and deduplicated per initiative. A distinct trigger during assessment is retained for a subsequent assessment.

initiative_steered carries success, outcome, error, initiative, steer_id, prompt, decision, provider and the optional durable action. It also carries reason when nothing changed, eligible_members when the precheck found members that can advance, and follow_up_of when the assessment was a follow-up. Its decision is exactly one of advance, dispatch, hold, relay, ask, escalate, stage, done or wait. Only applied requests an action; every other outcome admits no work.

outcomesuccessDetailAssessment work item
appliedtruenonelanded
waitedtruereasonlanded, reason steering waited: <reason>
no_optruereasonlanded, reason steering decision already in force: <reason>
skippedtruereason; no agent ran, so prompt is emptylanded, reason steering skipped: <reason>
rejectedtrueerror holds the guard's messagecancelled, reason steering rejected: <message>
staletrueerrorlanded; a fresh initiative_advance_requested follows
failedfalseerrorfailed

initiative_action_requested carries the persisted action, including its identity, initiative, typed decision, provider pairing and context fingerprint. The admission boundary compares current state before dispatch. Replay uses that identity to acknowledge the same work rather than dispatch it again. Audit findings also retain audit with the intent reference, classification, registered project, checked paths and explanation. Tracker close proposals remain on the initiative; slice 1 does not write Tracker state.

initiative_owner_action_recorded carries initiative, action_id, operator_origin and a typed action (hold, milestone or member_override). It is emitted after persistence and does not activate steering. The event envelope records its timestamp and identity.