handoff-relay 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,70 @@
1
+ # Launch Copy
2
+
3
+ ## Short X Post
4
+
5
+ Public beta: Handoff, human-approved context handoffs between coding agents.
6
+
7
+ Package selected agent-session context, review before send, review before hydration, keep claims separate from evidence, and get audit receipts for every step.
8
+
9
+ Not shared memory. Not agent Slack. Just safer teammate handoffs.
10
+
11
+ ## Preflight Before Posting
12
+
13
+ - Push the release branch to the public GitHub repo.
14
+ - Publish `handoff-relay` to npm.
15
+ - Verify `npx -y handoff-relay doctor --json` runs from a clean temp directory.
16
+ - Record the short demo from `docs/demo-video-script.md` after the npm package is live.
17
+
18
+ ## GitHub Release Announcement
19
+
20
+ Handoff is a local-first public beta for human-approved context handoffs between coding agents.
21
+
22
+ The first release focuses on one workflow: a developer can package selected session context into a reviewable packet so another teammate's coding agent can continue without reconstructing the investigation.
23
+
24
+ What is included:
25
+
26
+ - Structured ask, share, reply, and clarification packets.
27
+ - Sender approval before send.
28
+ - Recipient review before hydration.
29
+ - Reply approval before return.
30
+ - Sender-controlled reply hydration.
31
+ - Claims and evidence as separate fields.
32
+ - Redaction that blocks secret-looking content by default.
33
+ - Explicit state machine with invalid transition rejection.
34
+ - SQLite coordination storage.
35
+ - Fastify coordination API.
36
+ - MCP server for Claude Code, Codex, and generic MCP clients.
37
+ - Profile-backed setup with `start`, `invite`, `join`, and `doctor`.
38
+ - CLI support for setup, admin flows, approval tokens, debugging, watch, and demos. Normal handoffs happen through MCP tools inside the coding agent.
39
+ - Audit and hydration receipts.
40
+ - Local polling watcher with terminal output, best-effort desktop notifications, and generic webhook posts.
41
+ - Docs, examples, and a five-minute two-user demo.
42
+
43
+ What this is not:
44
+
45
+ - Not passive agent memory.
46
+ - Not Slack for agents.
47
+ - Not autonomous agent-to-agent chat.
48
+ - Not a hosted SaaS dependency.
49
+
50
+ Try it:
51
+
52
+ ```bash
53
+ # Sam hosts a reachable workspace
54
+ npx -y handoff-relay start --lan
55
+ npx -y handoff-relay invite alice
56
+
57
+ # Alice joins from her machine
58
+ npx -y handoff-relay join http://<host>:3737/invite/<invite-token>
59
+ npx -y handoff-relay doctor
60
+
61
+ # Then wire Handoff into Codex, Claude Code, Cursor, or another MCP client.
62
+ ```
63
+
64
+ ## Comparison
65
+
66
+ Compared with raw Slack or paste workflows, Relay keeps handoffs structured, reviewed, evidence-backed, and auditable.
67
+
68
+ Compared with passive memory tools, Relay does not watch every session or ingest everything by default. A human chooses what crosses the boundary.
69
+
70
+ Compared with autonomous agent-to-agent systems, Relay keeps both humans in the loop: sender approves send, recipient approves hydration, recipient approves replies, sender approves reply hydration.
@@ -0,0 +1,170 @@
1
+ # Local Self-Hosting
2
+
3
+ Handoff is local-first, but team handoff needs a server Alice's machine can reach. For teammates on the same Wi-Fi, Sam can host directly from his machine:
4
+
5
+ ```bash
6
+ npx -y handoff-relay start --lan
7
+ npx -y handoff-relay invite alice
8
+ npx -y handoff-relay doctor
9
+ ```
10
+
11
+ Alice runs the printed join command on her own machine:
12
+
13
+ ```bash
14
+ npx -y handoff-relay join http://<sam-lan-ip>:3737/invite/<invite-token>
15
+ npx -y handoff-relay doctor
16
+ ```
17
+
18
+ Plain `start` is for local demos, CI smoke tests, or two profiles on one machine. It resets the active profile to loopback-only invite links. Re-run `start --lan` or pass `--public-url` before creating new invites that another machine should join.
19
+
20
+ For a dedicated trusted host, run one coordination server and have teammates join an invite from that server.
21
+
22
+ ## Coordination Server
23
+
24
+ ```bash
25
+ npx -y handoff-relay server start \
26
+ --db /srv/handoff/relay.db \
27
+ --host 10.0.0.10 \
28
+ --port 3737
29
+ ```
30
+
31
+ Put the host behind your normal network controls. Handoff does not provide a hosted cloud service.
32
+
33
+ For local profile-managed servers started by `handoff start`, inspect or stop the recorded background process:
34
+
35
+ ```bash
36
+ npx -y handoff-relay server status
37
+ npx -y handoff-relay server stop
38
+ ```
39
+
40
+ ## Profiles For Teammates
41
+
42
+ Create a workspace and invite members with the advanced commands, or run `start --lan` on the host machine and use the printed invite command.
43
+
44
+ After a teammate runs:
45
+
46
+ ```bash
47
+ npx -y handoff-relay join http://10.0.0.10:3737/invite/<invite-token>
48
+ ```
49
+
50
+ their local profile stores the server URL, member token, workspace ID, and approval secret. They can install one supported local MCP config while joining:
51
+
52
+ ```bash
53
+ npx -y handoff-relay join http://10.0.0.10:3737/invite/<invite-token> --install-mcp codex
54
+ # or
55
+ npx -y handoff-relay join http://10.0.0.10:3737/invite/<invite-token> --install-mcp cursor
56
+ ```
57
+
58
+ Their MCP command stays profile-backed:
59
+
60
+ ```bash
61
+ npx -y handoff-relay server mcp --profile default
62
+ ```
63
+
64
+ ## Explicit Server-Backed Commands
65
+
66
+ Low-level server-backed commands remain available for automation:
67
+
68
+ ```bash
69
+ npx -y handoff-relay inbox \
70
+ --server-url http://10.0.0.10:3737 \
71
+ --token <token> \
72
+ --workspace <workspace-id>
73
+ ```
74
+
75
+ Configure project/repo aliases once per workspace so clone names and local repo aliases resolve to the same packet history:
76
+
77
+ ```bash
78
+ npx -y handoff-relay workspace alias set \
79
+ --server-url http://10.0.0.10:3737 \
80
+ --token <admin-token> \
81
+ --workspace <workspace-id> \
82
+ --canonical handoff \
83
+ --alias relay-local \
84
+ --json
85
+
86
+ npx -y handoff-relay workspace alias list \
87
+ --server-url http://10.0.0.10:3737 \
88
+ --token <token> \
89
+ --workspace <workspace-id> \
90
+ --json
91
+ ```
92
+
93
+ ## Approval Tokens
94
+
95
+ Strict profile-backed approval tokens use the local profile:
96
+
97
+ ```bash
98
+ npx -y handoff-relay approval-token <packet-id> --action send
99
+ npx -y handoff-relay approval-token <packet-id> --action hydrate
100
+ ```
101
+
102
+ Profile-backed MCP can opt into agent-confirmed approvals:
103
+
104
+ ```bash
105
+ npx -y handoff-relay server mcp --profile default --agent-approvals
106
+ ```
107
+
108
+ In that mode, the MCP process requests and consumes the same short-lived approval tokens through the configured Handoff backend after the agent shows the packet and you explicitly tell it to send, approve, or hydrate. Local database profiles keep that request local; remote/self-hosted profiles send the approval secret to the configured Handoff server API.
109
+
110
+ Explicit approval-token mode remains available:
111
+
112
+ ```bash
113
+ npx -y handoff-relay approval-token <packet-id> \
114
+ --server-url http://10.0.0.10:3737 \
115
+ --token <token> \
116
+ --approval-secret <approval-secret> \
117
+ --action send
118
+ ```
119
+
120
+ Approval secrets stay outside MCP config. `HANDOFF_APPROVAL_SECRET` and the older `AGENT_RELAY_APPROVAL_SECRET` alias are supported for the terminal running approval commands.
121
+
122
+ ## SQLite Operations
123
+
124
+ - The coordination server database path is controlled with `--db`, `HANDOFF_DB`, or `AGENT_RELAY_DB`.
125
+ - Back up the main `.db` file plus WAL/SHM files when WAL mode is active.
126
+ - Treat the database as sensitive: packet bodies and token hashes live there.
127
+ - Do not put `.relay/*.db` in git.
128
+
129
+ ## Watch Mode
130
+
131
+ Terminal polling watcher:
132
+
133
+ ```bash
134
+ npx -y handoff-relay watch \
135
+ --server-url http://10.0.0.10:3737 \
136
+ --token <token> \
137
+ --workspace <workspace-id> \
138
+ --interval 5000
139
+ ```
140
+
141
+ Add best-effort native desktop notifications on the machine running the watcher:
142
+
143
+ ```bash
144
+ npx -y handoff-relay watch \
145
+ --server-url http://10.0.0.10:3737 \
146
+ --token <token> \
147
+ --workspace <workspace-id> \
148
+ --desktop-notifications
149
+ ```
150
+
151
+ Post concise notification summaries to a generic webhook endpoint:
152
+
153
+ ```bash
154
+ npx -y handoff-relay watch \
155
+ --server-url http://10.0.0.10:3737 \
156
+ --token <token> \
157
+ --workspace <workspace-id> \
158
+ --webhook-url https://hooks.example.test/relay \
159
+ --webhook-header "Authorization: Bearer <token>"
160
+ ```
161
+
162
+ The watcher always uses polling. Terminal, desktop, and webhook notifications include sender handle, packet type, title, project, summary, and the open/review action, but never evidence bodies or raw transcripts. For scripts or tests, use `--once` to poll a single time and exit.
163
+
164
+ ## From A Local Checkout
165
+
166
+ ```bash
167
+ pnpm install
168
+ pnpm build
169
+ node dist/cli.js server start --db /srv/handoff/relay.db --host 10.0.0.10 --port 3737
170
+ ```
@@ -0,0 +1,116 @@
1
+ # Packet Schema
2
+
3
+ Relay packets are Zod-validated TypeScript objects. The source lives in `src/protocol/schema.ts`.
4
+
5
+ ## Packet Types
6
+
7
+ - `ask`: requires `question`.
8
+ - `share`: requires `finding`.
9
+ - `reply`: requires `answer`.
10
+ - `clarification`: requires `question` and references an original packet.
11
+
12
+ ## Required Contract Fields
13
+
14
+ - `packet_id`
15
+ - `packet_type`
16
+ - `workspace_id`
17
+ - `sender_member_id`
18
+ - `recipient_member_ids`
19
+ - `created_at`
20
+ - `updated_at`
21
+ - `expires_at` or `recheck_by`
22
+ - `status`
23
+ - `project`
24
+ - `source_client`
25
+ - `title`
26
+ - `summary`
27
+ - `claims`
28
+ - `evidence`
29
+ - `files_or_symbols`
30
+ - `commands_or_tests_run`
31
+ - `what_was_tried`
32
+ - `known_failures`
33
+ - `current_hypothesis`
34
+ - `confidence`
35
+ - `suggested_next_steps`
36
+ - `redaction_report`
37
+ - `hydration_policy`
38
+ - `audit_receipt`
39
+
40
+ ## Project Identity
41
+
42
+ Packet `project.repo_name` is the canonical workspace project name when a matching project/repo alias is configured. Configure aliases with `workspace alias set` or `relay_configure_project_alias`; history/search filters accept either the canonical project or a configured alias.
43
+
44
+ ```json
45
+ {
46
+ "repo_name": "handoff",
47
+ "git_remote_fingerprint": "sha256:...",
48
+ "branch": "main",
49
+ "commit_hash": "abc123"
50
+ }
51
+ ```
52
+
53
+ ## Claims
54
+
55
+ ```json
56
+ {
57
+ "claim_id": "clm_1",
58
+ "text": "The failure happens after refresh token rotation.",
59
+ "confidence": "medium",
60
+ "status": "observed",
61
+ "evidence_ids": ["ev_1"],
62
+ "needs_recheck": true
63
+ }
64
+ ```
65
+
66
+ ## Evidence
67
+
68
+ ```json
69
+ {
70
+ "evidence_id": "ev_1",
71
+ "kind": "test_failure",
72
+ "label": "vitest failure",
73
+ "source": "pnpm test auth-refresh",
74
+ "excerpt": "expected 200, received 401",
75
+ "hash": "sha256:...",
76
+ "captured_at": "2026-06-15T12:00:00.000Z",
77
+ "sensitivity": "normal"
78
+ }
79
+ ```
80
+
81
+ ## State Model
82
+
83
+ Supported statuses:
84
+
85
+ ```text
86
+ draft
87
+ pending_sender_approval
88
+ sent
89
+ delivered
90
+ viewed
91
+ accepted
92
+ clarification_requested
93
+ response_drafting
94
+ pending_recipient_approval
95
+ replied
96
+ hydrated
97
+ archived
98
+ declined
99
+ expired
100
+ superseded
101
+ closed_resolved
102
+ closed_unresolved
103
+ ```
104
+
105
+ Invalid transitions throw `INVALID_STATE_TRANSITION`.
106
+
107
+ Examples:
108
+
109
+ - `pending_sender_approval` drafts can be edited with `update-draft`/`relay_update_draft`; edits recalculate redaction and write an `edit` audit receipt.
110
+ - `pending_sender_approval -> sent` only by sender.
111
+ - `sent -> delivered` only by system.
112
+ - `delivered -> viewed -> accepted -> hydrated` only by recipient.
113
+ - `response_drafting -> pending_recipient_approval -> replied` only by recipient.
114
+ - `replied -> viewed -> hydrated` by the reply recipient.
115
+
116
+ See [example packets](../examples/packets/).
@@ -0,0 +1,90 @@
1
+ # Security And Privacy Model
2
+
3
+ Handoff is built around review gates, bounded packets, and local ownership.
4
+
5
+ ## What Crosses The Boundary
6
+
7
+ Packets carry selected fields:
8
+
9
+ - Summary, question/finding/answer.
10
+ - Claims with confidence, status, evidence ids, and recheck flags.
11
+ - Evidence with kind, source, excerpt, hash, capture time, and sensitivity.
12
+ - Project identity: repo name, remote fingerprint, branch, optional commit.
13
+ - Audit and redaction receipts.
14
+
15
+ Raw transcripts are not captured or shared by default.
16
+
17
+ ## Required Human Gates
18
+
19
+ - Sender reviews and approves ask/share packets before send.
20
+ - Recipient views and accepts ask/share packets before hydration.
21
+ - Recipient reviews and approves replies before return.
22
+ - Sender views replies and hydrates them explicitly.
23
+
24
+ The service rejects invalid state transitions, and send/reply/hydrate actions require a short-lived human approval token. Strict mode generates that token outside MCP through the local CLI confirmation prompt. Agent-confirmed mode is an opt-in profile-backed MCP mode where the MCP process can request the same short-lived token through the configured Handoff backend after the agent shows the packet and the user explicitly tells it to send, approve, or hydrate. Local database profiles keep that request local; remote profiles send the approval secret to the configured Handoff server API.
25
+
26
+ Approval-token minting requires both the member token and a separate per-member approval secret returned during setup/acceptance. A member token alone cannot mint approval tokens. Agent-confirmed mode does not cryptographically prove a fresh terminal phrase; it treats explicit instruction in the active local agent session as the approval event.
27
+
28
+ ## Redaction
29
+
30
+ The redaction engine blocks by default when it sees:
31
+
32
+ - API-key or token-looking values.
33
+ - Private key blocks.
34
+ - Credential-bearing URLs.
35
+ - `.env`-like secret values.
36
+ - Evidence marked `secret_detected` or `restricted`.
37
+
38
+ Redaction scans packet titles, summaries, questions/findings/answers, hypotheses, claims, evidence labels/sources/excerpts, files or symbols, commands/tests, tried steps, known failures, and suggested next steps before a packet can be approved.
39
+
40
+ It warns, but does not block by default, for:
41
+
42
+ - Local absolute paths.
43
+ - Oversized excerpts that should be compressed.
44
+
45
+ Hashes are preserved when evidence excerpts are truncated or omitted.
46
+
47
+ ## Authorization
48
+
49
+ Authorization is enforced in the service/storage layer:
50
+
51
+ - Members can send only inside their workspace.
52
+ - Members can read packets they sent or packets addressed to them.
53
+ - Admins can manage workspace membership and view audit metadata by default.
54
+ - Admin packet body access is off by default and must be enabled as a workspace setting.
55
+ - Audit receipts are available through CLI, API, and MCP. Workspace-wide audit listing is admin-only; packet-specific audit listing follows metadata visibility.
56
+ - Revoked members cannot authenticate and cannot receive future packets.
57
+ - Search and history filter before returning results. Admins without body access can search and filter metadata fields only; body/provenance text is not exposed as a search oracle.
58
+
59
+ ## Audit Receipts
60
+
61
+ Receipts are recorded for:
62
+
63
+ - `draft`
64
+ - `approve`
65
+ - `send`
66
+ - `deliver`
67
+ - `view`
68
+ - `accept`
69
+ - `edit`
70
+ - `hydrate`
71
+ - `reply`
72
+ - `decline`
73
+ - `archive`
74
+ - `close`
75
+ - `configure_project_alias`
76
+ - `revoke`
77
+ - `rotate_token`
78
+ - `rotate_approval_secret`
79
+ - `search`
80
+
81
+ Receipts avoid logging extra raw sensitive evidence beyond the approved packet body.
82
+
83
+ ## Operational Notes
84
+
85
+ - Treat `.relay/*.db` as sensitive. It contains packet bodies, member token hashes, audit metadata, and hydration receipts.
86
+ - Treat approval secrets like local signing material. Keep them out of MCP config, tool schemas, and committed files. Strict mode uses them through `approval-token`; agent-confirmed mode lets the local profile-backed MCP process load them without exposing them to the agent as arguments.
87
+ - Rotate approval secrets with `member rotate-approval-secret` if one appears in shell history, terminal logs, or copied demo output. Rotation requires the current approval secret, returns the replacement once, invalidates unconsumed approval tokens minted by that member, and records `rotate_approval_secret`.
88
+ - Back up the SQLite database like any local coordination data store.
89
+ - Prefer private network access or localhost-only binding for the Fastify coordination server.
90
+ - Rotate member tokens if a token is pasted into a prompt, shell history, ticket, or chat. Rotate both credentials if both the member token and approval secret are exposed.
@@ -0,0 +1,180 @@
1
+ # Troubleshooting
2
+
3
+ ## Start With Doctor
4
+
5
+ Run:
6
+
7
+ ```bash
8
+ npx -y handoff-relay doctor
9
+ npx -y handoff-relay doctor --json
10
+ ```
11
+
12
+ Doctor checks the Handoff home directory, active profile, credential file permissions, member token, approval secret, server reachability, workspace access, and the profile-backed MCP command.
13
+
14
+ If the profile is missing and you are hosting a workspace for teammates, run:
15
+
16
+ ```bash
17
+ npx -y handoff-relay start --lan
18
+ npx -y handoff-relay invite alice
19
+ ```
20
+
21
+ If you are joining someone else's workspace, ask them for the invite command and run:
22
+
23
+ ```bash
24
+ npx -y handoff-relay join <invite-link>
25
+ ```
26
+
27
+ Plain `start` is only the right recovery path for local demos, CI smoke tests, or two profiles on one machine.
28
+
29
+ If `doctor` reports `WARN` for `mcp_config`, add Handoff to your MCP client. For Codex or Cursor, Handoff can write the common global config while hosting or joining:
30
+
31
+ ```bash
32
+ npx -y handoff-relay start --lan --install-mcp codex
33
+ npx -y handoff-relay start --lan --install-mcp cursor
34
+ npx -y handoff-relay join <invite-link> --install-mcp codex
35
+ npx -y handoff-relay join <invite-link> --install-mcp cursor
36
+ ```
37
+
38
+ For Claude Code or another MCP client, add the printed profile-backed command:
39
+
40
+ ```bash
41
+ npx -y handoff-relay server mcp --profile default
42
+ ```
43
+
44
+ If a teammate cannot join from another machine, restart the host in LAN mode and send a fresh invite:
45
+
46
+ ```bash
47
+ npx -y handoff-relay start --lan
48
+ npx -y handoff-relay invite alice
49
+ ```
50
+
51
+ ## `better-sqlite3` Cannot Find Native Bindings
52
+
53
+ Run:
54
+
55
+ ```bash
56
+ pnpm rebuild better-sqlite3 esbuild
57
+ ```
58
+
59
+ This package includes `pnpm-workspace.yaml` with `onlyBuiltDependencies` for `better-sqlite3` and `esbuild`. If your pnpm policy still blocks builds, approve those packages for this checkout.
60
+
61
+ ## MCP Server Starts But Tools Do Not Appear
62
+
63
+ - Confirm `pnpm build` produced `dist/cli.js`.
64
+ - Run the command directly:
65
+
66
+ ```bash
67
+ npx -y handoff-relay server mcp --profile default
68
+ ```
69
+
70
+ - In Claude Code, check `/mcp` or start with `--mcp-config`.
71
+ - In Codex, confirm the trusted `config.toml` has the expected `mcp_servers.<id>.command` and `args`.
72
+ - Confirm the MCP args use `--profile default` unless you intentionally need `--explicit-auth`.
73
+
74
+ ## Redaction Blocks A Packet
75
+
76
+ Handoff blocks secret-looking content by default. Remove the evidence excerpt, replace it with a hash or summary, then create a new draft.
77
+
78
+ Common causes:
79
+
80
+ - `API_KEY=...`
81
+ - `TOKEN=...`
82
+ - Private key PEM blocks.
83
+ - `postgres://user:pass@host/db`
84
+ - Evidence marked `secret_detected` or `restricted`.
85
+
86
+ ## Recipient Cannot See A Packet
87
+
88
+ Check:
89
+
90
+ - The recipient handle is in the same workspace.
91
+ - The member is active, not revoked.
92
+ - The packet was approved and delivered.
93
+ - The token belongs to the intended workspace.
94
+
95
+ Use:
96
+
97
+ ```bash
98
+ npx -y handoff-relay member list --db .relay/team.db --token <admin-token> --workspace <workspace-id>
99
+ npx -y handoff-relay status <packet-id> --db .relay/team.db --token <sender-token>
100
+ ```
101
+
102
+ ## Hydration Or Approval Is Rejected
103
+
104
+ Strict mode requires explicit review and a human approval token:
105
+
106
+ - Ask/share packets: recipient must `view`, then `accept`, then generate an `approval-token --approval-secret <secret> --action hydrate`, then `hydrate`.
107
+ - Reply packets: sender must `view`, then generate an `approval-token --approval-secret <secret> --action hydrate`, then `hydrate`.
108
+
109
+ Invalid transitions return `INVALID_STATE_TRANSITION`.
110
+
111
+ Missing, expired, reused, or wrong-action approval tokens return `FORBIDDEN`.
112
+
113
+ If you intended to use agent-confirmed approvals, confirm your MCP command includes profile mode and `--agent-approvals`:
114
+
115
+ ```bash
116
+ npx -y handoff-relay server mcp --profile default --agent-approvals
117
+ ```
118
+
119
+ Agent-confirmed approvals are not available in explicit-auth MCP mode or when the local profile credentials are missing.
120
+
121
+ If `/packets/:packetId/approval-token` returns `FORBIDDEN` with an approval secret message, use the CLI `approval-token` command with the approval secret returned during setup/acceptance. Static local-renderer headers are ignored.
122
+
123
+ In profile-backed mode:
124
+
125
+ ```bash
126
+ npx -y handoff-relay approval-token <packet-id> --action send
127
+ ```
128
+
129
+ In explicit advanced mode:
130
+
131
+ ```bash
132
+ npx -y handoff-relay approval-token <packet-id> --db .relay/team.db --token <member-token> --approval-secret <approval-secret> --action send
133
+ ```
134
+
135
+ For audit/debugging:
136
+
137
+ ```bash
138
+ npx -y handoff-relay history --db .relay/team.db --token <member-token> --workspace <workspace-id> --filter open
139
+ npx -y handoff-relay audit --db .relay/team.db --token <admin-token> --workspace <workspace-id>
140
+ ```
141
+
142
+ If an approval secret leaks, rotate it and update your local secret manager:
143
+
144
+ ```bash
145
+ npx -y handoff-relay member rotate-approval-secret --db .relay/team.db --token <member-token> --approval-secret <current-approval-secret> --json
146
+ ```
147
+
148
+ The old approval secret stops working immediately, and unconsumed approval tokens already minted by that member are invalidated. If you no longer have the current approval secret, ask a workspace admin to revoke and reinvite the member.
149
+
150
+ ## Packet Needs More Evidence
151
+
152
+ Recipients can ask for clarification before hydration:
153
+
154
+ ```bash
155
+ npx -y handoff-relay clarify <packet-id> --db .relay/team.db --token <recipient-token> --question "Can you include the failing assertion?" --requested-evidence "test failure"
156
+ ```
157
+
158
+ ## Watcher Prints Nothing
159
+
160
+ The watcher only reports new packet ids once per process. Check `inbox` directly:
161
+
162
+ ```bash
163
+ npx -y handoff-relay inbox --db .relay/team.db --token <token> --workspace <workspace-id>
164
+ ```
165
+
166
+ ## Desktop Or Webhook Notifications Do Not Fire
167
+
168
+ Desktop notifications are best-effort from the local watcher process:
169
+
170
+ - macOS uses `osascript`.
171
+ - Linux uses `notify-send`; install your desktop notification package if it is missing.
172
+ - Windows uses a PowerShell tray notification.
173
+
174
+ Webhook notifications require a reachable endpoint that accepts JSON POSTs:
175
+
176
+ ```bash
177
+ npx -y handoff-relay watch --db .relay/team.db --token <token> --workspace <workspace-id> --webhook-url https://hooks.example.test/relay --once
178
+ ```
179
+
180
+ If the adapter fails, `watch` still prints the terminal notification and writes an adapter warning to stderr.
@@ -0,0 +1,14 @@
1
+ {
2
+ "receipt_id": "rcp_hydrate_example",
3
+ "action": "hydrate",
4
+ "actor_member_id": "mem_sam",
5
+ "packet_id": "pkt_example_reply",
6
+ "workspace_id": "wrk_example",
7
+ "created_at": "2026-06-15T12:25:00.000Z",
8
+ "metadata": {
9
+ "client": "codex",
10
+ "session_id": "sam-session",
11
+ "packet_type": "reply"
12
+ },
13
+ "receipt_hash": "sha256:example"
14
+ }