zynk 1.5.2

Portable protocol and helper CLI for multi-agent collaboration.
# 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

```text
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`, and
  `zynk doctor`. The send verbs compose the existing audited `send herdr` path, 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 --unanswered` is a best-effort heuristic.
- Shipped in v1.4.0+ (ADR 041, Herdr delivery verification): `send herdr` now
  VERIFIES receiver-side submission before recording `delivery_status=sent` — a
  `herdr` transport 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 status` protocol >= 12 with `compatible: yes`, and advertised
  `herdr pane run`; unsupported/incompatible Herdr fails before transport with no
  audit/corpus. It submits once through Herdr's atomic `pane run` input primitive,
  then 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 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 split `send-text`/`send-keys` submit 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.yaml` embedded into the `zynk` default profile.
- Dashboard examples: `examples/dashboard.md` plus session examples under `examples/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
  verbs `zynk reply`, `zynk send agent`, `zynk whoami`/`who`, `zynk inbox`,
  `zynk thread`, and `zynk doctor` are implemented in Rust.
- `zynk db serve` is 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](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.

```bash
cargo build
```

The install exposes one command:

```bash
./target/debug/zynk --help
```

Use `cargo install --path .` to install `zynk` into Cargo's bin directory.

## How To Use In Another Project

1. Copy or vendor `decisions/` as protocol reference.
2. Copy `skills/multi-agent-message-scaffolds/` into the target project's agent skills directory.
3. Copy `tools/message-profile.yaml` into the target project's `outputs/tools/` or equivalent tool config location.
4. For active sessions, create `outputs/sessions/<session_id>/status.md`, `summary.md`, and `audit.md` following ADR 022 and ADR 023.
5. 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 is `human`, 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:

```bash
cargo test
```

## 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`.