Skip to content

Agents Talking to Agents

luvus lets one agent give work to another. Because the server owns every pane’s terminal, “send a prompt to another agent” means luvus pastes the text into that agent’s input and submits it, then reports back its detected state. There is no separate message channel: the target agent’s own input is the channel, and the host is the broker.

Every pane already has $LUVUS_PANE_ID and $LUVUS_SOCKET_PATH injected, so an agent running inside a pane can drive its neighbors with the same luvus commands you would type yourself.

Terminal window
luvus agent list # every live agent: name, pane, kind, status, cwd
luvus agent name reviewer # alias the current agent (or --pane <id>)
luvus agent prompt reviewer "Review the diff" --wait --until idle --timeout 600
luvus agent read reviewer --lines 120 # read what it produced
luvus agent keys reviewer enter # answer a blocked approval (esc, ctrl+c, up, ...)

A <target> is one of three things:

  • a live name you set (grammar [a-z][a-z0-9_-]{0,31}), set with agent name or pane name,
  • a pane id (the pane field from agent list),
  • an agent kind (claude, kimi, codex, …) when exactly one agent of that kind is running. Two of the same kind is ambiguous, and the error names the candidates so you pick a pane id or a name.

agent prompt and agent keys only target a pane that is actually running an agent, so a plain shell is refused. agent send remains a compatibility alias.

agent.keys requires a recognized agent pane and a non-empty array of named keys. A target that resolves to a plain shell returns agent_not_ready. Luvus validates every entry before it queues one ordered byte sequence, so a mixed-type or unknown-key batch sends no prefix. A closed PTY input queue returns send_failed instead of reporting delivery.

Prompt text and its final Enter are queued as one ordered submission, including direct agent.send requests and DIFF note handoffs. Other queued input cannot interleave between that paste and Enter. A successful send means the queue accepted the submission, not that the agent completed it. A closed queue fails without recording a successful handoff. Submission uses the existing PTY writer and does not create a delayed-send thread.

Paired control Access also permits this exact RPC; read-only Access refuses it. The key grammar stays identical to local agent keys, including ctrl+z and printable Unicode. ["esc","[","Z"] sends Shift+Tab as one ordered batch. Inspect the prompt before answering; Enter remains a separate intentional action. Access does not permit the compatibility agent.send method.

For line-specific feedback, the native DIFF review uses the same target validation. It groups selected local notes into one bounded message, quotes source context as untrusted review data, and records delivery without resolving the notes.

Run luvus agent list (each row has pane, agent kind, name, cwd, workspace_name, and the stable workspace_id). Two Claudes share the kind claude but differ by pane id and folder. Give each a name so you can mention it:

Terminal window
luvus agent name api --pane 1 # or run `luvus pane name api` inside that pane
luvus agent name web --pane 4
luvus agent prompt api "add the /health endpoint" --wait

The AGENTS sidebar also shows each agent’s delegation token on its second line: =name once you name it, otherwise =<id>.

Start an agent in a sibling pane, name it, hand it the task, and collect the result:

Terminal window
luvus agent start codex --kind codex --anchor "$LUVUS_PANE_ID" --timeout 60
luvus agent prompt codex "Implement the CSV parser in src/parse.rs and add a test." \
--wait --until idle --timeout 600 # send and wait
luvus agent read codex --lines 120 # read the result

agent prompt --wait blocks until the agent settles, using Luvus’s state detection plus post-submission output revisions (idle, working, blocked, done). A fast turn that starts and finishes between detector ticks is accepted only after its newer output becomes quiet. If a prompt returns while the agent is blocked, inspect it with agent read and answer with agent keys.

By default, delegation does not block the sender. luvus agent prompt without --wait returns the moment the prompt is queued, so the sender is free. The clean pattern is: name yourself, send without --wait with a report-back instruction, then end the turn.

Terminal window
luvus agent name lead # a name the worker can reply to
luvus agent prompt codex "Build the parser. When done, run: luvus agent prompt lead 'done: <summary>'"

