What is Synkro?A package manager for agents, with Rules for using your software.Getting startedQuickstartLet your agent set up Synkro, create your first Rule, and verify an action.Getting startedSetup checklistCheck your account, installation, repository, and first agent decision.SetupInstall and verifyInstall the CLI, sign in, and connect your agent.SetupSet up your agentConnect your agent and verify its first tool call.SetupVerify a decisionFind the recorded decision for an agent action.SetupYour first decisionRead your first agent decision and test a Rule.SetupHow Synkro worksUnderstand how Synkro applies Rules and records agent decisions.Core conceptsRules and ControlsChoose repository Rules for actions and Controls for access restrictions.Core conceptsRule outcomesUnderstand when an action continues, needs approval, or must be changed.Core conceptsRulesAdd, test, update, and remove the Rules used by your repository.GuidesEventsFind recorded agent actions and decisions with the Synkro CLI.GuidesApprove MCP toolsChoose project approvals and package defaults for MCP tools.GuidesConsentReview and approve an agent action before it runs.GuidesFeedbackReport a Synkro bug or suggest an improvement with diagnostic context.GuidesBilling and usageAdd funds and check your organization's balance and usage.GuidesGitHubConnect GitHub to discover Rules from private repositories.IntegrationsCLI commandsFind the current commands for setup, Rules, events, account, and recovery.ReferenceSupported agentsFind the installed Synkro files and the checks that apply to each agent.ReferenceTroubleshootingFix setup, sign-in, missing decisions, Rule, and approval problems.Reference
Documentation
Guides

Events

Read prompts, tool inputs, results, Rule checks and decisions with the Synkro CLI.

Use synkro events to inspect what someone asked their agent to do, what the agent tried, which Rules matched, and what happened next.

Run it from your signed-in CLI to see events across your organization. An approved, human-claimed agent can use the same command to read its own installation's hooks, requests, decisions, evaluations, Rule matches and errors. It cannot read another installation by supplying its event or trace ID. For setup through synkro onboard, use synkro onboard verify to check the first Rule and action. See the Quickstart.

Start with a decision

synkro events --type verdict --limit 1 --json

--json returns complete records. Use jq, a JSON command-line tool, to pick the fields you want:

synkro events --type verdict --limit 1 --json | jq '.events[] | {
  id: .envelope.id,
  recorded_at: .envelope.recorded_at,
  correlation_id: .envelope.correlation_id,
  action: .envelope.payload.action,
  reason: .envelope.payload.reason,
  decision_latency_ms: .envelope.payload.decision_latency_ms,
  evaluation_status: .envelope.payload.evaluation_status,
  agent_event_id: .envelope.payload.agent_event_id,
  evaluation_event_id: .envelope.payload.evaluation_event_id
}'

Example output:

{
  "id": "019fe000-0000-7000-8000-000000000005",
  "recorded_at": "2026-10-07T18:30:00Z",
  "correlation_id": "019fe000-0000-7000-8000-000000000001",
  "action": "block",
  "reason": "Matched semantic rules: project/protect-reports",
  "decision_latency_ms": 866,
  "evaluation_status": "violation",
  "agent_event_id": "019fe000-0000-7000-8000-000000000003",
  "evaluation_event_id": "019fe000-0000-7000-8000-000000000004"
}

The action was blocked by project/protect-reports. The IDs lead to the attempted action and its semantic check.

Common commands

synkro events --limit 10
synkro events --type verdict --limit 5 --details
synkro events --type consent --limit 10 --json
synkro events --list-types

--details prints each complete event. --json returns a page containing events, next_cursor, as_of and the applied filters. Each event has:

  • envelope: its ID, type, timestamps, source, related IDs and original payload.
  • typed_payload: named fields for that event type, such as the tool name, session, verdict or Rule match. A status of present means those fields are available.

You do not need --details with --json to get the full data.

