🪝 yoink

Audit event schema

Per-variant JSON fields for events in `/var/lib/yoink/audit/events.jsonl`.

Every line in the on-host audit log is a single JSON object. Top-level fields are constant; the event discriminator selects which variant fields are present. See Read the on-host audit log for the operator-facing reading flow.

Envelope (every event)

fieldtypenotes
vintSchema version. Currently 1. Bumped on backward-incompatible changes; older readers can refuse newer lines.
event_idstringUUIDv7 per individual line. The merge view dedupes on this; the TUI uses it as a stable row identifier.
originstring"operator" (line written to $XDG_STATE_HOME/yoink/audit/events.jsonl on the operator's machine) or "host" (line written to /var/lib/yoink/audit/events.jsonl on the managed host).
tsstringRFC 3339 wall-clock with millisecond precision (2026-05-01T15:42:01.317Z).
deploy_idstringUUIDv7 — one per yoink up / rollback / prune / secrets rotate run. Lexicographic sort orders by start time.
actorstring$USER@$HOSTNAME of the operator. ?@? when not resolvable.
yoink_versionstringOperator's yoink version.
git_shastring | nullShort git SHA of the operator's working tree at the time of the run. null when not a git repo or --allow-dirty was set.
hoststringThe host the event applies to. Empty for origin: "operator" events that aren't host-specific (e.g. a RunStarted that fans out to multiple hosts).
eventstringDiscriminator — picks the variant below.

Envelope events

RunStarted

fieldtypenotes
commandstringup, rollback, prune, secrets rotate.
servicesarray<string>Selected service names; empty when the run targets the full config.

RunFinished

fieldtypenotes
commandstringSame as RunStarted.command.
okbooltrue on clean reconcile; false if any host or service failed.
errorstring | nullFirst operator-facing error string when ok=false.

LockAcquired, LockReleased

No additional fields. The gap between paired events is the deploy-lock hold time on that host.

Per-service / per-container events

HookStarted, HookFinished

fieldtype
namestring

HookFinished is forensic — it lands per-event so a triage tail of the audit log shows hooks even on aborted runs.

PullStarted, PullFinished

fieldtype
imagestring
tagstring

NetworkReady

fieldtypenotes
networkstringDocker network name.
createdbooltrue if yoink created it on this run; false if it already existed.

ContainerStarted

fieldtype
servicestring
containerstring
spec_hashstring
tagstring

Progress event — fired when the new replica's container is created and started, before the healthcheck. The forensic counterpart is ContainerCreated.

HealthcheckHealthy

fieldtypenotes
servicestring
containerstring
attemptsintPolls before passing.

ContainerCreated

Forensic event: the new replica passed its healthcheck and was promoted into routing. This is the "we did the deploy" event.

fieldtype
servicestring
containerstring
spec_hashstring
tagstring

AlreadyAtSpec

fieldtype
servicestring
containerstring
spec_hashstring

Fired when every replica was already at the desired spec — no work done.

OldContainerStopped, ContainerRemoved

fieldtype
servicestring
containerstring

OldContainerStopped is progress (best-effort flush). ContainerRemoved is forensic.

DeployFailed

Forensic. Fired when the new replica never passed its healthcheck and yoink rolled back.

fieldtypenotes
servicestring
containerstring
log_tailarray<string>The last few stdout/stderr lines from the failed container, captured before yoink removed it.

RollbackStarted, RollbackFinished

fieldtypenotes
servicestring
target_tag (Started)stringThe tag yoink is restoring to.
ok (Finished)bool
error (Finished)string | null

ContainerPruned

Fired by yoink prune for every removed container.

fieldtypenotes
servicestring | nullnull when the container had no yoink.service label.
containerstring

SecretsRotated

fieldtypenotes
new_recipientstringThe new age1… public key. The old recipient is in the prior secrets: block — diff git history to see it.

FileUploaded

fieldtypenotes
servicestringService that owns the mount.
sha256stringContent hash — same as the path under /var/lib/yoink/files/.
remote_pathstringAbsolute path on the host.

WebhookFired

Forensic. One per outbound webhook attempt, success or failure. Always lands origin: "operator" — webhooks fire from the operator's machine.

fieldtypenotes
namestringThe webhook's name: from yoink.yaml.
okbooltrue only on a 2xx response.
statusint | nullHTTP status code when the response was received; null when the call never reached a status (DNS / TCP / TLS / timeout / template error).
errorstring | nullFailure reason: transport: …, non-2xx: <code>, timed out after <duration>, template parse: …, template render: …, or a missing-secret message. null when ok=true.

Forensic vs. progress

The flush policy is per-variant. Forensic events bypass the per-host buffer and SSH-flush immediately, so a kill -9 mid-deploy still lands them on disk. Progress events buffer and flush at end of run.

ForensicProgress
RunStarted, RunFinishedHookStarted
LockAcquired, LockReleasedPullStarted, PullFinished
HookFinishedNetworkReady
ContainerCreated, ContainerRemovedContainerStarted
DeployFailedHealthcheckHealthy
RollbackStarted, RollbackFinishedOldContainerStopped
ContainerPrunedAlreadyAtSpec
SecretsRotated
FileUploaded
WebhookFired

Storage

Two files; same line shape, different paths:

originpathwho writes
operator$XDG_STATE_HOME/yoink/audit/events.jsonl (defaults to ~/.local/state/yoink/audit/)the operator's yoink process — local file write
host/var/lib/yoink/audit/events.jsonl on each managed hostoperator over SSH (tee -a); permissions 0640, owned by the SSH deploy user
  • Rotation: each active file rotates at 5 MiB into events-<UTC-timestamp>.jsonl; a fresh active file starts.
  • Retention: yoink does not enforce one. Run yoink audit gc --keep <DURATION> from cron to prune (host-side only currently; operator-side rotated files accumulate until you delete them manually).

See also

On this page