Repository navigation
feat: give opencode sessions the tools to drive the others - #12
Merged
Merged
Conversation
An opencode session could report what it was doing and nothing else. Claude Code and Codex get the other direction — list the sessions, hand one a task, answer one, open a session with a worktree under it, close one, read the checkouts — as MCP tools lich registers when it spawns them. opencode has no flag to be told about a server, and a plugin there cannot register one either. It can define tools, so the same seven are defined here, under the same names: an agent that learns one surface finds the other where it expects it. Each tool builds an argv and runs the lich binary. Posting to the endpoint directly would have been fewer moving parts and the third implementation of one contract, in a repository lich cannot see — an argument that moved in its docs/cli.md would have gone red in neither. This way what lives here is the argv, and every rule, refusal and wording stays where it is written; a failure answers with lich's own stderr, unedited. Two absences on purpose, and the reports survive both. Outside lich nothing is registered: seven tools that could only answer "no lich is running" would sit in the prompt of every unrelated opencode session. And the tool helper is imported inside a try, because it resolves from opencode's own plugin dependencies and a module dropped where they do not reach must still report. Verified against a running opencode server: the seven appear in its tool list beside the native ones, and against a live lich they list, refuse and open for real.
This was referenced Aug 11, 2026
Merged
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.
An opencode session could report what it was doing and nothing else. This adds
the other direction.
Claude Code and Codex get it as MCP tools lich registers at spawn — it can
pass a server on their command line. opencode cannot be told about one, and
a plugin there cannot register an MCP server
either. What it can do is define tools, so the same seven are defined in the
module, under the same names the MCP server uses: an agent that learns one
surface should find the other where it expects it.
list_sessionssend_to_sessionwait_for_answerreply_to_sessionopen_sessionclose_sessionlist_worktreesThey shell out to
lichEach tool builds an argv and runs the binary. Posting to the same loopback
endpoint the reports use would have been fewer moving parts — and the third
implementation of one contract (lich's CLI, lich's MCP server, this), in a
repository lich cannot see. An argument that moved in
docs/cli.mdwould havegone red in neither.
So what lives here is the argv. Which arguments are required, what a worktree's
last session decides, when
--forceis needed, and every wording written for anagent to act on stay in lich; a command that fails answers with its own stderr,
unedited.
The binary is
$LICH_BIN, neverlichoffPATH— a machine running aninstalled lich beside a
task devbuild has two, and only one belongs to thesession.
Two absences, on purpose
The reports keep working in both, which is the point: they need neither.
lich is running" would be seven tools in the prompt of every unrelated
opencode session on the machine.
toolhelper is imported at run time inside a
try, because it resolves fromopencode's own plugin dependencies and a module dropped where those do not
reach would otherwise fail at import — taking the reports down with it.
Test plan
node --test tests/— 121 pass. The new suite pins the translation and nothing else: the binary that runs, optional arguments left out rather than sent empty, the wait capped at 90,--forcepassed only for a literaltrue(a model sending"false"must not discard someone's work), a refusal returned as lich worded it, and both absences.opencode serve, isolated config, module in its plugin dir): all seven appear in/experimental/tool/idsbeside the native ones."my project"surviving as one.list_sessionsandlist_worktreesreturned real JSON,close_sessioncame back with lich's own refusal about the checkout's fate, andopen_sessionopened one.Needs no change in lich to work. A follow-up there is worth considering: the
relayed message decides whether to name the
reply_to_sessiontool or thecommand from
providers.AcceptsMCPServer, which will now be wrong for opencode.