oxtail 0.6.0 → 0.6.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/AGENTS.md CHANGED
@@ -29,7 +29,9 @@ Current phase remains **dogfooding**: use the tools in real parallel-agent work,
29
29
 
30
30
  The v0.5 change: two new MCP tools (`send_message`, `read_my_messages`) plus an opt-in `PreToolUse` hook installable via `npx oxtail install-hook`. Friction observed while pairing on Terminator — two agents in the same project root can see each other's state cards and transcripts but couldn't say anything to each other. Now they can. Claude Code peers see messages mid-turn (via the hook); Codex peers (or unhooked Claude Code) see them next-turn (via polling `read_my_messages`).
31
31
 
32
- The v0.6 change: one new MCP tool (`ask_peer`) that turns v0.5's async pings into synchronous delegate-and-wait. Friction observed while dogfooding v0.5 — `send_message` lets agents say things to each other, but the sender doesn't stay in-turn waiting for a reply, and an idle receiver doesn't get nudged. `ask_peer` blocks server-side until a reply with a matching `from_session_id` lands (or a fixed timeout elapses) and fires a `tmux send-keys` wake to rouse idle peers. The result: an agent talking to its user can delegate to a peer, exchange multiple rounds inside one of its own turns, and report back synthesized findings.
32
+ The v0.6 change: one new MCP tool (`ask_peer`) that turns v0.5's async pings into a blocking delegate-and-wait. Friction observed while dogfooding v0.5 — `send_message` lets agents say things to each other, but the sender doesn't stay in-turn waiting for a reply. `ask_peer` blocks server-side until a reply with a matching `from_session_id` lands (or a fixed timeout elapses) and fires a `tmux send-keys` wake against the peer's pane.
33
+
34
+ **v0.6 known limitation (tracked in issue #3, scoped for v0.7).** The wake does *not* reliably rouse fully-idle TUI peers. Codex composer pollution is verified (2026-05-13 in `terminal-orchestrator`): the wake's `tmux send-keys ... Enter` lands as typed-but-not-submitted text in Codex's `›` composer, leaving the wake notification visible to the user but never flushing it as a turn. Idle Claude Code peers are also unwoken in practice — the PreToolUse hook only fires inside an existing turn, so idle Claude at its prompt has no polling path — but the root cause is not yet captured the same way (could be the same `\r`-as-newline issue; could be different). For now, `ask_peer` is reliable only when the target is already in a turn (or enters one on its own via user input) inside the timeout window. Against a fully idle peer with no human at the keyboard, expect `timed_out: true`.
33
35
 
34
36
  ## How to collaborate on this project
35
37
 
@@ -45,9 +47,13 @@ The v0.6 change: one new MCP tool (`ask_peer`) that turns v0.5's async pings int
45
47
  3. **Both Claude Code and Codex CLI must work** with whatever we build. MCP is the cross-tool protocol; Skills are Claude-specific syntactic sugar that wraps MCP tools, never primary functionality.
46
48
  4. **Minimum viable first.** One MCP tool that's actually used > five speculative ones.
47
49
 
50
+ ## Invariants worth defending
51
+
52
+ - **`client.session_id` is the unique agent identity.** Not `server_pid`, not `tmux_session`. One Claude/Codex client can be backed by multiple MCP server children — the documented dual-scope setup (project `.mcp.json` + user `~/.claude.json`) intentionally spawns two oxtail processes per session, and Claude Code/Codex restarts during a long session can leak ghost children. The registry stores one file per `server_pid`, so duplicates per `session_id` are the norm; `readAll()` collapses them by `session_id` (freshest `started_at` wins). Any new code that reasons about peer identity must key on `client.session_id` — adding lookups keyed on `server_pid` or `tmux_session` will reintroduce the bug class where peer reads bail with misleading scope errors (see commit history for the v0.6-era dedupe fix).
53
+
48
54
  ## Recently shipped
49
55
 
50
- - **Delegate-and-wait (v0.6).** `ask_peer({ target, body })` blocks server-side until the peer replies (filtered by `from_session_id`) or a fixed timeout elapses, with a `tmux send-keys` wake fallback for idle peers. Late replies fall back to the v0.5 hook / poll delivery path. Target must have a registered `client.session_id`.
56
+ - **Delegate-and-wait (v0.6).** `ask_peer({ target, body })` blocks server-side until the peer replies (filtered by `from_session_id`) or a fixed timeout elapses, with a best-effort `tmux send-keys` wake attempted against the peer's pane. Late replies fall back to the v0.5 hook / poll delivery path. Target must have a registered `client.session_id`. **Idle-TUI wake is not reliable in v0.6** — see the limitation note above and issue #3.
51
57
  - **Cross-session messaging (v0.5).** `send_message({ target, body })` + `read_my_messages()`. Mailbox lives at `~/.oxtail/mailboxes/<server_pid>.jsonl`, drained under an `mkdir`-based advisory lock. Opt-in PreToolUse hook (`npx oxtail install-hook`) for mid-turn delivery to Claude Code.
52
58
 
53
59
  ## Deliberately deferred
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # oxtail
2
2
 
3
+ [![test](https://github.com/d4j3y2k/oxtail/actions/workflows/test.yml/badge.svg)](https://github.com/d4j3y2k/oxtail/actions/workflows/test.yml)
4
+
3
5
  Run two or more coding agents in the same repo and let them see each other. oxtail is a local MCP server that gives parallel Claude Code and Codex CLI sessions peer awareness: each session can list the others running in the same project root, read their state cards, and (when needed) read their transcripts directly. No fixed cap — every oxtail-aware session in the project shows up in `list_project_sessions`.
4
6
 
5
7
  Works for any mix of clients that speak MCP — Claude Code, Codex CLI, or one of each. Scope is **project-root as the unit**: sessions in `/path/to/foo` see each other; sessions in `/path/to/bar` see each other; cross-project there is no visibility, by design.
@@ -38,14 +40,14 @@ curl -L https://raw.githubusercontent.com/d4j3y2k/oxtail/v0.6.0/.claude/commands
38
40
  -o ~/.claude/commands/oxtail-join.md
39
41
  ```
40
42
 
41
- **Codex skill** (`/oxtail-register`):
43
+ **Codex skill** (`/oxtail-join`):
42
44
 
43
45
  ```sh
44
- mkdir -p ~/.codex/skills/oxtail-register/agents
45
- curl -L https://raw.githubusercontent.com/d4j3y2k/oxtail/v0.6.0/integrations/codex/oxtail-register/SKILL.md \
46
- -o ~/.codex/skills/oxtail-register/SKILL.md
47
- curl -L https://raw.githubusercontent.com/d4j3y2k/oxtail/v0.6.0/integrations/codex/oxtail-register/agents/openai.yaml \
48
- -o ~/.codex/skills/oxtail-register/agents/openai.yaml
46
+ mkdir -p ~/.codex/skills/oxtail-join/agents
47
+ curl -L https://raw.githubusercontent.com/d4j3y2k/oxtail/v0.6.1/integrations/codex/oxtail-join/SKILL.md \
48
+ -o ~/.codex/skills/oxtail-join/SKILL.md
49
+ curl -L https://raw.githubusercontent.com/d4j3y2k/oxtail/v0.6.1/integrations/codex/oxtail-join/agents/openai.yaml \
50
+ -o ~/.codex/skills/oxtail-join/agents/openai.yaml
49
51
  ```
50
52
 
51
53
  Floating form (`npx -y oxtail` with no `@`) exists for trying it out; don't pin daily configs to it — it floats end users into whatever the next published version turns out to be.
@@ -63,9 +65,9 @@ Contributing? `git clone https://github.com/d4j3y2k/oxtail && cd oxtail && npm i
63
65
  - `read_session` — the recent transcript of a peer session, as clean per-turn messages when the peer is oxtail-aware (Claude Code and Codex CLI), or as raw tmux pane text otherwise. Accepts a tmux session name OR a `client_session_id` UUID; an ambiguous tmux name returns `ambiguous-target` with the candidate UUIDs.
64
66
  - `claim_session` — single-shot session registration. The routine path: `Bash echo $CLAUDE_CODE_SESSION_ID` (or `$CODEX_THREAD_ID` for Codex) → `claim_session({ session_id })`. Returns `{ ok, session_id, transcript_path }`.
65
67
  - `set_my_state` — write a small "state card" onto this session's registry entry so peers can see what we're doing without reading our transcript. v1 surfaces a single field, `purpose` (≤200 chars).
66
- - `send_message` — **fire-and-forget** message to a peer. **Does NOT wake an idle peer** — use `ask_peer` for that. Target is a tmux session name or a raw `client_session_id` UUID. Body ≤ 8KB. Delivery is async via the peer's mailbox file. (v0.5+)
68
+ - `send_message` — **fire-and-forget** message to a peer. **Does NOT wake an idle peer.** Target is a tmux session name or a raw `client_session_id` UUID. Body ≤ 8KB. Delivery is async via the peer's mailbox file. (v0.5+) (`ask_peer` attempts a wake but the v0.6 implementation does not reliably rouse idle TUI peers — see its description.)
67
69
  - `read_my_messages` — drain this session's mailbox and return any queued messages. Codex peers (and unhooked Claude Code) poll this; Claude Code peers with the PreToolUse hook installed see messages mid-turn instead. (v0.5+)
68
- - `ask_peer` — **synchronous delegate-and-wait**. Wakes the peer via `tmux send-keys` and **blocks until they reply** (or the fixed timeout elapses, default 45s, tunable via `OXTAIL_ASK_PEER_TIMEOUT_MS`). Returns the peer's reply body. Use this for delegate-and-wait dynamics; use `send_message` for fire-and-forget. (v0.6+)
70
+ - `ask_peer` — **delegate-and-wait**. Enqueues a message and blocks server-side until the peer replies (or the fixed timeout elapses, default 45s, tunable via `OXTAIL_ASK_PEER_TIMEOUT_MS`). Fires a best-effort `tmux send-keys` wake. **Known limitation (issue #3, planned v0.7):** the wake does not reliably rouse fully-idle TUI peers — see "Delegate-and-wait (v0.6)" below. Reliable when the target is already in a turn; against a fully idle peer expect timeout. Use `send_message` when you don't need a synchronous reply. (v0.6+)
69
71
  - `register_my_session` — pin this MCP server's `session_id` directly. Kept for debugging; prefer `claim_session`.
70
72
  - `get_my_session` — return this MCP server's own registry entry plus a per-strategy detection diagnosis. Useful for debugging.
71
73
 
@@ -136,18 +138,20 @@ oxtail trusts any process running as the **same local user** to enqueue messages
136
138
 
137
139
  ## Delegate-and-wait (v0.6)
138
140
 
139
- `ask_peer` extends v0.5's mailbox transport into a synchronous primitive:
141
+ `ask_peer` extends v0.5's mailbox transport into a blocking primitive:
140
142
 
141
143
  ```
142
144
  ask_peer({ target, body })
143
145
  → { ok: true, message_id, reply: { id, body, enqueued_at, from_session_id } | null, timed_out }
144
146
  ```
145
147
 
148
+ > **Known limitation in v0.6 — read this before relying on `ask_peer`.** The wake mechanism does not reliably rouse a fully-idle TUI peer. Verified 2026-05-13 against Codex CLI: the `tmux send-keys ... Enter` lands in Codex's `›` composer as typed-but-not-submitted text, leaving the wake notification visible to the user but never flushing it as a turn. Idle Claude Code peers are also unwoken in practice (no polling at the prompt), though the exact mechanism is not yet root-caused the same way. `ask_peer` is therefore reliable only when the target is already in a turn (or enters one on its own via user input or another tool call's PreToolUse hook) inside the timeout window. Against a fully idle peer with no human at the keyboard, expect `timed_out: true`. Tracked in [issue #3](https://github.com/d4j3y2k/oxtail/issues/3); per-client wake strategy is scoped for v0.7.
149
+
146
150
  Mechanics:
147
151
 
148
152
  1. Enqueue `body` into the target's mailbox (same as `send_message`).
149
153
  2. Wait ~500ms for a hook-delivered reply (rare path — handles the case where the peer was already mid-tool-call and replied immediately).
150
- 3. Fire a `tmux send-keys` wake against the peer's pane: a single literal line `[oxtail] new peer message — run mcp__oxtail__read_my_messages and respond via mcp__oxtail__send_message` followed by Enter. This nudges idle peers without requiring the human at the other end to type.
154
+ 3. Fire a best-effort `tmux send-keys` wake against the peer's pane (see known limitation above): a single literal line `[oxtail] new peer message — run mcp__oxtail__read_my_messages and respond via mcp__oxtail__send_message` followed by `Enter`. In a shell prompt this would flush as a command; in a TUI composer it currently lands as composer text.
151
155
  4. Poll the caller's mailbox at 200ms for a reply with `from_session_id == target.session_id`. Other peers' messages stay in the mailbox untouched.
152
156
  5. Return the reply on match, or `{ reply: null, timed_out: true }` after the fixed timeout. Late replies fall back to the normal v0.5 hook / `read_my_messages` path — never lost, just delivered out of band.
153
157
 
@@ -155,7 +159,7 @@ Constraints:
155
159
 
156
160
  - The target peer must have a registered `client.session_id`. Codex peers must call `claim_session` / `register_my_session` first; without that, `ask_peer` returns `error: "peer-has-no-session-id"` rather than guessing.
157
161
  - Timeout defaults to 45000ms (conservative under typical MCP-client tool-call abort windows). For longer dialogues, the calling agent chains multiple `ask_peer` calls in one turn rather than configuring a longer single block.
158
- - The wake is best-effort. If `tmux send-keys` fails against the cached pane id (Terminator-style window churn can leave the id stale), oxtail retries against the tmux session name (which targets the currently-active pane). If both fail, the peer may still respond on its own via polling — the only loss is the immediacy of the nudge.
162
+ - Pane targeting can go stale: if `tmux send-keys` fails against the cached pane id (Terminator-style window churn can leave the id stale), oxtail retries against the tmux session name (which targets the currently-active pane). Reaching the right pane is a separate concern from the pane-actually-submitting-the-wake limitation above.
159
163
 
160
164
  ### Tuning the timeout
161
165
 
@@ -209,4 +213,4 @@ If `MCP_TRACE_FILE` is set in the environment, every detection run appends an ND
209
213
 
210
214
  ## Status
211
215
 
212
- v0.6.0. Adds `ask_peer` on top of v0.5's mailbox transport: an agent can send a message and block until the peer replies, with an automatic `tmux send-keys` wake for idle peers. Combined with the existing PreToolUse hook, two Claude Code sessions can now sustain a back-and-forth handoff inside a single turn of the delegating agent. Codex peers are supported as targets once they've claimed a session.
216
+ v0.6.0. Adds `ask_peer` on top of v0.5's mailbox transport: an agent can send a message and block server-side until the peer replies. The implementation attempts a `tmux send-keys` wake against the peer's pane — but in practice that wake does not reliably rouse fully-idle TUI peers; `ask_peer` is reliable only when the peer is already in a turn (or enters one on its own inside the timeout). When both sides are mid-turn, the existing PreToolUse hook handles mid-turn delivery cleanly. Codex peers are supported as targets once they've claimed a session. Per-client wake strategy is scoped for v0.7 (issue #3).
package/dist/registry.js CHANGED
@@ -134,6 +134,13 @@ export function refreshTmuxBinding(entry) {
134
134
  }
135
135
  export function register(entry) {
136
136
  ensureDir();
137
+ // Best-effort GC: drop stale entries from dead processes that share our
138
+ // session_id. Happens when oxtail is configured in multiple MCP scopes
139
+ // (user + project), so the same client session has spawned several MCP
140
+ // server children over its lifetime — survivors of crashed prior children
141
+ // accumulate otherwise. Leaves live siblings alone; readAll() collapses
142
+ // those by session_id.
143
+ gcDeadSiblings(entry);
137
144
  // Temp file + atomic rename. Concurrent peers running readAll() can otherwise
138
145
  // catch a torn write, fail JSON.parse, and silently drop the entry until the
139
146
  // next write completes.
@@ -153,6 +160,38 @@ export function register(entry) {
153
160
  throw err;
154
161
  }
155
162
  }
163
+ function gcDeadSiblings(entry) {
164
+ const sid = entry.client.session_id;
165
+ if (!sid)
166
+ return;
167
+ const dir = registryDir();
168
+ if (!existsSync(dir))
169
+ return;
170
+ for (const file of readdirSync(dir)) {
171
+ if (!file.endsWith(".json"))
172
+ continue;
173
+ const full = join(dir, file);
174
+ let other;
175
+ try {
176
+ other = JSON.parse(readFileSync(full, "utf8"));
177
+ }
178
+ catch {
179
+ continue;
180
+ }
181
+ if (other.server_pid === entry.server_pid)
182
+ continue;
183
+ if (other.client.session_id !== sid)
184
+ continue;
185
+ if (isAlive(other.server_pid))
186
+ continue;
187
+ try {
188
+ unlinkSync(full);
189
+ }
190
+ catch {
191
+ // already gone, fine
192
+ }
193
+ }
194
+ }
156
195
  export function unregister(pid = process.pid) {
157
196
  try {
158
197
  unlinkSync(entryPath(pid));
@@ -175,7 +214,7 @@ export function readAll() {
175
214
  const dir = registryDir();
176
215
  if (!existsSync(dir))
177
216
  return [];
178
- const out = [];
217
+ const live = [];
179
218
  for (const file of readdirSync(dir)) {
180
219
  if (!file.endsWith(".json"))
181
220
  continue;
@@ -196,9 +235,35 @@ export function readAll() {
196
235
  }
197
236
  continue;
198
237
  }
199
- out.push(entry);
238
+ live.push(entry);
239
+ }
240
+ return dedupeBySessionId(live);
241
+ }
242
+ // One Claude/Codex session can be backed by multiple MCP server children when
243
+ // oxtail is declared in more than one MCP scope (e.g. user-level config +
244
+ // project `.mcp.json`). Each child registers separately, so the registry ends
245
+ // up with N entries that share the same client.session_id. session_id is the
246
+ // unique agent identity downstream (resolver UUID lookup, peer messaging),
247
+ // so collapse the duplicates here. Keep the freshest by started_at — that's
248
+ // the most likely to have an up-to-date transcript path and tmux binding.
249
+ // Entries with no session_id are left alone: they're either pre-claim
250
+ // (haven't called claim_session yet) or unclaimed peers, and conflating
251
+ // them would be wrong.
252
+ export function dedupeBySessionId(entries) {
253
+ const winnerBySession = new Map();
254
+ const noSession = [];
255
+ for (const e of entries) {
256
+ const sid = e.client.session_id;
257
+ if (!sid) {
258
+ noSession.push(e);
259
+ continue;
260
+ }
261
+ const prior = winnerBySession.get(sid);
262
+ if (!prior || e.started_at > prior.started_at) {
263
+ winnerBySession.set(sid, e);
264
+ }
200
265
  }
201
- return out;
266
+ return [...winnerBySession.values(), ...noSession];
202
267
  }
203
268
  export function findByTmuxSession(name) {
204
269
  return readAll().filter((e) => e.tmux_session === name);
package/dist/server.js CHANGED
@@ -715,7 +715,7 @@ server.registerTool("send_message", {
715
715
  "Delivery is asynchronous: the message lands in the target's mailbox and is delivered mid-turn via the oxtail PreToolUse hook (Claude Code) or next-turn via read_my_messages (Codex, or any client without the hook installed). If the peer is idle (no in-flight turn, no polling), the message waits until they next call a tool or poll explicitly — there is no nudge.",
716
716
  "Sender-side wrapping: if you want the message to appear as a system-reminder, include the <system-reminder>...</system-reminder> tags in `body`. The mailbox is a dumb transport.",
717
717
  "Cross-project targets are rejected, never silently dropped.",
718
- "For a blocking send-and-wait variant that pauses your turn until the peer replies AND nudges an idle peer via tmux send-keys, use ask_peer instead.",
718
+ "For a blocking send-and-wait variant that pauses your turn until the peer replies, use ask_peer instead. (Note: ask_peer's idle-peer wake is best-effort in v0.6 and does not reliably rouse fully-idle TUI peers — see ask_peer's tool description.)",
719
719
  ].join(" "),
720
720
  inputSchema: {
721
721
  target: z
@@ -815,10 +815,18 @@ function askPeerDelay(ms, signal) {
815
815
  signal.addEventListener("abort", onAbort, { once: true });
816
816
  });
817
817
  }
818
- // Best-effort wake: two send-keys calls so the text is interpreted literally
819
- // (-l) and Enter is parsed as a key event. The -l flag neutralizes any tmux
820
- // keysequences a malicious peer could plant in its registry entry. Failure to
821
- // reach tmux is non-fatal — the peer may still poll or hook-deliver on its own.
818
+ // KNOWN ISSUE (tracked in #3, planned for v0.7): this wake does not actually
819
+ // rouse idle TUI peers. Verified 2026-05-13 against Codex CLI the trailing
820
+ // `tmux send-keys ... Enter` lands as composer-newline rather than submit,
821
+ // leaving the wake text typed-but-not-flushed in Codex's `›` composer. Idle
822
+ // Claude Code peers are also unwoken in practice; the PreToolUse hook only
823
+ // fires inside an existing turn, so an idle Claude at its prompt sees nothing
824
+ // until the user types. ask_peer is therefore effectively async-only against
825
+ // idle peers: replies arrive once the peer enters a turn on its own.
826
+ //
827
+ // Two send-keys calls: the text is interpreted literally (-l) and Enter is
828
+ // parsed as a key event. The -l flag neutralizes any tmux keysequences a
829
+ // malicious peer could plant in its registry entry.
822
830
  //
823
831
  // Pane targeting can go stale: tmux_pane is cached at server startup (registry
824
832
  // resolveTmuxPane), but Terminator-style window churn can move or close the
@@ -897,9 +905,10 @@ async function askPeerPoll(my_pid, from_session_id, deadlineMs, signal) {
897
905
  }
898
906
  server.registerTool("ask_peer", {
899
907
  description: [
900
- "Synchronous delegate-and-wait. Wakes the peer via tmux send-keys and blocks until they reply (or timeout).",
901
- "Use this when you want a synchronous back-and-forth with another agent in the same project root, rather than fire-and-forget like send_message.",
902
- "Behavior: enqueues the body to the target's mailbox, waits ~500ms for a hook-delivered reply, then fires a tmux send-keys wake to nudge the peer if idle, then polls this session's mailbox at 200ms for a reply from the target.",
908
+ "Enqueue a message to a peer and block until they reply (or timeout).",
909
+ "Use this when you want a back-and-forth with another agent in the same project root, rather than fire-and-forget like send_message.",
910
+ "KNOWN LIMITATION (v0.6, tracked in issue #3, planned v0.7): the tmux send-keys wake does NOT reliably rouse idle TUI peers. Codex composer pollution verified 2026-05-13 wake text lands as typed-but-not-submitted input. Idle Claude Code peers are also unwoken in practice. ask_peer reliably returns a reply only if the target enters a turn on its own (user types into it, or another tool call fires its PreToolUse hook) within the timeout. Against a fully idle peer with no human at the keyboard, expect timeout.",
911
+ "Behavior: enqueues the body to the target's mailbox, waits ~500ms for a hook-delivered reply, fires a best-effort tmux send-keys wake (see limitation above), then polls this session's mailbox at 200ms for a reply from the target.",
903
912
  "Returns when the target sends a message back (via send_message) whose from_session_id matches them, or when the timeout elapses (returns reply: null, timed_out: true). Timeout defaults to 45000ms; user-tunable via OXTAIL_ASK_PEER_TIMEOUT_MS env var.",
904
913
  "Target must have a registered client.session_id (Codex peers must call register_my_session first).",
905
914
  "Late replies that arrive after timeout are delivered normally via read_my_messages / the PreToolUse hook.",
@@ -1057,6 +1066,14 @@ function maybeHookHint() {
1057
1066
  }
1058
1067
  process.stderr.write("[oxtail] PreToolUse hook not installed — run `npx oxtail install-hook` to enable mid-turn peer messaging.\n");
1059
1068
  }
1060
- const transport = new StdioServerTransport();
1061
- await server.connect(transport);
1062
- maybeHookHint();
1069
+ // Importing server.ts (e.g. from a test that needs an exported helper) used
1070
+ // to await server.connect(transport) at module load — which never resolves
1071
+ // without stdin EOF and hung `npm test` indefinitely. Gate the transport
1072
+ // behind a direct-invocation check, mirroring scripts/install-hook.mjs.
1073
+ const invokedDirectly = typeof process.argv[1] === "string" &&
1074
+ import.meta.url === new URL(process.argv[1], "file:").href;
1075
+ if (invokedDirectly) {
1076
+ const transport = new StdioServerTransport();
1077
+ await server.connect(transport);
1078
+ maybeHookHint();
1079
+ }
@@ -1,11 +1,11 @@
1
1
  ---
2
- name: oxtail-register
3
- description: Register the current Codex agent session with the oxtail MCP peer registry. Use when the user asks to join oxtail, register with oxtail, run oxtail-register, fix oxtail client_session_id detection, or make this Codex session visible/readable to peer agents in the same project.
2
+ name: oxtail-join
3
+ description: Join this Codex session into the oxtail MCP peer registry. Use when the user asks to join oxtail, register with oxtail, run oxtail-join, fix oxtail client_session_id detection, or make this Codex session visible/readable to peer agents in the same project.
4
4
  ---
5
5
 
6
- # Oxtail Register
6
+ # Oxtail Join
7
7
 
8
- Register this Codex session with oxtail quickly and verify the result.
8
+ Join this Codex session into the oxtail peer registry quickly and verify the result.
9
9
 
10
10
  ## Communication Contract
11
11
 
@@ -0,0 +1,10 @@
1
+ interface:
2
+ display_name: "Oxtail Join"
3
+ short_description: "Join this Codex session to the oxtail peer registry"
4
+ default_prompt: "Use $oxtail-join to register this Codex session with the oxtail peer registry."
5
+
6
+ dependencies:
7
+ tools:
8
+ - type: "mcp"
9
+ value: "oxtail"
10
+ description: "Local oxtail MCP server exposing session registration tools"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxtail",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Coordination layer for parallel AI coding agent sessions, exposed over MCP.",
@@ -1,10 +0,0 @@
1
- interface:
2
- display_name: "Oxtail Register"
3
- short_description: "Register Codex with oxtail peers"
4
- default_prompt: "Use $oxtail-register to register this Codex session with the oxtail peer registry."
5
-
6
- dependencies:
7
- tools:
8
- - type: "mcp"
9
- value: "oxtail"
10
- description: "Local oxtail MCP server exposing session registration tools"