feat(cookbook): add the two-agent-chat recipe - #466
Merged
Conversation
Lets Claude Code and Codex hold a conversation with each other in one agterm split. Each agent sends a line into the other's composer with peer-chat.py and reads the reply as an ordinary prompt, so the user watches both halves without relaying anything by hand. peer-chat.py is send-only and starts nothing: it confirms the target pane is running the agent named by --to, checks the caret is at rest through `surface cursor` before typing, verifies the line reached the composer before the submit key follows, sends Return for Claude Code and Tab for Codex, and retries only the pre-write refusal. Deciding that a pane is safe to type a startup command into means guessing from what it has drawn, so the reader opens the split and starts both agents himself. An agent started through a wrapper shows that wrapper's name to agterm rather than its own, so --target-command declares it and that name is still checked before every pane read and write. Every check also requires the split to exist, since a live left pane on its own is no longer a two-agent layout. Ships one skill file per agent rather than the single SKILL.md the layout allows, since the mechanism is two-sided. CONTRIBUTING records that as the rule for a multi-agent recipe, noting that every loader requires the installed file to be named SKILL.md. Requires agterm 0.24.0, which added `surface cursor`.
…appers Live-testing the recipe with two real agents in a split found four defects that neither the mocked tests nor review caught. An agent started through a wrapper shows the wrapper's name to agterm, not its own, so every send refused. --target-command declares that name and it is still checked before each pane read and write. Every check now also requires the split to exist, since a live left pane alone is not a two-agent layout. Codex strips AGTERM_SESSION_ID from tool subprocesses and its sandbox blocks reading a parent process, so that side could never identify its own session and fell back to a tree scan that refused whenever two sessions matched. Resolution now maps the caller's checkout through git-common-dir and accepts one match in that checkout, refusing rather than choosing a session elsewhere that happens to fit. Setup documents injecting the id at launch, which is deterministic and the only thing that works when two sessions share a checkout, as every worktree of one repository does. --session accepts a unique prefix, and resolution returns the canonical id so composed surface addresses stay valid. Verified live in both directions: six sends, including a multi-turn exchange the two agents drove themselves from these skill files.
…pause The check made after typing reads only the composer's first rendered row, so a wrapped message hides anything sitting on a continuation row, in both directions. The same residual is pinned deliberately in the transport this recipe was reduced from; a stricter comparison is not a fix, since exact equality would reject legitimate wrapped messages. An agent may also ask its own permission before running the script, and neither skill will answer that prompt, so a first exchange can sit waiting on the user and look like a hang.
…setup Says plainly that the recipe is a cut-down version of what the author runs, that it has been tested with two real agents, and that it will be revised as it gets used. Also drops an em-dash from Requirements.
Deploying agterm with
|
| Latest commit: |
1699789
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://7be10848.agterm.pages.dev |
| Branch Preview URL: | https://two-agent-chat.agterm.pages.dev |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
cookbook/two-agent-chat, a recipe letting Claude Code and Codex hold a conversation with each other in one agterm split. Each agent sends a line into the other's composer withpeer-chat.pyand reads the reply as an ordinary prompt, so both halves of the exchange are visible without relaying anything by hand.The script is reduced from the pair of transports I actually run, about 1740 lines of production code between them, down to 353 lines covering peer messaging only. Dropped: startup, prompt guessing, watches, status, handoff tokens, state files, response parsing, and the embedded test suites. What is kept is the part nobody would reinvent correctly: a caret preflight through
surface cursorbefore a character is typed, verification that the line reached the target composer before the submit key follows, Return for Claude Code and Tab for Codex, and a bounded retry on the pre-write refusal alone.Two decisions for you as maintainer.
The layout rule in
cookbook/CONTRIBUTING.mdallows oneSKILL.mdper recipe. This mechanism is two-sided and needs one skill per agent, so the rule now says a multi-agent recipe shipsSKILL-<agent>.mdper agent, noting every loader requires the installed file to be namedSKILL.md. That sets a precedent for future multi-agent recipes.Startup stays manual and the script starts nothing. Deciding a pane is safe to type a launch command into means guessing from what it has drawn, agterm reports no foreground for both an idle shell and a program hiding its argv, and every reader's prompt differs. A recipe whose first step types into whatever holds focus is the one bug not worth publishing.
Verified against two real agents, not only mocked. The first version passed review and its own tests and still failed on the first live send. Four defects came out of running it: a wrapper-launched agent shows the wrapper's name to agterm so every send refused; Codex strips
AGTERM_SESSION_IDfrom tool subprocesses and its sandbox blocks reading a parent process, so that side could never identify its own session;--sessionrejected a unique prefix with a misleading error; and fixing that broke the caret preflight by carrying the prefix into a composed surface address. All four are fixed here. The final run was a multi-turn technical argument the two agents drove themselves from these skill files, in both directions, unattended.Known limits, all stated in the README. Only the composer's first rendered row is identifiable, so a wrapped message hides anything on a continuation row from the post-write check, in both directions. The same residual is pinned deliberately in the transport this was reduced from, and a stricter comparison would reject legitimate wrapped messages rather than fix it. Session resolution never guesses: without an injected id it matches only the caller's checkout, and every worktree of one repository shares a checkout, so two sessions on the same repo need the id injected at launch or an explicit
--session.ruffclean, six README headings, index consistent both ways, no absolute home paths or user names in any committed file.