bots-garden/mini-mepublic Fork
⑂ feature/ask-cli
Commits
⬇ Clone ▾
git clone https://git.rickub.com/bots-garden/mini-me.git
git clone ssh://git@rickub.com/bots-garden/mini-me.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP
🛟 Updated. 382fecb · on feature/ask-cli · k33g · 19d ago
asking-another-agent.md · 42 lines · 6.6 KBmarkdown
Blame HistoryOpen raw

Asking another agent — explanation

What is this about?

/ask-bob <prompt> lets the agent you are talking to consult another mm agent: another model, another system prompt, other tools and skills. Bob's answer is shown, then kept in your conversation so your own model can use it on your next question. This page explains how that is built and why.

Why it is designed this way

Another agent is another process. Bob runs as a child mm -acp -config <bob's file>, the same binary as the agent that asks. Running him inside the same process was the obvious alternative and the wrong one: mm's configuration is one global, read by the engine, the tools, the compaction and the sessions alike, and bob's differs in all of them. A second engine in the same process would first have meant pulling that global apart everywhere. A child keeps each agent whole, with its own tools, skills and MCP servers.

The two talk ACP. mm already speaks the Agent Client Protocol as a server, for editors. Asking bob makes the asking agent an ACP client of its child. The protocol gives, for free, what scraping a terminal never would: bob's answer as text, his tool calls as structured events, his permission requests as requests that can be answered, and a standard way to cancel. mm's ACP server only ever calls two client methods — session updates and permission requests — so the client side is small; file and terminal requests are refused as absent.

Bob's permissions are yours to give. When bob wants to run a command, the request is forwarded to the front end you are using: in an editor its own dialog, in the window the permissions setting and its inline prompt, in the line mode nothing — exactly as for your own agent's tools there. Bob's tools are named bob/<tool>, so allowing your agent's bash "for this session" does not allow bob's.

