relay-claude-channel 0.2.1
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/.claude-plugin/plugin.json +27 -0
- package/LICENSE +21 -0
- package/README.md +173 -0
- package/commands/configure.md +71 -0
- package/package.json +44 -0
- package/runtime/server.mjs +26197 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "relay",
|
|
3
|
+
"description": "Relay channel for Claude Code. Message your Claude Code session from your Relay agent conversation, with remote Allow/Deny permission relay. Run /relay:configure to set up.",
|
|
4
|
+
"version": "0.2.0",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Relay"
|
|
7
|
+
},
|
|
8
|
+
"keywords": [
|
|
9
|
+
"relay",
|
|
10
|
+
"messaging",
|
|
11
|
+
"channel",
|
|
12
|
+
"mcp"
|
|
13
|
+
],
|
|
14
|
+
"mcpServers": {
|
|
15
|
+
"relay": {
|
|
16
|
+
"command": "node",
|
|
17
|
+
"args": [
|
|
18
|
+
"${CLAUDE_PLUGIN_ROOT}/runtime/server.mjs"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"channels": [
|
|
23
|
+
{
|
|
24
|
+
"server": "relay"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Companion Inc.
|
|
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,173 @@
|
|
|
1
|
+
# Relay channel for Claude Code
|
|
2
|
+
|
|
3
|
+
Message a running Claude Code session through your Relay agent conversation.
|
|
4
|
+
The plugin is a self-contained MCP stdio server for Claude Code's experimental
|
|
5
|
+
[channels contract](https://code.claude.com/docs/en/channels-reference).
|
|
6
|
+
|
|
7
|
+
- Owner-authenticated Relay messages enter the session as
|
|
8
|
+
`notifications/claude/channel` events.
|
|
9
|
+
- The `reply` tool sends a logical message back with retry-safe idempotency.
|
|
10
|
+
- Permission prompts can be reviewed and denied from Relay. Remote Allow is
|
|
11
|
+
available only when Claude supplies a complete, verifiable tool-input JSON;
|
|
12
|
+
otherwise approval remains local.
|
|
13
|
+
|
|
14
|
+
## Requirements
|
|
15
|
+
|
|
16
|
+
- Node.js 20.11 or newer
|
|
17
|
+
- Claude Code with channel support (channels remain a research preview)
|
|
18
|
+
- A Relay agent and Agent Token
|
|
19
|
+
- No webhook enabled for that agent: Relay permits one event consumer, so
|
|
20
|
+
long-polling and webhook delivery are mutually exclusive
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
Install the published CLI, pair once, and install its bundled local
|
|
25
|
+
marketplace:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
npm install -g @relaymessenger/cli
|
|
29
|
+
relaymessenger pair
|
|
30
|
+
relaymessenger install-claude
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`install-claude` strictly validates the bundled source, copies it to a stable
|
|
34
|
+
content-addressed directory under the paired account's private Relay runtime,
|
|
35
|
+
registers the local `relaymessenger-bundled` marketplace, and installs
|
|
36
|
+
`relay@relaymessenger-bundled`. It does not depend on this GitHub repository or on
|
|
37
|
+
the npm package remaining at its original install path. The installed plugin
|
|
38
|
+
already contains `runtime/server.mjs` with all runtime dependencies bundled;
|
|
39
|
+
do not locate a plugin cache or run `npm install` after installation.
|
|
40
|
+
|
|
41
|
+
## Configure
|
|
42
|
+
|
|
43
|
+
The install command also configures the channel without exposing the token:
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
relaymessenger install-claude
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
That command writes the paired token, API origin, and owner pin to the
|
|
50
|
+
platform-equivalent of:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
~/.claude/channels/relay/.env
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
with owner-only permissions and these values:
|
|
57
|
+
|
|
58
|
+
```dotenv
|
|
59
|
+
RELAY_AGENT_TOKEN=<your agent token>
|
|
60
|
+
RELAY_BASE_URL=https://api.relayapp.im
|
|
61
|
+
# Optional explicit owner pin. Otherwise GET /v1/agents/me must return one.
|
|
62
|
+
#RELAY_OWNER_USER_ID=usr_...
|
|
63
|
+
# Optional stable session namespace. Defaults to the Claude project directory.
|
|
64
|
+
#RELAY_CHANNEL_SESSION_ID=my-repository
|
|
65
|
+
# Explicit opt-in for a private agent only: trust the first user sender.
|
|
66
|
+
#RELAY_ALLOW_TOFU=1
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The file is mode 600/current-user-only. The command never prints the token and
|
|
70
|
+
refuses to overwrite a different existing channel identity. Run
|
|
71
|
+
`/relay:configure` for verification or for manual setup when relaymessenger is not
|
|
72
|
+
available and you already have a token through another secure route.
|
|
73
|
+
|
|
74
|
+
`RELAY_BASE_URL` must be an HTTPS origin with no path, query, fragment, or
|
|
75
|
+
embedded credentials. Plain HTTP is accepted only for `localhost`,
|
|
76
|
+
`127.0.0.1`, or `::1` development servers.
|
|
77
|
+
|
|
78
|
+
Verify without printing the token:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
node <installed-plugin-directory>/runtime/server.mjs --check
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Run
|
|
85
|
+
|
|
86
|
+
Custom channels require Claude Code's development-channel flag during the
|
|
87
|
+
research preview:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
claude --dangerously-load-development-channels plugin:relay@relaymessenger-bundled
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Use `server:relay` instead when registered as a bare MCP server.
|
|
94
|
+
|
|
95
|
+
Only one live Claude session may consume an agent's event stream. A second
|
|
96
|
+
session fails closed instead of stealing the long-poll consumer. Use a
|
|
97
|
+
different Relay agent when two sessions must receive messages concurrently.
|
|
98
|
+
|
|
99
|
+
## Delivery and retry contract
|
|
100
|
+
|
|
101
|
+
Channel notifications are unacknowledged at the Claude transport layer. This
|
|
102
|
+
plugin therefore stages each inbound event in an atomic local ledger before
|
|
103
|
+
notifying Claude and includes `delivery_id="evt_..."` on the channel tag.
|
|
104
|
+
Claude calls the `acknowledge` tool after fully handling it. Until then, the
|
|
105
|
+
delivery is re-notified every 30 seconds and replayed after a channel restart.
|
|
106
|
+
This is **at-least-once**, not exactly-once, delivery.
|
|
107
|
+
|
|
108
|
+
A crash after an external side effect but before acknowledgement can replay the
|
|
109
|
+
request. Before repeating a deploy, deletion, payment, shell command, or other
|
|
110
|
+
non-idempotent action, reconcile whether it already succeeded. The bridge
|
|
111
|
+
cannot make arbitrary tools exactly-once.
|
|
112
|
+
|
|
113
|
+
Outbound `reply` calls require a `send_id`. Reuse the same `send_id`,
|
|
114
|
+
conversation, and text for an unknown-outcome retry; use a new `send_id` for an
|
|
115
|
+
intentional repeat. The mapping is persisted before the HTTP request, and
|
|
116
|
+
reusing an id with different content is rejected.
|
|
117
|
+
|
|
118
|
+
## Permission safety and data boundary
|
|
119
|
+
|
|
120
|
+
Claude's channel permission notification exposes `input_preview`, documented
|
|
121
|
+
as JSON truncated at 200 characters. The plugin no longer truncates or folds
|
|
122
|
+
that field: it sends every character it receives and makes invisible controls
|
|
123
|
+
visible. When the value is shorter than the truncation boundary and parses as
|
|
124
|
+
complete JSON, the Relay card offers Allow and Deny. Otherwise it clearly says
|
|
125
|
+
the input may be incomplete, offers only Deny, and requires local-terminal
|
|
126
|
+
review to approve. This prevents a hidden destructive suffix from being
|
|
127
|
+
approved remotely.
|
|
128
|
+
|
|
129
|
+
Permission cards cross a data boundary: tool names, descriptions, shell
|
|
130
|
+
commands, local paths, and prefixes or complete contents supplied in the input
|
|
131
|
+
are uploaded to the configured Relay API and retained in Relay message history.
|
|
132
|
+
Do not enable permission relay for repositories or commands whose details must
|
|
133
|
+
not leave the machine. The Agent Token itself remains only in the local `.env`.
|
|
134
|
+
|
|
135
|
+
Only the agent owner's Relay user id can inject messages or verdicts. The owner
|
|
136
|
+
comes from `RELAY_OWNER_USER_ID` or `GET /v1/agents/me`; without one, startup
|
|
137
|
+
fails closed unless `RELAY_ALLOW_TOFU=1` was explicitly set. TOFU is suitable
|
|
138
|
+
only for an agent no one else can message.
|
|
139
|
+
|
|
140
|
+
## Durable state
|
|
141
|
+
|
|
142
|
+
State lives below `~/.claude/channels/relay/state/`, namespaced first by the
|
|
143
|
+
canonical API origin and Relay agent id. The account directory contains:
|
|
144
|
+
|
|
145
|
+
- `consumer-state.json` for the shared cursor and TOFU owner pin
|
|
146
|
+
- `consumer-ledger.json` for unacknowledged deliveries and recent event ids
|
|
147
|
+
|
|
148
|
+
Those two files are account-scoped so a later Claude session inherits the
|
|
149
|
+
consumer position instead of replaying retained history. Each hashed session
|
|
150
|
+
subdirectory separately contains `routing.json` and `session-ledger.json` for
|
|
151
|
+
last-conversation routing, permission registrations, and logical outbound
|
|
152
|
+
sends. A new session cannot answer an old session's permission card.
|
|
153
|
+
|
|
154
|
+
Writes use owner-only files and atomic rename. If consumer cursor state or
|
|
155
|
+
either security-critical ledger is corrupt, startup fails closed and preserves
|
|
156
|
+
a block marker plus the quarantined file instead of resetting the cursor or
|
|
157
|
+
silently replaying old events. Session routing state may be quarantined and
|
|
158
|
+
reset because it does not guard event delivery or external side effects.
|
|
159
|
+
|
|
160
|
+
## Development
|
|
161
|
+
|
|
162
|
+
```text
|
|
163
|
+
npm ci
|
|
164
|
+
npm run check
|
|
165
|
+
npm test
|
|
166
|
+
npm run build
|
|
167
|
+
npm run pack:smoke
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`npm run build` produces the checked-in, self-contained
|
|
171
|
+
`runtime/server.mjs`. `npm pack` runs that build again through `prepack`. The
|
|
172
|
+
root release checks also run Claude Code's pinned `plugin validate --strict`
|
|
173
|
+
against both the plugin and marketplace before npm publication.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Configure and verify the self-contained Relay channel
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Configure Relay without asking the user to paste or echo a secret in chat.
|
|
6
|
+
|
|
7
|
+
1. Use the paired relaymessenger flow. Ask the user to run these locally if needed:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
npm install -g @relaymessenger/cli
|
|
11
|
+
relaymessenger pair
|
|
12
|
+
relaymessenger install-claude
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`install-claude` installs the bundled local marketplace as
|
|
16
|
+
`relay@relaymessenger-bundled`, then copies the paired token, API origin, and
|
|
17
|
+
pinned owner into the channel `.env` with current-user-only permissions. It
|
|
18
|
+
never prints the token and refuses to overwrite a different configured
|
|
19
|
+
channel identity.
|
|
20
|
+
|
|
21
|
+
2. Determine the user's channel directory using their platform conventions:
|
|
22
|
+
`~/.claude/channels/relay` on macOS/Linux or
|
|
23
|
+
`%USERPROFILE%\.claude\channels\relay` on Windows. Create it with access
|
|
24
|
+
restricted to the current user.
|
|
25
|
+
|
|
26
|
+
Verify that `.env` exists. Do not read or display its contents.
|
|
27
|
+
|
|
28
|
+
3. If relaymessenger is unavailable and the user already obtained an Agent Token
|
|
29
|
+
through another secure route, they may create `.env` themselves with
|
|
30
|
+
current-user-only access:
|
|
31
|
+
|
|
32
|
+
```dotenv
|
|
33
|
+
RELAY_AGENT_TOKEN=
|
|
34
|
+
RELAY_BASE_URL=https://api.relayapp.im
|
|
35
|
+
#RELAY_OWNER_USER_ID=usr_...
|
|
36
|
+
#RELAY_CHANNEL_SESSION_ID=my-repository
|
|
37
|
+
#RELAY_ALLOW_TOFU=1
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`RELAY_ALLOW_TOFU=1` is an explicit fallback only for an agent no one else
|
|
41
|
+
can message. Normally the owner comes from `GET /v1/agents/me`.
|
|
42
|
+
|
|
43
|
+
Never request, print, or place the token in a command argument.
|
|
44
|
+
|
|
45
|
+
4. Do not run `npm install`. The installed plugin's
|
|
46
|
+
`runtime/server.mjs` already contains its runtime dependencies.
|
|
47
|
+
|
|
48
|
+
5. After the user confirms the file is ready, run this from the installed
|
|
49
|
+
plugin directory using a platform-native path:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
node runtime/server.mjs --check
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Report only success, agent id, or the sanitized error. Never display the
|
|
56
|
+
`.env` file or token. The check also rejects non-HTTPS remote origins.
|
|
57
|
+
|
|
58
|
+
6. Explain how to start the research-preview channel:
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
claude --dangerously-load-development-channels plugin:relay@relaymessenger-bundled
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Use `server:relay` for a bare MCP registration. The agent must not have a
|
|
65
|
+
webhook enabled, and only one live Claude session can consume that agent.
|
|
66
|
+
|
|
67
|
+
7. Ask the user to message the agent from Relay. Explain that messages are
|
|
68
|
+
delivered at least once until Claude acknowledges them. Permission cards
|
|
69
|
+
upload the displayed tool details to Relay history; an incomplete
|
|
70
|
+
200-character Claude preview can be denied remotely but must be approved at
|
|
71
|
+
the local terminal.
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "relay-claude-channel",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Relay channel for Claude Code. Bridges a Relay agent conversation into a Claude Code session over the experimental claude/channel MCP contract.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/relaymessenger/Relay-SDK.git",
|
|
13
|
+
"directory": "integrations/claude-code"
|
|
14
|
+
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=20.11"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
".claude-plugin/",
|
|
20
|
+
"commands/",
|
|
21
|
+
"runtime/",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "node scripts/build.mjs",
|
|
27
|
+
"check": "npm run typecheck",
|
|
28
|
+
"prepack": "npm run build",
|
|
29
|
+
"start": "node runtime/server.mjs",
|
|
30
|
+
"dev": "tsx server.ts",
|
|
31
|
+
"pack:smoke": "node scripts/pack-smoke.mjs",
|
|
32
|
+
"test": "node scripts/test.mjs",
|
|
33
|
+
"typecheck": "tsc --noEmit",
|
|
34
|
+
"verify": "npm run typecheck && npm test && npm run build"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
38
|
+
"@types/node": "^26.2.0",
|
|
39
|
+
"esbuild": "^0.28.2",
|
|
40
|
+
"tsx": "^4.23.11",
|
|
41
|
+
"typescript": "^7.0.2",
|
|
42
|
+
"zod": "4.4.3"
|
|
43
|
+
}
|
|
44
|
+
}
|