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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 0dust
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,434 @@
1
+ <div align="center">
2
+
3
+ # Handoff
4
+
5
+ <p><strong>Human-approved context handoffs between coding agents.</strong></p>
6
+
7
+ <p>Move selected investigation context from one teammate's agent to another teammate's agent without dumping raw transcripts into Slack.</p>
8
+
9
+ <p>
10
+ MCP server | team workspace | local profiles | explicit approvals | audit receipts
11
+ </p>
12
+
13
+ <p>
14
+ <img alt="Node 20 plus" src="https://img.shields.io/badge/node-20%2B-4b5563">
15
+ <img alt="MCP stdio" src="https://img.shields.io/badge/MCP-stdio-5f5a4f">
16
+ <img alt="Self hosted" src="https://img.shields.io/badge/self--hosted-SQLite-2f7d5b">
17
+ <img alt="License MIT" src="https://img.shields.io/badge/license-MIT-3f3a36">
18
+ </p>
19
+
20
+ <p>
21
+ <a href="#mental-model">Mental model</a> |
22
+ <a href="#team-setup">Team setup</a> |
23
+ <a href="#agent-setup">Agent setup</a> |
24
+ <a href="#using-handoff">Using Handoff</a> |
25
+ <a href="#security-model">Security model</a>
26
+ </p>
27
+ </div>
28
+
29
+ ---
30
+
31
+ Handoff is not a chat room and it is not a manual CLI handoff tool. The normal workflow happens inside Codex, Claude Code, Cursor, or another MCP-capable coding agent.
32
+
33
+ An agent drafts a structured Relay Packet from the current session. A human reviews and approves what leaves. The recipient's agent reads the packet, the recipient reviews it, and only then hydrates bounded context into their own session.
34
+
35
+ ```text
36
+ Alice's Codex session
37
+ -> selected investigation context
38
+ -> human-reviewed Relay Packet
39
+ -> Bob's Claude Code inbox
40
+ -> Bob reviews and approves hydration
41
+ -> Bob's agent continues with bounded context
42
+ ```
43
+
44
+ ## Mental Model
45
+
46
+ A team has one shared Handoff workspace and many local member profiles.
47
+
48
+ ```text
49
+ One reachable Handoff server/workspace
50
+ 15 teammates with local profiles
51
+ 15 coding agents connected through MCP
52
+ Many addressed handoff packets between members
53
+ ```
54
+
55
+ There are two roles:
56
+
57
+ | Role | Who does it | What they do |
58
+ | -------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
59
+ | Workspace host/admin | One person, a dev box, or a small internal server | Hosts the reachable Handoff server, creates the workspace, and invites members. |
60
+ | Member/user | Every teammate, including the host if they also use Handoff | Joins the workspace, configures their coding agent through MCP, sends and receives handoffs from inside the agent. |
61
+
62
+ The host can also be a normal member. Hosting is an extra responsibility, not a separate kind of user.
63
+
64
+ For a 15-person team, one host/admin sets up the workspace once. All 15 teammates, including the host if they want to use Handoff personally, need their own local profile and MCP setup.
65
+
66
+ ## Team Setup
67
+
68
+ ### 1. Host The Workspace
69
+
70
+ Pick the machine that will host Handoff. For a small team this can be a teammate's machine on the LAN. For a more reliable team setup, use a stable internal host or VPN-reachable machine.
71
+
72
+ On the host:
73
+
74
+ ```bash
75
+ npx -y handoff-relay start --lan
76
+ ```
77
+
78
+ This creates:
79
+
80
+ - the Handoff workspace
81
+ - the host/admin member
82
+ - the SQLite coordination database
83
+ - a reachable server URL for teammates on the network
84
+ - a local profile for the host
85
+
86
+ Check it:
87
+
88
+ ```bash
89
+ npx -y handoff-relay doctor
90
+ ```
91
+
92
+ If the host also wants to use Handoff from Codex or Cursor, install MCP during start:
93
+
94
+ ```bash
95
+ npx -y handoff-relay start --lan --install-mcp codex
96
+ # or
97
+ npx -y handoff-relay start --lan --install-mcp cursor
98
+ ```
99
+
100
+ Claude Code setup is shown in [Agent setup](#agent-setup).
101
+
102
+ ### 2. Invite Teammates
103
+
104
+ The host/admin creates one invite per teammate:
105
+
106
+ ```bash
107
+ npx -y handoff-relay invite alice
108
+ npx -y handoff-relay invite bob
109
+ npx -y handoff-relay invite priya
110
+ ```
111
+
112
+ Each invite prints a `join` command. Send each person their own command.
113
+
114
+ ### 3. Members Join
115
+
116
+ Each teammate runs their invite command on their own machine:
117
+
118
+ ```bash
119
+ npx -y handoff-relay join http://<handoff-host>:3737/invite/<invite-token>
120
+ ```
121
+
122
+ This creates the teammate's local profile and stores their member credentials. It does not replace MCP setup. The teammate still needs their coding agent connected to Handoff.
123
+
124
+ Members using Codex or Cursor can install MCP while joining:
125
+
126
+ ```bash
127
+ npx -y handoff-relay join <invite-link> --install-mcp codex
128
+ # or
129
+ npx -y handoff-relay join <invite-link> --install-mcp cursor
130
+ ```
131
+
132
+ After joining:
133
+
134
+ ```bash
135
+ npx -y handoff-relay doctor
136
+ ```
137
+
138
+ `doctor` may show `WARN mcp_config` when the profile and server work but the coding agent is not wired to Handoff yet. That warning means setup is not complete for real product use.
139
+
140
+ ## Agent Setup
141
+
142
+ Handoff is ready when the user's coding agent can see the Handoff MCP tools. The CLI creates profiles and handles approvals, but the handoff workflow itself belongs in the agent.
143
+
144
+ ### Codex
145
+
146
+ Install automatically when hosting or joining:
147
+
148
+ ```bash
149
+ # host/admin who also uses Codex
150
+ npx -y handoff-relay start --lan --install-mcp codex
151
+
152
+ # teammate joining with Codex
153
+ npx -y handoff-relay join <invite-link> --install-mcp codex
154
+ ```
155
+
156
+ The MCP entry looks like:
157
+
158
+ ```toml
159
+ [mcp_servers.handoff]
160
+ command = "npx"
161
+ args = ["-y", "handoff-relay", "server", "mcp", "--profile", "default"]
162
+ startup_timeout_sec = 10
163
+ tool_timeout_sec = 60
164
+ enabled = true
165
+ ```
166
+
167
+ More detail: [docs/codex-setup.md](docs/codex-setup.md).
168
+
169
+ ### Claude Code
170
+
171
+ Handoff prints the profile-backed MCP command after `start` or `join`:
172
+
173
+ ```bash
174
+ npx -y handoff-relay server mcp --profile default
175
+ ```
176
+
177
+ Add it to Claude Code:
178
+
179
+ ```bash
180
+ claude mcp add-json handoff \
181
+ '{"type":"stdio","command":"npx","args":["-y","handoff-relay","server","mcp","--profile","default"]}'
182
+ ```
183
+
184
+ Or use MCP JSON:
185
+
186
+ ```json
187
+ {
188
+ "mcpServers": {
189
+ "handoff": {
190
+ "command": "npx",
191
+ "args": ["-y", "handoff-relay", "server", "mcp", "--profile", "default"]
192
+ }
193
+ }
194
+ }
195
+ ```
196
+
197
+ More detail: [docs/claude-code-setup.md](docs/claude-code-setup.md).
198
+
199
+ ### Cursor
200
+
201
+ Install automatically when hosting or joining:
202
+
203
+ ```bash
204
+ # host/admin who also uses Cursor
205
+ npx -y handoff-relay start --lan --install-mcp cursor
206
+
207
+ # teammate joining with Cursor
208
+ npx -y handoff-relay join <invite-link> --install-mcp cursor
209
+ ```
210
+
211
+ More detail: [docs/generic-mcp-setup.md](docs/generic-mcp-setup.md).
212
+
213
+ ### Other MCP Clients
214
+
215
+ Any MCP client that can launch a stdio command can use:
216
+
217
+ ```bash
218
+ npx -y handoff-relay server mcp --profile default
219
+ ```
220
+
221
+ Profile mode reads the active local Handoff profile. Agents do not need member tokens, workspace IDs, database paths, server URLs, or approval secrets in prompts or MCP schemas.
222
+
223
+ ## Ask An Agent To Set It Up
224
+
225
+ Most users should give these instructions to their coding agent instead of wiring the files by hand.
226
+
227
+ If the npm package is live, the agent can use `npx -y handoff-relay`. If testing from a local checkout:
228
+
229
+ ```bash
230
+ cd /path/to/handoff
231
+ pnpm install
232
+ pnpm build
233
+ ```
234
+
235
+ Then use `node /path/to/handoff/dist/cli.js` anywhere the examples say `npx -y handoff-relay`.
236
+
237
+ ### Host/Admin Prompt
238
+
239
+ ```text
240
+ Set up Handoff as the host/admin for my team.
241
+
242
+ 1. Use `npx -y handoff-relay`, or build this local checkout and use `node /path/to/handoff/dist/cli.js`.
243
+ 2. Start a reachable team workspace with `start --lan`.
244
+ 3. If I use Codex, install MCP with `start --lan --install-mcp codex`.
245
+ If I use Cursor, install MCP with `start --lan --install-mcp cursor`.
246
+ If I use Claude Code, show me the `claude mcp add-json` command.
247
+ 4. Invite each teammate I name and give me their exact join commands.
248
+ 5. Run `doctor`.
249
+ 6. Confirm whether my coding agent can see the Handoff MCP tools. Do not call setup complete until MCP is wired.
250
+ ```
251
+
252
+ ### Member Prompt
253
+
254
+ ```text
255
+ Set up my machine as a Handoff team member.
256
+
257
+ 1. Use `npx -y handoff-relay`, or build this local checkout and use `node /path/to/handoff/dist/cli.js`.
258
+ 2. Run the join command my teammate sent me.
259
+ 3. If I use Codex, add `--install-mcp codex` to the join command.
260
+ If I use Cursor, add `--install-mcp cursor` to the join command.
261
+ If I use Claude Code, show me the `claude mcp add-json` command after join succeeds.
262
+ 4. Run `doctor`.
263
+ 5. Confirm whether my coding agent can see the Handoff MCP tools. Do not call setup complete until MCP is wired.
264
+ ```
265
+
266
+ ## Using Handoff
267
+
268
+ The human talks to their coding agent. The agent uses Handoff MCP tools.
269
+
270
+ Sender:
271
+
272
+ ```text
273
+ Use Handoff to package this investigation for @bob.
274
+ Include files touched, commands run, known failures, current hypothesis, evidence excerpts, and suggested next steps.
275
+ Show me the Relay Packet before sending.
276
+ ```
277
+
278
+ Recipient:
279
+
280
+ ```text
281
+ Use Handoff to check my inbox.
282
+ Show me the packet before hydration.
283
+ Wait for my approval before calling relay_hydrate.
284
+ ```
285
+
286
+ Handoff MCP tools include:
287
+
288
+ | Tool | Purpose |
289
+ | ------------------------------- | --------------------------------------------------------------------------------- |
290
+ | `relay_share` | Draft a handoff packet with selected context, findings, evidence, and next steps. |
291
+ | `relay_ask` | Draft a handoff packet that includes a question for the recipient. |
292
+ | `relay_update_draft` | Edit a draft before sender approval. |
293
+ | `relay_approve` | Send a packet or approve a reply after human review. |
294
+ | `relay_inbox` | List packets addressed to the current member. |
295
+ | `relay_status` | Fetch the latest readable packet status. |
296
+ | `relay_view` | Record that a packet was opened for review. |
297
+ | `relay_accept` | Accept a packet before hydration. |
298
+ | `relay_hydrate` | Return bounded context and record a hydration receipt. |
299
+ | `relay_reply` | Draft a reply packet. |
300
+ | `relay_clarify` | Request missing evidence or context. |
301
+ | `relay_decline` | Decline an addressed packet. |
302
+ | `relay_archive` | Archive a readable packet. |
303
+ | `relay_search` | Search permitted packet history without hydrating results. |
304
+ | `relay_history` | List drafts, sent packets, open work, or closed packets. |
305
+ | `relay_audit` | List packet or workspace audit receipts. |
306
+ | `relay_configure_project_alias` | Map a repo or clone alias to a canonical project. |
307
+ | `relay_project_aliases` | List configured project aliases. |
308
+
309
+ ## Approval Flow
310
+
311
+ Handoff supports two approval modes.
312
+
313
+ Strict mode is the default. Agents can draft and read handoff packets, but they cannot mint approval tokens.
314
+
315
+ When your agent asks for a send, hydrate, or reply approval token, generate it in a local terminal:
316
+
317
+ ```bash
318
+ npx -y handoff-relay approval-token <packet-id> --action send
319
+ npx -y handoff-relay approval-token <packet-id> --action hydrate
320
+ npx -y handoff-relay approval-token <reply-packet-id> --action reply
321
+ ```
322
+
323
+ Paste the short-lived approval token back into the agent instruction. This is a human approval gate, not the handoff mechanism itself.
324
+
325
+ Agent-confirmed mode is optional for profile-backed MCP sessions. Start MCP with `--agent-approvals`:
326
+
327
+ ```bash
328
+ npx -y handoff-relay server mcp --profile default --agent-approvals
329
+ ```
330
+
331
+ In that mode, your agent may call `relay_approve` or `relay_hydrate` without a pasted token after it shows you the packet and you tell it to send, approve, or hydrate. The MCP process requests and consumes the same short-lived approval token through the configured Handoff backend. Local database profiles keep that request local; remote profiles send the approval secret to the configured Handoff server API. Approval secrets stay out of MCP schemas and config.
332
+
333
+ ## Packet Shape
334
+
335
+ A Relay Packet keeps context structured instead of dumping a transcript:
336
+
337
+ ```json
338
+ {
339
+ "packet_type": "share",
340
+ "title": "Auth refresh handoff",
341
+ "summary": "The refresh-token retry path still returns 401 after rotation.",
342
+ "finding": "The retry path appears to skip persistence before the second request.",
343
+ "source_client": "codex",
344
+ "files_or_symbols": ["src/auth/refresh.ts", "refreshSession"],
345
+ "commands_or_tests_run": ["pnpm test auth-refresh"],
346
+ "what_was_tried": ["Checked token expiry math", "Re-ran the refresh integration test"],
347
+ "known_failures": ["expected 200 received 401"],
348
+ "current_hypothesis": "Refresh persistence ordering issue.",
349
+ "suggested_next_steps": ["Trace where the rotated token is written before retry"]
350
+ }
351
+ ```
352
+
353
+ Full schema notes: [docs/packet-schema.md](docs/packet-schema.md).
354
+
355
+ ## Security Model
356
+
357
+ - Sender approval is required before ask/share packets leave the sender.
358
+ - Recipient acceptance and approval are required before ask/share packets hydrate.
359
+ - Reply approval is required before recipient-agent output returns to the sender.
360
+ - Strict mode requires manual approval tokens; optional agent-confirmed mode lets profile-backed MCP request those tokens after explicit user instruction.
361
+ - Approval secrets are not exposed through MCP schemas or config.
362
+ - Member tokens and approval secrets are stored outside profile metadata.
363
+ - Secret-looking content blocks sending by default.
364
+ - Raw transcripts are not shared by default.
365
+ - Packet access is enforced in the service and storage layer, not only in MCP filtering.
366
+ - Audit and hydration receipts record packet movement.
367
+
368
+ More detail: [docs/security-privacy.md](docs/security-privacy.md).
369
+
370
+ ## Operating A Team Workspace
371
+
372
+ For a small team, `start --lan` is the fastest way to host on the same network. For a more durable team setup, run Handoff on a stable internal host:
373
+
374
+ ```bash
375
+ npx -y handoff-relay server start \
376
+ --db /srv/handoff/relay.db \
377
+ --host 10.0.0.10 \
378
+ --port 3737
379
+ ```
380
+
381
+ See [Local self-hosting](docs/local-self-hosting.md) and [Advanced manual setup](docs/advanced-manual-setup.md).
382
+
383
+ ## Commands Are Support Plumbing
384
+
385
+ The CLI exists for setup, invites, admin operations, approval tokens, health checks, and automation. Normal teammate handoff should happen through MCP tools inside the coding agent.
386
+
387
+ Common operational commands:
388
+
389
+ ```bash
390
+ handoff start
391
+ handoff invite
392
+ handoff join
393
+ handoff doctor
394
+ handoff server status
395
+ handoff server stop
396
+ handoff server mcp
397
+ handoff approval-token
398
+ handoff watch
399
+ ```
400
+
401
+ ## Docs
402
+
403
+ - [Codex setup](docs/codex-setup.md)
404
+ - [Claude Code setup](docs/claude-code-setup.md)
405
+ - [Generic MCP setup](docs/generic-mcp-setup.md)
406
+ - [Local self-hosting](docs/local-self-hosting.md)
407
+ - [Advanced manual setup](docs/advanced-manual-setup.md)
408
+ - [Packet schema](docs/packet-schema.md)
409
+ - [Security and privacy model](docs/security-privacy.md)
410
+ - [Troubleshooting](docs/troubleshooting.md)
411
+
412
+ ## Run From Source
413
+
414
+ Use this path when developing Handoff itself:
415
+
416
+ ```bash
417
+ pnpm install
418
+ pnpm build
419
+ pnpm check
420
+ ```
421
+
422
+ The package ships `dist`, top-level docs, examples, fixtures, and this README.
423
+
424
+ ## Current Limits
425
+
426
+ - Handoff does not provide a hosted cloud service. You host the workspace/server.
427
+ - Slack is not a first-class adapter. Handoff is meant to replace raw paste/chat handoff with structured agent-to-agent context transfer.
428
+ - Literal client-specific slash command registration is not shipped. Use MCP tools and optional local command templates in your client.
429
+ - SQLite is the default storage for local/self-hosted teams. Postgres is intentionally left as a future storage adapter.
430
+ - Handoff does not passively capture sessions, build a team memory index, or apply another teammate's patch automatically.
431
+
432
+ ## License
433
+
434
+ MIT.
@@ -0,0 +1,16 @@
1
+ import { FastifyInstance } from 'fastify';
2
+ import { R as RelayService } from '../relay-service-BjF5HNvN.js';
3
+ import 'zod';
4
+ import 'better-sqlite3';
5
+
6
+ interface ApiServerOptions {
7
+ service: RelayService;
8
+ }
9
+ declare function buildApiServer(options: ApiServerOptions): FastifyInstance;
10
+ declare function startApiServer(input: {
11
+ dbPath: string;
12
+ host?: string;
13
+ port?: number;
14
+ }): Promise<FastifyInstance>;
15
+
16
+ export { type ApiServerOptions, buildApiServer, startApiServer };