Portable Multi-Agent Collaboration Protocol
Portable protocol package for collaboration between multiple coding agents and an operator.
The protocol was designed during the herdr-trial evaluation, but the decisions are transport-aware rather than herdr-only. Herdr is the first concrete transport profile.
Repository Contents
decisions/ Accepted ADRs for provenance, identity, message structure, workflow modes, operator interface, and audit trail.
skills/ Reusable agent skills derived from the protocol.
tools/ Config and helper scripts.
examples/ File-based dashboard/status/summary/audit examples + workflow-profile reference artifacts (examples/workflow-profiles/).
Current Status
- Protocol decisions: accepted through ADR 041, including ADR 036 actor/role/trait overlays, ADR 037 workflow profiles, ADR 038 multiline Herdr delivery, and ADR 039 Herdr runtime orchestration shipped in v1.3.0.
- Shipped in v1.4.0 (ADR 040, agent-ergonomics): short verbs
zynk reply <mid>,zynk send agent <name>,zynk whoami/who,zynk inbox,zynk thread, andzynk doctor. The send verbs compose the existing auditedsend herdrpath, so their persisted record is byte-identical to the longhand (ADR 040 D1) and they re-resolve both source and target panes against live Herdr (failing loud on an ambiguous/stale pane, ADR 040 D2); the read helpers write no.zynk//outputs/state (ADR 040 D5).inbox --unansweredis a best-effort heuristic. - Shipped in v1.4.0+ (ADR 041, Herdr delivery verification):
send herdrnow VERIFIES receiver-side submission before recordingdelivery_status=sent— aherdrtransport exit 0 alone is not proof. The v1.5.2 candidate path keeps verification TUI-independent (no input-box scraping) and requires Herdr >= 0.6.8,herdr statusprotocol >= 12 withcompatible: yes, and advertisedherdr pane run; unsupported/incompatible Herdr fails before transport with no audit/corpus. It submits once through Herdr's atomicpane runinput primitive, then recordssentonly when a new rendered[herdr ...]header marker appears beyond a pre-send baseline in Herdr receiver read surfaces (recent-unwrappedandvisible, marker-count only; no input-box classification; immediate post-submit visible echo/draft is excluded). zynk polls patiently (ZYNK_VERIFY_TIMEOUT_MS, default 30000) and does not automatically re-submit/retry because marker absence cannot distinguish loss from receiver lag. Anything unverifiable exits nonzero with no audit/corpus (D4). D3c retired the earlier input-box scraping machinery (D3/D3a/D3b); D3f replaces splitsend-text/send-keyssubmit with atomic submit; D8 (native input-state) remains the durable fix. This strengthens ADR 024. - Skill artifact:
skills/multi-agent-message-scaffolds/SKILL.md. - Tooling profile:
tools/message-profile.yamlembedded into thezynkdefault profile. - Dashboard examples:
examples/dashboard.mdplus session examples underexamples/sessions/. - Executable helpers:
zynk list,zynk compose,zynk send herdr,zynk status,zynk audit,zynk dashboard,zynk report,zynk decide,zynk reveal,zynk assign,zynk herdr ...,zynk db ..., and the v1.4.0 agent-ergonomics verbszynk reply,zynk send agent,zynk whoami/who,zynk inbox,zynk thread, andzynk doctorare implemented in Rust. zynk db serveis the live DB-backed dashboard console. Browser writes are off by default and become available only with--allow-writes.- Historical Python reference: available from git tag
python-v0.1-final.
Quickstart
Start with QUICKSTART.md. It walks through the helper flow: compose a message, dry-run/send via herdr, update rolling status, append or auto-write audit records, record work telemetry, render dashboards, and run tests.
Install
Requires Rust 1.89+ and Cargo.
The install exposes one command:
Use cargo install --path . to install zynk into Cargo's bin directory.
How To Use In Another Project
- Copy or vendor
decisions/as protocol reference. - Copy
skills/multi-agent-message-scaffolds/into the target project's agent skills directory. - Copy
tools/message-profile.yamlinto the target project'soutputs/tools/or equivalent tool config location. - For active sessions, create
outputs/sessions/<session_id>/status.md,summary.md, andaudit.mdfollowing ADR 022 and ADR 023. - Use
examples/as sample output, not as canonical state.
Implemented Tooling
Implemented helpers:
zynk compose reads the embedded message profile and generates:
- human prefix,
- structured header,
- required type-specific fields,
- short body templates.
zynk send herdr wraps message composition and sends the composed message
through Herdr. Body newlines are preserved for multiline messages (ADR 038). As of
v1.4.0+ (ADR 041), it VERIFIES receiver-side submission before recording
delivery_status=sent — a transport exit 0 alone is not proof. The v1.5.2
candidate submit/verify path is TUI-independent (no input-box scraping): zynk
first preflights Herdr >= 0.6.8, herdr status protocol >= 12 with
compatible: yes, and the herdr pane run capability, then submits the message
once with Herdr's atomic pane run. It records sent only when a new
rendered [herdr ...] header marker appears beyond a pre-send baseline in Herdr
receiver read surfaces (recent-unwrapped and visible, marker-count only; no
input-box classification; immediate post-submit visible echo/draft is excluded).
zynk submits once and waits for the marker; it does not automatically
re-submit/retry. Anything unverifiable exits nonzero with no audit/corpus and prints
a recovery hint for stuck input. Use
--dry-run to print without sending. As of v0.5 (ADR 029), passing
--session-id audits the send by default: on a verified transport send zynk
writes the sender audit (delivery_status=sent, verified_by=helper-tool) and
persists the message into the corpus automatically — no separate zynk audit.
--no-audit opts out; --no-db keeps the audit file-only.
The marker-only verify loop is tuned by environment variables (all optional):
ZYNK_VERIFY_TIMEOUT_MS (marker-wait budget, default 30000) and
ZYNK_VERIFY_POLL_MS (marker poll interval, default 200). The old
ZYNK_VERIFY_SETTLE_MS split-submit knob is retired; setting it has no effect in
the atomic-submit path.
No known fixable residuals remain in this path. Accepted-design residuals are
fail-closed and operationally visible: if Herdr passes preflight but pane run or
marker proof still fails, zynk writes no sent audit/corpus and the operator must
inspect the target pane before retrying. zynk intentionally does not auto-clear
input or auto-retry because that can delete user drafts or duplicate delivered
messages; if manual inspection proves delivery, reconcile with an operator/helper
verified audit instead of blindly re-sending.
zynk reply <mid> and zynk send agent <name> (ADR 040, shipped in v1.4.0) are
agent-ergonomics shortcuts that COMPOSE the audited send herdr path: the
persisted audit + corpus record is byte-identical to the longhand (D1), and both
the source (HERDR_PANE_ID) and target panes re-resolve against live Herdr at
send time, aborting with no write on a 0/>1/agent-mismatch (D2). zynk whoami/who,
zynk inbox (incl. --unanswered, a labeled best-effort heuristic), zynk thread,
and zynk doctor are strictly read-only — they write no .zynk//outputs//DB
state (D5). send herdr stays the explicit longhand/escape hatch.
zynk status writes ADR 022 rolling status files at outputs/sessions/<session_id>/status.md.
zynk audit appends ADR 023 audit records with SHA-256 payload hashes and previous_audit_id chain links.
zynk report records typed work telemetry events for the v1 dashboard feed
(think, system, tool, plan, usage, diff, artifact, gate, and
conflict).
zynk decide records typed operator decisions (gate, conflict, mode,
interrupt, and redirect) with audited provenance.
zynk reveal reveals a retained payload only after writing an operator-verified
reveal proof. Use --retain-custody on audited writes when a redacted payload
must be revealable later.
zynk assign (ADR 036) records a participant overlay so the dashboard roster is
actor/role/trait aware in a 3+-agent workflow. Three orthogonal concepts ride
one audited write (record_type=participant-overlay, a non-transport operator
proof, never delivery_status=sent):
zynk assign actor-kind --subject <actor> --kind human|agent|external— the human operator ishuman, NOT an agent, and the roster renders it distinctly.zynk assign role --subject <actor> --role-id <slug> --role-label "<free>"— roles are FULLY free-form and profile-defined; the machine never reasons over the role name (it is for human display only).zynk assign trait --subject <actor> --trait <name> [--unset]— a small KNOWN integrity-trait vocabulary the machine DOES reason over:independent,can_edit_source,non_iterating,can_verify_gate,can_merge_approve.
The roster shows kind + role + trait badges, each carrying its asserter and
asserted-at provenance. The honesty bound is STRUCTURAL, not authenticated
identity: a trait is only honored when the proof-bound asserter is not the
subject (no self-grant) and the proof is operator-grade (verified_by=operator,
command_origin=operator, transport=none). zynk has no identity
authentication, so the badge cites provenance and never implies an
authenticated identity.
Workflow profiles (ADR 037) are a distribution-artifact layer — "out of core,
not out of zynk". A workflow profile expresses a reusable, gated-verification
multi-agent workflow (its roles, the role→integrity-trait mapping, and its gate
sequence) by composing the existing verbs; it requires no core change and is a
separate concept from the message/audit --profile. The repo ships a generic
template and a sanitized reference instance under examples/workflow-profiles/,
a deterministic reference script scripts/workflow-profile-smscode.sh, and the
zynk-workflow-profiles skill. Every overlay a profile enacts stays
operator-asserted; a profile declares roles freely but never invents a
machine-reasoned trait (the trait vocabulary stays core and closed).
zynk db serve serves the live DB-backed dashboard console. It is loopback by
default; browser writes require --allow-writes.
zynk dashboard renders a point-in-time snapshot at outputs/dashboard.md. It
uses .zynk/zynk.db when present and falls back to session status files.
zynk list and zynk herdr ... (ADR 039, shipped in v1.3.0) operate on Herdr
runtime state: workspaces, tabs, panes, agent names/statuses, and pane layout.
They do not write audit/corpus artifacts, outputs/, .zynk/, or DB state.
Delivery proof matters: text printed by zynk compose or zynk send herdr --dry-run is only a draft. Record delivery_status=sent only after a real transport send or operator relay, and use delivery_status=drafted for message-shaped text that remained in the sender pane.
The current implementation uses Rust. The previous Python helper set is preserved at git tag python-v0.1-final; it is intentionally absent from main.
Run tests with:
Transport Scope
The current profile targets herdr first because that is the observed transport. The protocol leaves room for tmux, chat, Slack, or other transports through stable agent_id, transport address fields, and transport_thread_id.