The sender is not blocked; it picks the task back up only when the worker runs that agent prompt lead … and hands it back.

Wait only when you ask for it. Add --wait when the very next step needs the result in the same reply:

Terminal window
luvus agent prompt codex "Build the CSV parser and add a test." --wait
luvus agent read codex --lines 120

--wait blocks the sender until the worker settles and is bounded by --timeout (default 300s, exit 2 on timeout; exit 0 on settle). A timeout still reports submitted:true, so inspect the agent and do not blindly send the same prompt twice. Since it blocks, reach for it only when the next step needs the answer. Luvus permits one waiting prompt per pane and rejects an overlapping wait before queuing its text.

With the skill installed you rarely type the commands. Write =name at the start of a line and the rest of it goes to that agent:

=codex add tests to src/parse.rs
=reviewer take a look at the diff
=7 run the migration

=codex addresses the pane named codex. An agent name or a pane id work the same way, so =reviewer and =7 both resolve. The same targets agent prompt takes. The marker is recognized only as the first non-whitespace character on a line, so equations and shell assignments do not trigger delegation. Codex keeps $ for invoking skills such as $luvus or $changelog.

It is a hand-off, not a wait: the agent you typed into keeps working, and the answer comes back when the other one is done. Ask for it to wait and it will.

If the name does not resolve, the agent runs luvus agent list to find it or asks you which pane you meant.

The commands above work without an agent skill. The optional skill teaches a coding agent when and how to use them. Luvus does not install skills or edit agent configuration during startup. Enable the one version-matched Luvus skill explicitly:

Terminal window
luvus skill enable

Luvus detects supported coding-agent environments and installs the same bundled skill through their native adapters:

  • Claude Code: ~/.claude/skills/luvus/
  • Codex: ~/.agents/skills/luvus/
  • Kilo Code: ~/.agents/skills/luvus/
  • Devin: ~/.agents/skills/luvus/
  • Letta Code: ~/.letta/skills/luvus/
  • opencode (including the opencode2 compatibility alias): ${XDG_CONFIG_HOME:-~/.config}/opencode/skills/luvus/

The command makes no network request and never replaces a skill directory it does not own. Luvus does not add a global AGENTS.md pointer. Supported agents discover the skill from their native directory and load its instructions only when relevant or explicitly invoked.

luvus skill enable installs prompt guidance. It is independent from luvus integration install, which adds optional exact session identity and lifecycle events for resume, alerts, and automation. Core process and screen detection, sidebar visibility, and ordinary resume need no hook. Enabling either one never enables the other.

The messaging commands themselves work with every agent luvus detects (claude, codex, gemini, opencode, kimi, grok, aider, and more), whether or not that agent has the skill installed. The skill just teaches an agent to reach for them on its own.

Inspect the logical skill state or print the canonical instructions bundled with the running Luvus binary:

Terminal window
luvus skill status
luvus skill show

After updating Luvus, run enable again to refresh every Luvus-managed native copy from the new binary:

Terminal window
luvus skill enable

Disable the skill with luvus skill disable. Luvus removes only unchanged installations it manages. Modified files and externally managed skills are preserved and reported.

Restart your coding agent so it loads the skill, open it in a luvus pane, and ask in plain language:

Have codex implement the parser in the other pane and tell me when it is done.

The agent recognizes the request, runs the agent send/wait/read loop itself, and reports back. The skill also controls workspaces, tabs, panes, and other Luvus surfaces when asked. It stays out of the way when the request is unrelated to Luvus.

luvus pane name <name> (and its synonym luvus agent name) does two things: it sets a live address for the CLI and API, and it renames the pane’s title strip to that name in place of its cwd path, so a named pane is easy to spot. It shows the same delegation token in the AGENTS sidebar (=name).

A name is keyed to the pane, so it survives the agent restarting inside it and is dropped only when the pane closes. It does not change the pane’s tab label, which is still luvus tab rename. Clear a name with luvus pane name --clear.