Event typeWhat you can inspect
harness.hook_receivedThe original agent hook, including prompts, tool arguments, edits or responses supplied in that hook.
agent.tool_requestedTool name, session, working directory, model, file paths, connected tool and action summary.
agent.tool_returnedTool result, outcome and the ID of the corresponding request.
evaluation.createdSemantic-check input, Rules considered, matches, status and timing.
verdict.createdFinal action, reason, correction guidance, check status and the policy version used.
rule.matchedMatched Rule ID, content digest, outcome, severity and any file or edit location.
consent.*Approval requests, grants, uses, cancellations and expiry.
error.occurredRecorded failures related to an action.

--tz changes how text timestamps are displayed and how offset-free filters are read. It does not rewrite stored timestamps. JSON and the JSON payload printed by --details retain their recorded timestamp values.

Follow an action from input to decision

Copy correlation_id from a verdict to read the records for that check:

synkro events --correlation REPLACE_WITH_CORRELATION_UUID --json

For a specific record, use --id. To find records caused by it, use --causation:

synkro events --id REPLACE_WITH_EVENT_UUID --details
synkro events --causation REPLACE_WITH_EVENT_UUID --details

Follow these fields to move between records:

Starting recordFieldLeads to
Verdictpayload.agent_event_idThe attempted tool action.
Tool requestcausation_idThe original hook with exact tool arguments.
Verdictpayload.evaluation_event_idThe semantic check, when one was recorded.
Verdict ID--causationRule matches and approval requests caused by that verdict.
Tool returnpayload.requested_event_idThe request that produced the result.

These paths are inside envelope. A prompt or tool return can have a different correlation ID from the action's check. Use the session and request links below to find those records.

Read the exact tool input

Read the verdict's agent_event_id, then copy that tool request's envelope.causation_id. This is the hook ID:

synkro events --id REPLACE_WITH_HOOK_UUID --json |
  jq '.events[].envelope.payload'

Example output for a Codex command:

{
  "cwd": "/work/acme",
  "model": "gpt-5",
  "turn_id": "turn-1",
  "tool_name": "Bash",
  "session_id": "report-cleanup",
  "tool_input": {
    "command": "rm reports/quarterly-report.csv"
  },
  "tool_use_id": "call-1",
  "hook_event_name": "PreToolUse",
  "permission_mode": "default",
  "transcript_path": null
}

For an edit, inspect the supplied path and patch or replacement text. For a connected tool, inspect its supplied arguments. The raw payload keeps the agent's field names; tool_call_summary is a summary, not a replacement for this input.

Read the user's prompts

Prompt text is in the original UserPromptSubmit hook. This shows prompt hooks from the latest page of received hooks:

synkro events --type harness.hook_received --limit 50 --json | jq '
  .events[]
  | select(.typed_payload.fields.hook_event == "UserPromptSubmit")
  | {
      id: .envelope.id,
      session: .typed_payload.fields.provider_session_id,
      prompt: .envelope.payload.prompt
    }'

Example output:

{
  "id": "019fe000-0000-7000-8000-000000000000",
  "session": "report-cleanup",
  "prompt": "Clean up temporary report files. Keep quarterly-report.csv."
}

To read all received hooks for one agent session on a page, copy provider_session_id and harness from its hook's typed_payload.fields:

synkro events --type harness.hook_received --limit 50 --json |
  jq --arg session 'REPLACE_WITH_PROVIDER_SESSION_ID' --arg harness 'codex' '
    .events[]
    | select(.typed_payload.fields.provider_session_id == $session
        and .typed_payload.fields.harness == $harness)
    | {recorded_at: .envelope.recorded_at, hook: .envelope.payload}'

Use your agent's harness value. The results contain the prompts and tool calls it supplied through hooks.

Inspect a semantic check

Copy evaluation_event_id from the verdict:

synkro events --id REPLACE_WITH_EVALUATION_UUID --details

The record includes candidate_rule_ids, violated_rule_ids, status, error_code, latency_ms, timeout_ms and response_reason.

Its request field is JSON stored as a string. Decode it to see the action evidence, session context, recent prompts and Rule text and examples used for that check:

