antiphon 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 Serkan Can Gökalp
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,113 @@
1
+ # Antiphon
2
+
3
+ **Two terminals, two separate agents, an open-identity bridge.** While Claude Code and Codex CLI work in the same project, each sees the other's context and can wake the other when it needs to, without ever faking who the message is from.
4
+
5
+ Antiphon doesn't dispatch work. It only carries messages between the two sides while preserving whether they came from the human user, from Claude, or from Codex.
6
+
7
+ ## How it works
8
+
9
+ No shared log is kept. Both CLIs already write their own transcripts; Antiphon reads and derives from them, marking in `.antiphon/cursor.json` which messages each side has already seen.
10
+
11
+ ### Pull — context, no wake
12
+
13
+ | Direction | Mechanism |
14
+ |---|---|
15
+ | Codex → Claude | Claude `UserPromptSubmit` hook |
16
+ | Claude → Codex | Codex `UserPromptSubmit` hook |
17
+
18
+ The other side's recent messages enter your turn's context when you type
19
+ something. Nobody is woken up.
20
+
21
+ ### Push — live wake
22
+
23
+ | Direction | Mechanism |
24
+ |---|---|
25
+ | Claude → Codex | Claude `Stop` hook + `codex queue` |
26
+ | Codex → Claude | Codex `Stop` hook + MCP Channel |
27
+
28
+ A line starting with `@codex` or `@claude` in a reply reaches the other
29
+ agent immediately, even if nobody is typing.
30
+
31
+ ### How identity is preserved
32
+
33
+ A Claude → Codex message reaches Codex tagged either `[Antiphon bridge] Claude:` (pushed from Claude's Stop hook) or `[Antiphon channel] Claude:` (a direct reply sent through the channel, via the `reply_to_codex` tool) — either way, Codex sees these as Claude's words, not the human user's.
34
+
35
+ A Codex → Claude message never pastes text into the terminal and never impersonates user input. The local MCP server sends Claude Code a `notifications/claude/channel` event. Its metadata looks like:
36
+
37
+ ```xml
38
+ <channel source="antiphon" sender="codex" sender_kind="agent" message_id="...">
39
+ ```
40
+
41
+ Claude Code's interface shows this as an incoming channel event, and Claude treats the message as the words of the Codex agent, not of the human user. It sends its reply back with the `reply_to_codex` MCP tool.
42
+
43
+ ## Install
44
+
45
+ Requires Node 18+ and Python 3. The Claude Code channel is a research
46
+ preview and needs Claude Code 2.1.80 or newer.
47
+
48
+ Install the command, either straight from the repository:
49
+
50
+ npm i -g github:serkancangokalp/antiphon
51
+
52
+ or from npm:
53
+
54
+ npm i -g @serkancangokalp/antiphon
55
+
56
+ Either way the command is `antiphon` — the package name only decides
57
+ where it comes from. Then, in the project the two agents share:
58
+
59
+ cd /your/project
60
+ antiphon setup
61
+ claude --dangerously-load-development-channels server:antiphon
62
+
63
+ `setup` writes `.claude/settings.json`, `.codex/hooks.json`,
64
+ `.codex/config.toml`, `.mcp.json`, `.claude/settings.local.json`,
65
+ `AGENTS.md` and `CLAUDE.md` for that project. The hook commands resolve
66
+ `antiphon` through your `PATH` rather than hardcoding an install path, so
67
+ they keep working after a reinstall or a move; `.mcp.json` and
68
+ `.codex/config.toml` still record this project's own absolute directory,
69
+ so each side can find the right channel socket. None of the seven files
70
+ live in this repository — they are generated per project. Approve the
71
+ Codex hooks once when Codex first shows them.
72
+
73
+ ## Update
74
+
75
+ npm i -g github:serkancangokalp/antiphon # from the repository
76
+ npm i -g @serkancangokalp/antiphon@latest # from npm
77
+
78
+ cd /your/project && antiphon setup
79
+
80
+ Re-running `setup` migrates hooks and instruction blocks written by older
81
+ versions in place; it never creates duplicates.
82
+
83
+ ## Commands
84
+
85
+ ```bash
86
+ antiphon status # transcript, cursor and channel status
87
+ antiphon summary [side] # show the context that would be injected
88
+ antiphon setup # (re)install the project setup
89
+ npm test # Python unit tests + real MCP protocol test
90
+ ```
91
+
92
+ `setup` registers the `antiphon_read` MCP tool for Codex in this project's
93
+ `.codex/config.toml`, so there is nothing to add by hand. Note the entry
94
+ names `args = ["mcp"]`: the `channel` server is Claude's side and hands out
95
+ `reply_to_codex`. Aiming Codex at it would let Codex publish messages
96
+ labelled as Claude's — exactly what this bridge exists to prevent — so
97
+ `setup` rewrites that table whenever it is wrong, leaving the rest of the
98
+ file alone.
99
+
100
+ The bridge works without this entry; it only lets Codex query the bridge by hand when it suspects the pull hook has gone quiet.
101
+
102
+ ## Limits
103
+
104
+ - A live push needs an open session on the target side. If the target is closed, the message still shows up on the next pull.
105
+ - The Claude MCP Channel is only live while Claude Code is started with the right development-channel flag.
106
+ - Channels is currently a research preview; it requires a claude.ai login or a Console API key. It isn't supported on the Bedrock, Vertex, or Foundry providers. A Team/Enterprise admin may need to enable the feature.
107
+ - The Codex hook asks for re-approval the first time it's used and whenever the hook file changes.
108
+ - Matching is done on the same project's absolute directory.
109
+ - Once a message has been seen, the cursor advances and the same content is never injected twice.
110
+ - Context transfer has a budget of roughly 2600 characters; the newest messages are kept.
111
+ - Unix sockets only — there is no Windows support.
112
+
113
+ MIT.
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from "node:child_process";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ const here = dirname(fileURLToPath(import.meta.url));
7
+ const [subcommand, ...rest] = process.argv.slice(2);
8
+
9
+ // `channel` is a long-lived stdio MCP server; it runs directly, never through Python.
10
+ const target = subcommand === "channel"
11
+ ? { cmd: process.execPath, args: [join(here, "..", "lib", "channel.mjs")] }
12
+ : { cmd: "python3", args: [join(here, "..", "lib", "antiphon.py"), ...(subcommand ? [subcommand] : []), ...rest] };
13
+
14
+ const child = spawn(target.cmd, target.args, { stdio: "inherit" });
15
+ child.on("exit", (code, signal) => process.exit(signal ? 1 : code ?? 0));
16
+ child.on("error", (error) => {
17
+ process.stderr.write(`antiphon: ${error.message}\n`);
18
+ process.exit(1);
19
+ });