From mesh-channel
Two-agent communication over a shared JSONL file. Controller-asymmetric — install on the controller side only; the peer uses the channel via shell commands in its prompt. Use Monitor to wake on new lines from the other agent.
How this skill is triggered — by the user, by Claude, or both
Slash command
/mesh-channel:mesh-channelThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
A minimal protocol so two long-running agents can exchange messages through a single file, without polling each other and without coordinating writes.
A minimal protocol so two long-running agents can exchange messages through a single file, without polling each other and without coordinating writes.
This plugin installs on the controller side only. The peer agent is a generic Claude Code (or
similar) session that uses the channel via plain shell commands embedded in its instruction
prompt — it never installs mesh-channel itself.
Monitor wake on inbound messages.mesh-channel-send and mesh-channel-watch (or pre-baked command lines) inside the prompt you spawn it with. The peer treats them as opaque shell commands.This shape lets you set up a one-way controller→peer asymmetry quickly, while the channel itself is still bidirectional at the file level — the peer can write back, your Monitor task wakes you on its lines.
assets-dispatch --continue/--btwBoth mechanisms can carry "controller wants to tell a running asset something." The boundary:
tmux-pane (--continue / --btw) | file-channel (mesh-channel) | |
|---|---|---|
| Direction | controller → asset, one-way | bidirectional |
| Sync | synchronous (send-keys, immediate) | async (file append + poll) |
| Persistence | pane scrollback only | durable JSONL log, inspectable with cat/tail/jq |
| Peers per channel | one asset | many (file is shared) |
| Cross-host | requires the controller to have the tmux socket | works wherever the file is reachable (shared FS, sync) |
Rule of thumb: tmux-pane for one-shot directives to a single asset, mesh-channel for bidirectional / multi-peer / observable streams.
Monitor), not loop-pollingExamples: pairing this session with a long-running squad in tmux; cross-instance debug chat with another agent; agent ↔ external program that can append JSONL lines.
/tmp/<channel-name>.jsonl).ts, from, body. body is a string; markdown is fine (the JSON encoder handles newlines, quotes, backticks).O_APPEND + single write(). On Linux and macOS the kernel atomically appends each write to regular files via the inode lock — concurrent writers won't interleave bytes within one call. We cap each line at 4096 bytes as a portability guard for exotic filesystems (e.g. NFS without locking).<channel>.cursor.<my-name>. A new watcher starts at EOF by default (no backlog replay); pass --catch-up to start at 0. --catch-up always wins — it overwrites an existing cursor.from == my-name so you don't get your own writes back. Note this is honor-system: any writer can set from to your name and your watcher will silently drop those lines.Wrap the watcher in the Monitor tool. Each notification = one inbound message from the OTHER agent.
Monitor(
command="/path/to/mesh-channel-watch /tmp/<channel>.jsonl <my-name>",
description="mesh-channel <channel> as <my-name>",
persistent=true
)
Add --catch-up to the command if you want to read the file from the beginning (replay backlog). Default starts at EOF.
The Monitor task ID is what you'll pass to TaskStop later. Save it.
bash: /path/to/mesh-channel-send /tmp/<channel>.jsonl <my-name> "<body>"
Body is a single shell argument — quote it. Markdown inside is fine; the writer does json.dumps so any ", \n, or ``` becomes a proper JSON-string escape.
For multi-line markdown body, pass the whole thing inside the quotes:
mesh-channel-send /tmp/demo.jsonl worker "Multi-line body:
- one
- two
Looks good?"
TaskStop(<monitor-task-id>)
Or just let the session end — Monitor is session-bound and dies with the REPL.
Each line is:
{"ts": "2026-05-15T02:38:00Z", "from": "worker", "body": "any string, markdown OK"}
Optional fields you can add downstream (the watcher passes them through):
to — addressing hint when more than two agents share a channeltype — message kind (msg, ack, event, etc.)from is enforced for self-filtering--poll <seconds> to tune). Pure-Python, no inotify / watchdog dependency./tmp/test.jsonl) for production traffic so a third writer can't impersonate you.<my-name> on the same channel will race on the cursor sidecar (atomic per write, but they'll leapfrog each other → both lose lines intermittently). Pick distinct names or stop the stale watcher.\n and waits for the next event before re-trying — no half-line emissions.> file truncate) — watchers will pick it up.Monitor, not a while True: read() in your reasoning.body. This is a comms protocol, not a remote-control protocol. Whatever the other agent does with the message is up to its own SKILL/logic.Monitor — event-driven wake, replaces polling.TaskStop — to leave a channel cleanly.Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub meowkey-dev/machine-plugins --plugin mesh-channel