The answer is a pair of messages. It enters your history as a user message ([asked bob (provider/model): …]) followed by an assistant message ([bob's answer] and the text). One message would have been simpler, but your next question is a user message too, and several chat templates (Gemma's, Mistral's) refuse two user messages in a row. The marks say who said what, so your model does not mistake bob's answer for its own. The answer is capped like a tool's output, at maxOutput characters: it lands in your model's window.

Each ask is a fresh conversation for bob. Bob keeps no memory between two asks. When he needs to know what you were doing, /ask-with-context-bob sends a transcript: questions, answers, one line per tool call — never the tool outputs, which would cost his window what they already cost yours, never your system prompt or reasoning. Continuity is explicit, chosen per question, rather than a second conversation drifting on its own.

One child per agent, started once. Starting mm costs its engine set-up, its server probe and its MCP servers. The first ask starts bob; later asks reuse him, each with a new session. He stops when your agent exits.

The child is fenced off from what is meant for its parent. Variables like AGENT_MODEL, AGENT_PROVIDER or AGENT_BASE_URL override a configuration; inherited by bob, they would silently turn him into a copy of you. They are removed from his environment. Bob also runs with AGENT_SESSIONS=off: he works in your project, and his session files would otherwise appear in your /sessions and /resume.

Chains stop. /ask is a command a person types; no model can call it, so no agent loops on its own. A person could still type /ask into an agent that was itself asked, so each child is told its depth (MM_ASK_DEPTH): your agent may ask bob, bob may ask riker, riker may not ask anyone.

The same machinery answers scripts. mm --ask <agent> and mm --ask-with-context <agent> are the slash commands for whatever can only run a command — a skill, a script. They start the same child over ACP, with the same environment fence and depth limit, but the answer goes to stdout and everything else to stderr, so a caller captures the answer alone. mm exports MM_BIN and MM_CONFIG to the commands its bash tool runs, so a skill calls "this mm, with this configuration" without knowing either path. Two things differ from the slash commands, both because the caller is a command and not a person. The agent's tool calls are allowed, as in the line mode: the person already approved the mm --ask command itself. And mm --ask watches its parent process: the bash tool kills bash when its budget runs out, not bash's children, and an orphaned ask kept its agent running — and writing files — after nobody waited for it any more.

Time is the weak point. A local model can take a minute to answer, and one bash command had 30 seconds; bashTimeout now sets that budget. The watchdog of the asking agent also keeps counting while a command runs (ticket 57), so it has to be raised too until that ticket is fixed.

Rejected alternatives

  • mm -p "<prompt>" as a subprocess. One process per question and nothing to keep alive — but its output is a terminal screen (answer, reasoning, tool echoes, colours, the command recap) that would have to be parsed; it never asks permission, so bob would run commands unchecked; it cannot be cancelled except by killing it.
  • A second engine in the same process. Fast, no process — at the price of turning the global configuration into a per-agent one throughout the code base.
  • Letting the current model answer at once with bob's input. The user chose otherwise: bob's answer is shown and kept, and you decide what to ask next.
  • Keeping bob's own conversation across asks. Two conversations evolving in parallel, one of them invisible, are harder to reason about than an explicit transcript sent when asked.
  • A generic /ask <name> only, in editors too. An editor's / menu completes a command name, never its argument; one command per agent is the only way for the menu to list the agents.

How it relates to the rest

  • The child is an ordinary ACP agent; the parent reuses the protocol from the other side.
  • Its tool calls and permissions go through the same event interface the three front ends implement for your own agent's tools.
  • The exchange is part of the history like any other turn: it is saved with the session, replayed by /resume, and summarised by context compression when it gets old.
  • Using it: how to ask another agent. Every command and message: slash commands reference.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# Asking another agent — explanation

## What is this about?

`/ask-bob <prompt>` lets the agent you are talking to consult another mm agent: another model, another system prompt, other tools and skills. Bob's answer is shown, then kept in your conversation so your own model can use it on your next question. This page explains how that is built and why.

## Why it is designed this way

**Another agent is another process.** Bob runs as a child `mm -acp -config <bob's file>`, the same binary as the agent that asks. Running him inside the same process was the obvious alternative and the wrong one: mm's configuration is one global, read by the engine, the tools, the compaction and the sessions alike, and bob's differs in all of them. A second engine in the same process would first have meant pulling that global apart everywhere. A child keeps each agent whole, with its own tools, skills and MCP servers.

**The two talk ACP.** mm already speaks the Agent Client Protocol as a server, for editors. Asking bob makes the asking agent an ACP *client* of its child. The protocol gives, for free, what scraping a terminal never would: bob's answer as text, his tool calls as structured events, his permission requests as requests that can be answered, and a standard way to cancel. mm's ACP server only ever calls two client methods — session updates and permission requests — so the client side is small; file and terminal requests are refused as absent.

**Bob's permissions are yours to give.** When bob wants to run a command, the request is forwarded to the front end you are using: in an editor its own dialog, in the window the `permissions` setting and its inline prompt, in the line mode nothing — exactly as for your own agent's tools there. Bob's tools are named `bob/<tool>`, so allowing your agent's `bash` "for this session" does not allow bob's.

**The answer is a pair of messages.** It enters your history as a user message (`[asked bob (provider/model): …]`) followed by an assistant message (`[bob's answer]` and the text). One message would have been simpler, but your next question is a user message too, and several chat templates (Gemma's, Mistral's) refuse two user messages in a row. The marks say who said what, so your model does not mistake bob's answer for its own. The answer is capped like a tool's output, at `maxOutput` characters: it lands in your model's window.

**Each ask is a fresh conversation for bob.** Bob keeps no memory between two asks. When he needs to know what you were doing, `/ask-with-context-bob` sends a transcript: questions, answers, one line per tool call — never the tool outputs, which would cost his window what they already cost yours, never your system prompt or reasoning. Continuity is explicit, chosen per question, rather than a second conversation drifting on its own.

**One child per agent, started once.** Starting mm costs its engine set-up, its server probe and its MCP servers. The first ask starts bob; later asks reuse him, each with a new session. He stops when your agent exits.

**The child is fenced off from what is meant for its parent.** Variables like `AGENT_MODEL`, `AGENT_PROVIDER` or `AGENT_BASE_URL` override a configuration; inherited by bob, they would silently turn him into a copy of you. They are removed from his environment. Bob also runs with `AGENT_SESSIONS=off`: he works in your project, and his session files would otherwise appear in your `/sessions` and `/resume`.

**Chains stop.** `/ask` is a command a person types; no model can call it, so no agent loops on its own. A person could still type `/ask` into an agent that was itself asked, so each child is told its depth (`MM_ASK_DEPTH`): your agent may ask bob, bob may ask riker, riker may not ask anyone.

**The same machinery answers scripts.** `mm --ask <agent>` and `mm --ask-with-context <agent>` are the slash commands for whatever can only run a command — a skill, a script. They start the same child over ACP, with the same environment fence and depth limit, but the answer goes to stdout and everything else to stderr, so a caller captures the answer alone. mm exports `MM_BIN` and `MM_CONFIG` to the commands its `bash` tool runs, so a skill calls "this mm, with this configuration" without knowing either path. Two things differ from the slash commands, both because the caller is a command and not a person. The agent's tool calls are allowed, as in the line mode: the person already approved the `mm --ask` command itself. And `mm --ask` watches its parent process: the `bash` tool kills `bash` when its budget runs out, not bash's children, and an orphaned ask kept its agent running — and writing files — after nobody waited for it any more.

**Time is the weak point.** A local model can take a minute to answer, and one `bash` command had 30 seconds; `bashTimeout` now sets that budget. The watchdog of the asking agent also keeps counting while a command runs (ticket 57), so it has to be raised too until that ticket is fixed.

## Rejected alternatives

- **`mm -p "<prompt>"` as a subprocess.** One process per question and nothing to keep alive — but its output is a terminal screen (answer, reasoning, tool echoes, colours, the command recap) that would have to be parsed; it never asks permission, so bob would run commands unchecked; it cannot be cancelled except by killing it.
- **A second engine in the same process.** Fast, no process — at the price of turning the global configuration into a per-agent one throughout the code base.
- **Letting the current model answer at once with bob's input.** The user chose otherwise: bob's answer is shown and kept, and you decide what to ask next.
- **Keeping bob's own conversation across asks.** Two conversations evolving in parallel, one of them invisible, are harder to reason about than an explicit transcript sent when asked.
- **A generic `/ask <name>` only, in editors too.** An editor's `/` menu completes a command name, never its argument; one command per agent is the only way for the menu to list the agents.

## How it relates to the rest

- The child is an ordinary [ACP agent](../reference/acp.md); the parent reuses the protocol from the other side.
- Its tool calls and permissions go through the same event interface the three front ends implement for your own agent's tools.
- The exchange is part of the history like any other turn: it is saved with the [session](persistent-sessions.md), replayed by `/resume`, and summarised by [context compression](context-compression.md) when it gets old.
- Using it: [how to ask another agent](../how-to/ask-another-agent.md). Every command and message: [slash commands reference](../reference/slash-commands.md#asking-another-agent).