synkro events --id REPLACE_WITH_EVALUATION_UUID --json |
  jq '.events[].typed_payload.fields.request | fromjson'

To focus on the prompts, tool evidence and Rules:

synkro events --id REPLACE_WITH_EVALUATION_UUID --json | jq '
  .events[].typed_payload.fields.request | fromjson
  | {recent_prompts, evidence, rules, omitted_rules, truncated_fields}'

Each entry in rules contains its ID, title, natural-language description and the examples included in the check. recent_prompts shows the prompts actually included. omitted_rules and truncated_fields report omissions or shortening in that request.

Compare those inputs with the recorded result:

synkro events --id REPLACE_WITH_EVALUATION_UUID --json | jq '
  .events[].typed_payload.fields
  | {status, candidate_rule_ids, violated_rule_ids, response_reason,
     latency_ms, timeout_ms, error_code}'

response_reason is null when no explanation was recorded. This event exposes the semantic input and interpreted result, not the raw model-service HTTP response. The verdict records Synkro's final action.

Inspect matched Rules and approval

synkro events --correlation REPLACE_WITH_CORRELATION_UUID --type rule.matched --details
synkro events --correlation REPLACE_WITH_CORRELATION_UUID --type consent --details

Rule matches include rule_id, rule_digest, action, kind, severity and, when applicable, path, hunk_ordinal, content_coverage and match_count. The verdict's ruleset_digest identifies the policy version used for that decision.

To follow an approval beyond the original check, copy its consent_id and filter consent events by that ID:

synkro events --type consent --limit 50 --json |
  jq --arg consent 'REPLACE_WITH_CONSENT_UUID' '
    .events[] | select(.envelope.payload.consent_id == $consent)'

Read the tool's result

Copy the request ID from the verdict's agent_event_id:

synkro events --type agent.tool_returned --limit 50 --json |
  jq --arg request 'REPLACE_WITH_AGENT_EVENT_UUID' '
    .events[] | select(.envelope.payload.requested_event_id == $request)
    | .envelope.payload'

outcome records the return status; tool_result contains the interpreted result. For the original response, use the return's envelope.correlation_id to find its hook:

synkro events --correlation REPLACE_WITH_RETURN_CORRELATION_UUID --type harness.hook_received --json |
  jq '.events[].envelope.payload'

Use the tool return to check execution status. If no return was recorded, the execution status is unknown.

Filter by time and type

synkro events --type verdict --from 2026-09-22 --to 2026-09-22 --tz UTC
synkro events --type '*.created' --exclude billing --limit 20
synkro events --from 2026-09-24T00:58:00 --tz America/Chicago --details

Change the dates for your test. A date-only --to includes that whole day. A time-specific --to excludes that exact ending time.

A timestamp without an offset uses --tz, or your local timezone by default. Use an explicit offset, such as 2026-09-24T00:58:00-05:00, when the local time is ambiguous around a daylight saving change.

The default is the latest 50 records in local time. --time-field occurred filters by event time; results still sort by recorded time, newest first.

The jq examples filter one returned page, not your entire history. Check the unfiltered page's next_cursor if the record you want is older:

synkro events --type harness.hook_received --limit 50 --json
synkro events --cursor REPLACE_WITH_NEXT_CURSOR --json

Repeat with each returned cursor until next_cursor is null. Do not combine --cursor with new filters. Apply the same jq expression to each page as needed.

Read the check status

A verdict.created record contains the decision. Its reason and check status distinguish a completed Rule check from paused enforcement or an error.

If a hook is rejected before evaluation, look for error.occurred and the failed cli.hook_transport stage. The raw hook remains available; this rejected check has no verdict or Rule match. Use the trace ID in the warning with synkro trace REPLACE_WITH_TRACE_ID.

A fix Rule records fix in rule.matched and block in verdict.created. The Rule supplies correction guidance; the verdict records that the original action was refused. Read both records when distinguishing fix from block.

For setup, see Verify a decision. For all filters, run synkro events --help.