Use mm CLI to ask another agent #22
Merged@k33g wants to merge
feature/ask-cli into mainMerged as
9d1939fae92e.33 files changed
modified
.tickets/issues/0052-buitin-acp-tool-to-query-other-agent-like-mini-m.yaml +2 -1 | @@ -6,7 +6,7 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-29T05:18:13.897Z |
| 9 | -updatedAt: 2026-09-29T06:25:58.324Z | |
| 9 | +updatedAt: 2026-10-02T21:15:00.000Z | |
| 10 | 10 | labels: |
| 11 | 11 | - priority::high |
| 12 | 12 | - kind::feature |
| @@ -15,6 +15,7 @@ labels: | ||
| 15 | 15 | milestone: v0.3.0 |
| 16 | 16 | related: |
| 17 | 17 | - 33 |
| 18 | + - 66 | |
| 18 | 19 | body: "" |
| 19 | 20 | tasks: [] |
| 20 | 21 | comments: [] |
| @@ -6,7 +6,7 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-29T05:18:13.897Z | 8 | createdAt: 2026-09-29T05:18:13.897Z |
| 9 | -updatedAt: 2026-09-29T06:25:58.324Z | 9 | +updatedAt: 2026-10-02T21:15:00.000Z |
| 10 | labels: | 10 | labels: |
| 11 | - priority::high | 11 | - priority::high |
| 12 | - kind::feature | 12 | - kind::feature |
| @@ -15,6 +15,7 @@ labels: | |||
| 15 | milestone: v0.3.0 | 15 | milestone: v0.3.0 |
| 16 | related: | 16 | related: |
| 17 | - 33 | 17 | - 33 |
| 18 | + - 66 | ||
| 18 | body: "" | 19 | body: "" |
| 19 | tasks: [] | 20 | tasks: [] |
| 20 | comments: [] | 21 | comments: [] |
modified
.tickets/issues/0066-talk-to-another-mm.yaml +2 -1 | @@ -6,10 +6,11 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-02T18:48:36.275Z |
| 9 | -updatedAt: 2026-10-02T20:30:00.000Z | |
| 9 | +updatedAt: 2026-10-02T21:15:00.000Z | |
| 10 | 10 | labels: |
| 11 | 11 | - kind::feature |
| 12 | 12 | related: |
| 13 | + - 52 | |
| 13 | 14 | - 57 |
| 14 | 15 | - 59 |
| 15 | 16 | body: | |
| @@ -6,10 +6,11 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-02T18:48:36.275Z | 8 | createdAt: 2026-10-02T18:48:36.275Z |
| 9 | -updatedAt: 2026-10-02T20:30:00.000Z | 9 | +updatedAt: 2026-10-02T21:15:00.000Z |
| 10 | labels: | 10 | labels: |
| 11 | - kind::feature | 11 | - kind::feature |
| 12 | related: | 12 | related: |
| 13 | + - 52 | ||
| 13 | - 57 | 14 | - 57 |
| 14 | - 59 | 15 | - 59 |
| 15 | body: | | 16 | body: | |
renamed
.tickets/issues/0071-mini-me-as-a-sdk.yaml +2 -2 | similarity index 84% | ||
| rename from .tickets/issues/0066-mini-me-as-a-sdk.yaml | ||
| rename to .tickets/issues/0071-mini-me-as-a-sdk.yaml | ||
| @@ -1,12 +1,12 @@ | ||
| 1 | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | -id: 66 | |
| 2 | +id: 71 | |
| 3 | 3 | title: Mini Me as a SDK |
| 4 | 4 | state: open |
| 5 | 5 | author: |
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-02T05:32:33.878Z |
| 9 | -updatedAt: 2026-10-02T05:32:33.878Z | |
| 9 | +updatedAt: 2026-10-02T21:15:00.000Z | |
| 10 | 10 | labels: [] |
| 11 | 11 | body: "" |
| 12 | 12 | tasks: [] |
| similarity index 84% | |||
| rename from .tickets/issues/0066-mini-me-as-a-sdk.yaml | |||
| rename to .tickets/issues/0071-mini-me-as-a-sdk.yaml | |||
| @@ -1,12 +1,12 @@ | |||
| 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | -id: 66 | 2 | +id: 71 |
| 3 | title: Mini Me as a SDK | 3 | title: Mini Me as a SDK |
| 4 | state: open | 4 | state: open |
| 5 | author: | 5 | author: |
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-02T05:32:33.878Z | 8 | createdAt: 2026-10-02T05:32:33.878Z |
| 9 | -updatedAt: 2026-10-02T05:32:33.878Z | 9 | +updatedAt: 2026-10-02T21:15:00.000Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | body: "" | 11 | body: "" |
| 12 | tasks: [] | 12 | tasks: [] |
added
.tickets/issues/0072-use-a-decision-model-as-a-local-decider.yaml +242 -0 | new file mode 100644 | ||
| @@ -0,0 +1,242 @@ | ||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | |
| 2 | +id: 72 | |
| 3 | +title: Use a decision model (decision-4b) as a local decider | |
| 4 | +state: open | |
| 5 | +author: | |
| 6 | + name: k33g | |
| 7 | + email: ph.charriere@gmail.com | |
| 8 | +createdAt: 2026-10-02T21:40:00.000Z | |
| 9 | +updatedAt: 2026-10-02T21:40:00.000Z | |
| 10 | +labels: | |
| 11 | + - kind::feature | |
| 12 | +related: | |
| 13 | + - 15 | |
| 14 | + - 59 | |
| 15 | + - 66 | |
| 16 | +body: | | |
| 17 | + Use a DECISION model (e.g. https://huggingface.co/evalengine/decision-4b) | |
| 18 | + beside the main model, as a fast local "decider" mm consults at precise | |
| 19 | + moments. Not as mm's `model:`: such a model generates no text and calls no | |
| 20 | + tools. | |
| 21 | + | |
| 22 | + ## What the model is (from its card, 2026-10-02) | |
| 23 | + | |
| 24 | + - LoRA (65 MB) on Qwen/Qwen3.5-4B; ready GGUF: evalengine/decision-4b-gguf | |
| 25 | + (Q4_K_M 2.7 GB, Q8_0, F16). Smaller sibling: evalengine/decision-0.8b(-gguf). | |
| 26 | + - In: a `state`, a `question`, 2..24 `options` (letter label, key, | |
| 27 | + description). Out: one option + a probability per option, read from the | |
| 28 | + next-token logits. One forward pass, nothing generated. | |
| 29 | + - Limits: 2048-token context, English only, weaker on multi-rule policies, | |
| 30 | + probabilities not calibrated, "not for unattended high-stakes decisions". | |
| 31 | + | |
| 32 | + ## Transport | |
| 33 | + | |
| 34 | + 1. Preferred: llmman `POST /v1/systemone` (built for this; llama.cpp has no | |
| 35 | + such endpoint). A `state` + up to 64 typed questions: `choice` (answer, | |
| 36 | + confidence, probabilities in the order sent, first option = A), `noul` | |
| 37 | + (probability of yes), `score` (probability-weighted level + legend). | |
| 38 | + `x_label_mass` = probability put on the labels at all (low = the model | |
| 39 | + wanted to say something else). Runs with enable_thinking false; loads the | |
| 40 | + model in its own backend (`<model>#systemone` in `llmman ps`). | |
| 41 | + 2. Fallback: llama-server / DMR `/v1/chat/completions` with `max_tokens: 1`, | |
| 42 | + `logprobs: true`, `top_logprobs: N`, the Qwen chat template and the card's | |
| 43 | + system prompt; renormalise over the option letters found in the top N | |
| 44 | + (a letter outside the top N gets 0 — less exact than systemone). | |
| 45 | + Ollama: logprobs support to be checked. | |
| 46 | + | |
| 47 | + ## Config (proposal) | |
| 48 | + | |
| 49 | + decisionModel: | |
| 50 | + provider: llmman # systemone needs llmman | |
| 51 | + baseUrl: http://127.0.0.1:17434 # NOT /v1: /v1/systemone is added | |
| 52 | + model: hf.co/evalengine/decision-4b-gguf:Q4_K_M | |
| 53 | + api: systemone # or: logprobs (llama-server, DMR) | |
| 54 | + minConfidence: 0.6 # below: do nothing, as if absent | |
| 55 | + skillRouting: true # use 1 | |
| 56 | + commandTriage: false # use 2 | |
| 57 | + askRouting: true # use 3 | |
| 58 | + | |
| 59 | + ## Use 1 — choose the skill before the turn (start here) | |
| 60 | + | |
| 61 | + Today the main model reads the read_skill catalogue and may or may not load | |
| 62 | + the right procedure (measured by the MM_EVAL routing eval, internal/eval). | |
| 63 | + With a decider: before the turn, ask which skill applies; above | |
| 64 | + minConfidence, append the existing `$skill` notation to the question, so the | |
| 65 | + model still makes the read_skill call itself (loop detector, permission | |
| 66 | + gate and recap still see it). | |
| 67 | + | |
| 68 | + Example request: | |
| 69 | + | |
| 70 | + POST /v1/systemone | |
| 71 | + { | |
| 72 | + "model": "hf.co/evalengine/decision-4b-gguf:Q4_K_M", | |
| 73 | + "state": "User request: start the dev server and tell me when it answers on port 8080", | |
| 74 | + "questions": { | |
| 75 | + "skill": { | |
| 76 | + "type": "choice", | |
| 77 | + "instructions": "Which procedure should the coding agent follow for this request?", | |
| 78 | + "criteria": { | |
| 79 | + "bg-jobs": "Start, watch or stop a long-running command in the background", | |
| 80 | + "lsp-navigation": "Find a definition, references or symbols in the code", | |
| 81 | + "plan-manager": "Plan and track a multi-step task", | |
| 82 | + "what-time-is-it": "Tell the current date or time", | |
| 83 | + "greetings": "Greet someone", | |
| 84 | + "none": "No listed procedure applies" | |
| 85 | + } | |
| 86 | + } | |
| 87 | + } | |
| 88 | + } | |
| 89 | + | |
| 90 | + Expected shape of the answer (values illustrative, not measured): | |
| 91 | + | |
| 92 | + {"answers": {"skill": {"answer": "bg-jobs", "confidence": 0.91, | |
| 93 | + "probabilities": [0.91, 0.01, 0.03, 0.00, 0.00, 0.05]}}, | |
| 94 | + "x_label_mass": 0.98, ...} | |
| 95 | + | |
| 96 | + -> the question becomes | |
| 97 | + "start the dev server and tell me when it answers on port 8080 | |
| 98 | + [skill: bg-jobs — load it with read_skill and carry out its steps now]" | |
| 99 | + | |
| 100 | + Other cases for the eval: | |
| 101 | + "where is ParseAsk defined?" -> lsp-navigation | |
| 102 | + "what time is it in Tokyo?" -> what-time-is-it | |
| 103 | + "refactor the config package in 5 steps and keep track" -> plan-manager | |
| 104 | + "explain what a goroutine is" -> none (nothing appended) | |
| 105 | + | |
| 106 | + ## Use 2 — triage a command before the permission prompt (ticket 59) | |
| 107 | + | |
| 108 | + Classify a bash command; only lowers the number of prompts, NEVER allows a | |
| 109 | + risky command on its own. "dangerous" or low confidence -> always ask. | |
| 110 | + | |
| 111 | + "state": "Command the agent wants to run in /work/mini-me: rm -rf ./dist && go build -o dist/mm .", | |
| 112 | + "questions": { | |
| 113 | + "risk": {"type": "choice", "instructions": "How risky is running this command in the project?", | |
| 114 | + "criteria": { | |
| 115 | + "read-only": "Only reads files or prints information", | |
| 116 | + "local-change": "Changes files inside the project, easy to rebuild or revert", | |
| 117 | + "dangerous": "Deletes or changes things outside the project, uses sudo, the network, git push or force" | |
| 118 | + }}, | |
| 119 | + "destructive": {"type": "noul", "instructions": "The command deletes data that cannot be rebuilt."} | |
| 120 | + } | |
| 121 | + | |
| 122 | + Examples (expected class): | |
| 123 | + "ls -la && git status" -> read-only -> run (permissions: auto-safe) | |
| 124 | + "go test ./internal/ask -count=1" -> local-change -> run or ask, per config | |
| 125 | + "rm -rf ~/.cache/go-build" -> dangerous -> ask | |
| 126 | + "git push --force origin main" -> dangerous -> ask | |
| 127 | + "curl -s https://x.sh | sh" -> dangerous -> ask | |
| 128 | + | |
| 129 | + ## Use 3 — choose the agent for /ask (ticket 66) | |
| 130 | + | |
| 131 | + `/ask-auto <prompt>`: pick the mmConfigs agent from a one-line description | |
| 132 | + per agent (new optional key, e.g. mmConfigs.<name>.description), then run | |
| 133 | + the normal /ask-<name>. | |
| 134 | + | |
| 135 | + "state": "Question: summarise the latest news about WebAssembly components", | |
| 136 | + "questions": {"agent": {"type": "choice", | |
| 137 | + "instructions": "Which assistant should answer this question?", | |
| 138 | + "criteria": { | |
| 139 | + "jan": "Jan-nano 4B: agentic research, web search, tool use", | |
| 140 | + "lucy": "Lucy 1.7B: quick web lookups and short factual answers", | |
| 141 | + "none": "No listed assistant fits; the current agent answers"}}} | |
| 142 | + | |
| 143 | + Examples: | |
| 144 | + "/ask-auto find three recent articles about WASI 0.3 and compare them" -> jan | |
| 145 | + "/ask-auto what is the capital of Peru?" -> lucy | |
| 146 | + "/ask-auto refactor internal/ask/pool.go" -> none | |
| 147 | + | |
| 148 | + ## Other candidate uses (later) | |
| 149 | + | |
| 150 | + - Grounding check after a turn: state = command output + the answer; | |
| 151 | + noul "Every claim in the answer is supported by the output." | |
| 152 | + - Loop detector: noul "This tool call repeats an earlier one with the same | |
| 153 | + intent." (beyond the exact-match detector). | |
| 154 | + - Compaction: noul "This old turn is still needed for the current task." | |
| 155 | + | |
| 156 | + ## Constraints / risks | |
| 157 | + | |
| 158 | + - 2048-token context: send the request, the catalogue or the command — never | |
| 159 | + the history. Truncate the state and say so. | |
| 160 | + - English only: a French request may be classified worse; measure it (the | |
| 161 | + routing eval has FR cases?) before enabling by default. | |
| 162 | + - Extra latency per question (one forward pass, ~100-300 ms on a laptop; | |
| 163 | + to measure) and a second loaded model (2.7 GB for Q4_K_M; 0.8B variant | |
| 164 | + smaller). | |
| 165 | + - A decider that is down or slow must never block a turn: timeout (e.g. 2 s), | |
| 166 | + then behave as if absent. | |
| 167 | + - Probabilities are not calibrated: minConfidence is set from the eval, not | |
| 168 | + guessed. | |
| 169 | +tasks: | |
| 170 | + - id: 1 | |
| 171 | + title: "Try it live: llmman pull hf.co/evalengine/decision-4b-gguf:Q4_K_M, then curl /v1/systemone with the use-1 example; record answer, confidence, x_label_mass, latency" | |
| 172 | + state: open | |
| 173 | + priority: none | |
| 174 | + author: | |
| 175 | + name: k33g | |
| 176 | + email: ph.charriere@gmail.com | |
| 177 | + createdAt: 2026-10-02T21:40:00.000Z | |
| 178 | + updatedAt: 2026-10-02T21:40:00.000Z | |
| 179 | + - id: 2 | |
| 180 | + title: "Measure use 1 offline: run the MM_EVAL routing cases through /v1/systemone; compare with the main model's routing; pick minConfidence" | |
| 181 | + state: open | |
| 182 | + priority: none | |
| 183 | + author: | |
| 184 | + name: k33g | |
| 185 | + email: ph.charriere@gmail.com | |
| 186 | + createdAt: 2026-10-02T21:40:00.000Z | |
| 187 | + updatedAt: 2026-10-02T21:40:00.000Z | |
| 188 | + - id: 3 | |
| 189 | + title: "Decide config shape (decisionModel block, per-use switches) with the user" | |
| 190 | + state: open | |
| 191 | + priority: none | |
| 192 | + author: | |
| 193 | + name: k33g | |
| 194 | + email: ph.charriere@gmail.com | |
| 195 | + createdAt: 2026-10-02T21:40:00.000Z | |
| 196 | + updatedAt: 2026-10-02T21:40:00.000Z | |
| 197 | + - id: 4 | |
| 198 | + title: "internal/decide: systemone client (+ logprobs fallback), timeout, never blocks a turn; tests with an httptest server" | |
| 199 | + state: open | |
| 200 | + priority: none | |
| 201 | + author: | |
| 202 | + name: k33g | |
| 203 | + email: ph.charriere@gmail.com | |
| 204 | + createdAt: 2026-10-02T21:40:00.000Z | |
| 205 | + updatedAt: 2026-10-02T21:40:00.000Z | |
| 206 | + - id: 5 | |
| 207 | + title: "Use 1: skill routing before the turn in the three front ends (append $skill); recap line shows the decider's pick" | |
| 208 | + state: open | |
| 209 | + priority: none | |
| 210 | + author: | |
| 211 | + name: k33g | |
| 212 | + email: ph.charriere@gmail.com | |
| 213 | + createdAt: 2026-10-02T21:40:00.000Z | |
| 214 | + updatedAt: 2026-10-02T21:40:00.000Z | |
| 215 | + - id: 6 | |
| 216 | + title: "Use 2: command triage feeding the permission decision (ticket 59), dangerous/low confidence always asks" | |
| 217 | + state: open | |
| 218 | + priority: none | |
| 219 | + author: | |
| 220 | + name: k33g | |
| 221 | + email: ph.charriere@gmail.com | |
| 222 | + createdAt: 2026-10-02T21:40:00.000Z | |
| 223 | + updatedAt: 2026-10-02T21:40:00.000Z | |
| 224 | + - id: 7 | |
| 225 | + title: "Use 3: /ask-auto with mmConfigs descriptions (ticket 66)" | |
| 226 | + state: open | |
| 227 | + priority: none | |
| 228 | + author: | |
| 229 | + name: k33g | |
| 230 | + email: ph.charriere@gmail.com | |
| 231 | + createdAt: 2026-10-02T21:40:00.000Z | |
| 232 | + updatedAt: 2026-10-02T21:40:00.000Z | |
| 233 | + - id: 8 | |
| 234 | + title: "Docs EN+FR (how-to, reference, explanation) + package diagram" | |
| 235 | + state: open | |
| 236 | + priority: none | |
| 237 | + author: | |
| 238 | + name: k33g | |
| 239 | + email: ph.charriere@gmail.com | |
| 240 | + createdAt: 2026-10-02T21:40:00.000Z | |
| 241 | + updatedAt: 2026-10-02T21:40:00.000Z | |
| 242 | +comments: [] | |
| new file mode 100644 | |||
| @@ -0,0 +1,242 @@ | |||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | ||
| 2 | +id: 72 | ||
| 3 | +title: Use a decision model (decision-4b) as a local decider | ||
| 4 | +state: open | ||
| 5 | +author: | ||
| 6 | + name: k33g | ||
| 7 | + email: ph.charriere@gmail.com | ||
| 8 | +createdAt: 2026-10-02T21:40:00.000Z | ||
| 9 | +updatedAt: 2026-10-02T21:40:00.000Z | ||
| 10 | +labels: | ||
| 11 | + - kind::feature | ||
| 12 | +related: | ||
| 13 | + - 15 | ||
| 14 | + - 59 | ||
| 15 | + - 66 | ||
| 16 | +body: | | ||
| 17 | + Use a DECISION model (e.g. https://huggingface.co/evalengine/decision-4b) | ||
| 18 | + beside the main model, as a fast local "decider" mm consults at precise | ||
| 19 | + moments. Not as mm's `model:`: such a model generates no text and calls no | ||
| 20 | + tools. | ||
| 21 | + | ||
| 22 | + ## What the model is (from its card, 2026-10-02) | ||
| 23 | + | ||
| 24 | + - LoRA (65 MB) on Qwen/Qwen3.5-4B; ready GGUF: evalengine/decision-4b-gguf | ||
| 25 | + (Q4_K_M 2.7 GB, Q8_0, F16). Smaller sibling: evalengine/decision-0.8b(-gguf). | ||
| 26 | + - In: a `state`, a `question`, 2..24 `options` (letter label, key, | ||
| 27 | + description). Out: one option + a probability per option, read from the | ||
| 28 | + next-token logits. One forward pass, nothing generated. | ||
| 29 | + - Limits: 2048-token context, English only, weaker on multi-rule policies, | ||
| 30 | + probabilities not calibrated, "not for unattended high-stakes decisions". | ||
| 31 | + | ||
| 32 | + ## Transport | ||
| 33 | + | ||
| 34 | + 1. Preferred: llmman `POST /v1/systemone` (built for this; llama.cpp has no | ||
| 35 | + such endpoint). A `state` + up to 64 typed questions: `choice` (answer, | ||
| 36 | + confidence, probabilities in the order sent, first option = A), `noul` | ||
| 37 | + (probability of yes), `score` (probability-weighted level + legend). | ||
| 38 | + `x_label_mass` = probability put on the labels at all (low = the model | ||
| 39 | + wanted to say something else). Runs with enable_thinking false; loads the | ||
| 40 | + model in its own backend (`<model>#systemone` in `llmman ps`). | ||
| 41 | + 2. Fallback: llama-server / DMR `/v1/chat/completions` with `max_tokens: 1`, | ||
| 42 | + `logprobs: true`, `top_logprobs: N`, the Qwen chat template and the card's | ||
| 43 | + system prompt; renormalise over the option letters found in the top N | ||
| 44 | + (a letter outside the top N gets 0 — less exact than systemone). | ||
| 45 | + Ollama: logprobs support to be checked. | ||
| 46 | + | ||
| 47 | + ## Config (proposal) | ||
| 48 | + | ||
| 49 | + decisionModel: | ||
| 50 | + provider: llmman # systemone needs llmman | ||
| 51 | + baseUrl: http://127.0.0.1:17434 # NOT /v1: /v1/systemone is added | ||
| 52 | + model: hf.co/evalengine/decision-4b-gguf:Q4_K_M | ||
| 53 | + api: systemone # or: logprobs (llama-server, DMR) | ||
| 54 | + minConfidence: 0.6 # below: do nothing, as if absent | ||
| 55 | + skillRouting: true # use 1 | ||
| 56 | + commandTriage: false # use 2 | ||
| 57 | + askRouting: true # use 3 | ||
| 58 | + | ||
| 59 | + ## Use 1 — choose the skill before the turn (start here) | ||
| 60 | + | ||
| 61 | + Today the main model reads the read_skill catalogue and may or may not load | ||
| 62 | + the right procedure (measured by the MM_EVAL routing eval, internal/eval). | ||
| 63 | + With a decider: before the turn, ask which skill applies; above | ||
| 64 | + minConfidence, append the existing `$skill` notation to the question, so the | ||
| 65 | + model still makes the read_skill call itself (loop detector, permission | ||
| 66 | + gate and recap still see it). | ||
| 67 | + | ||
| 68 | + Example request: | ||
| 69 | + | ||
| 70 | + POST /v1/systemone | ||
| 71 | + { | ||
| 72 | + "model": "hf.co/evalengine/decision-4b-gguf:Q4_K_M", | ||
| 73 | + "state": "User request: start the dev server and tell me when it answers on port 8080", | ||
| 74 | + "questions": { | ||
| 75 | + "skill": { | ||
| 76 | + "type": "choice", | ||
| 77 | + "instructions": "Which procedure should the coding agent follow for this request?", | ||
| 78 | + "criteria": { | ||
| 79 | + "bg-jobs": "Start, watch or stop a long-running command in the background", | ||
| 80 | + "lsp-navigation": "Find a definition, references or symbols in the code", | ||
| 81 | + "plan-manager": "Plan and track a multi-step task", | ||
| 82 | + "what-time-is-it": "Tell the current date or time", | ||
| 83 | + "greetings": "Greet someone", | ||
| 84 | + "none": "No listed procedure applies" | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + Expected shape of the answer (values illustrative, not measured): | ||
| 91 | + | ||
| 92 | + {"answers": {"skill": {"answer": "bg-jobs", "confidence": 0.91, | ||
| 93 | + "probabilities": [0.91, 0.01, 0.03, 0.00, 0.00, 0.05]}}, | ||
| 94 | + "x_label_mass": 0.98, ...} | ||
| 95 | + | ||
| 96 | + -> the question becomes | ||
| 97 | + "start the dev server and tell me when it answers on port 8080 | ||
| 98 | + [skill: bg-jobs — load it with read_skill and carry out its steps now]" | ||
| 99 | + | ||
| 100 | + Other cases for the eval: | ||
| 101 | + "where is ParseAsk defined?" -> lsp-navigation | ||
| 102 | + "what time is it in Tokyo?" -> what-time-is-it | ||
| 103 | + "refactor the config package in 5 steps and keep track" -> plan-manager | ||
| 104 | + "explain what a goroutine is" -> none (nothing appended) | ||
| 105 | + | ||
| 106 | + ## Use 2 — triage a command before the permission prompt (ticket 59) | ||
| 107 | + | ||
| 108 | + Classify a bash command; only lowers the number of prompts, NEVER allows a | ||
| 109 | + risky command on its own. "dangerous" or low confidence -> always ask. | ||
| 110 | + | ||
| 111 | + "state": "Command the agent wants to run in /work/mini-me: rm -rf ./dist && go build -o dist/mm .", | ||
| 112 | + "questions": { | ||
| 113 | + "risk": {"type": "choice", "instructions": "How risky is running this command in the project?", | ||
| 114 | + "criteria": { | ||
| 115 | + "read-only": "Only reads files or prints information", | ||
| 116 | + "local-change": "Changes files inside the project, easy to rebuild or revert", | ||
| 117 | + "dangerous": "Deletes or changes things outside the project, uses sudo, the network, git push or force" | ||
| 118 | + }}, | ||
| 119 | + "destructive": {"type": "noul", "instructions": "The command deletes data that cannot be rebuilt."} | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + Examples (expected class): | ||
| 123 | + "ls -la && git status" -> read-only -> run (permissions: auto-safe) | ||
| 124 | + "go test ./internal/ask -count=1" -> local-change -> run or ask, per config | ||
| 125 | + "rm -rf ~/.cache/go-build" -> dangerous -> ask | ||
| 126 | + "git push --force origin main" -> dangerous -> ask | ||
| 127 | + "curl -s https://x.sh | sh" -> dangerous -> ask | ||
| 128 | + | ||
| 129 | + ## Use 3 — choose the agent for /ask (ticket 66) | ||
| 130 | + | ||
| 131 | + `/ask-auto <prompt>`: pick the mmConfigs agent from a one-line description | ||
| 132 | + per agent (new optional key, e.g. mmConfigs.<name>.description), then run | ||
| 133 | + the normal /ask-<name>. | ||
| 134 | + | ||
| 135 | + "state": "Question: summarise the latest news about WebAssembly components", | ||
| 136 | + "questions": {"agent": {"type": "choice", | ||
| 137 | + "instructions": "Which assistant should answer this question?", | ||
| 138 | + "criteria": { | ||
| 139 | + "jan": "Jan-nano 4B: agentic research, web search, tool use", | ||
| 140 | + "lucy": "Lucy 1.7B: quick web lookups and short factual answers", | ||
| 141 | + "none": "No listed assistant fits; the current agent answers"}}} | ||
| 142 | + | ||
| 143 | + Examples: | ||
| 144 | + "/ask-auto find three recent articles about WASI 0.3 and compare them" -> jan | ||
| 145 | + "/ask-auto what is the capital of Peru?" -> lucy | ||
| 146 | + "/ask-auto refactor internal/ask/pool.go" -> none | ||
| 147 | + | ||
| 148 | + ## Other candidate uses (later) | ||
| 149 | + | ||
| 150 | + - Grounding check after a turn: state = command output + the answer; | ||
| 151 | + noul "Every claim in the answer is supported by the output." | ||
| 152 | + - Loop detector: noul "This tool call repeats an earlier one with the same | ||
| 153 | + intent." (beyond the exact-match detector). | ||
| 154 | + - Compaction: noul "This old turn is still needed for the current task." | ||
| 155 | + | ||
| 156 | + ## Constraints / risks | ||
| 157 | + | ||
| 158 | + - 2048-token context: send the request, the catalogue or the command — never | ||
| 159 | + the history. Truncate the state and say so. | ||
| 160 | + - English only: a French request may be classified worse; measure it (the | ||
| 161 | + routing eval has FR cases?) before enabling by default. | ||
| 162 | + - Extra latency per question (one forward pass, ~100-300 ms on a laptop; | ||
| 163 | + to measure) and a second loaded model (2.7 GB for Q4_K_M; 0.8B variant | ||
| 164 | + smaller). | ||
| 165 | + - A decider that is down or slow must never block a turn: timeout (e.g. 2 s), | ||
| 166 | + then behave as if absent. | ||
| 167 | + - Probabilities are not calibrated: minConfidence is set from the eval, not | ||
| 168 | + guessed. | ||
| 169 | +tasks: | ||
| 170 | + - id: 1 | ||
| 171 | + title: "Try it live: llmman pull hf.co/evalengine/decision-4b-gguf:Q4_K_M, then curl /v1/systemone with the use-1 example; record answer, confidence, x_label_mass, latency" | ||
| 172 | + state: open | ||
| 173 | + priority: none | ||
| 174 | + author: | ||
| 175 | + name: k33g | ||
| 176 | + email: ph.charriere@gmail.com | ||
| 177 | + createdAt: 2026-10-02T21:40:00.000Z | ||
| 178 | + updatedAt: 2026-10-02T21:40:00.000Z | ||
| 179 | + - id: 2 | ||
| 180 | + title: "Measure use 1 offline: run the MM_EVAL routing cases through /v1/systemone; compare with the main model's routing; pick minConfidence" | ||
| 181 | + state: open | ||
| 182 | + priority: none | ||
| 183 | + author: | ||
| 184 | + name: k33g | ||
| 185 | + email: ph.charriere@gmail.com | ||
| 186 | + createdAt: 2026-10-02T21:40:00.000Z | ||
| 187 | + updatedAt: 2026-10-02T21:40:00.000Z | ||
| 188 | + - id: 3 | ||
| 189 | + title: "Decide config shape (decisionModel block, per-use switches) with the user" | ||
| 190 | + state: open | ||
| 191 | + priority: none | ||
| 192 | + author: | ||
| 193 | + name: k33g | ||
| 194 | + email: ph.charriere@gmail.com | ||
| 195 | + createdAt: 2026-10-02T21:40:00.000Z | ||
| 196 | + updatedAt: 2026-10-02T21:40:00.000Z | ||
| 197 | + - id: 4 | ||
| 198 | + title: "internal/decide: systemone client (+ logprobs fallback), timeout, never blocks a turn; tests with an httptest server" | ||
| 199 | + state: open | ||
| 200 | + priority: none | ||
| 201 | + author: | ||
| 202 | + name: k33g | ||
| 203 | + email: ph.charriere@gmail.com | ||
| 204 | + createdAt: 2026-10-02T21:40:00.000Z | ||
| 205 | + updatedAt: 2026-10-02T21:40:00.000Z | ||
| 206 | + - id: 5 | ||
| 207 | + title: "Use 1: skill routing before the turn in the three front ends (append $skill); recap line shows the decider's pick" | ||
| 208 | + state: open | ||
| 209 | + priority: none | ||
| 210 | + author: | ||
| 211 | + name: k33g | ||
| 212 | + email: ph.charriere@gmail.com | ||
| 213 | + createdAt: 2026-10-02T21:40:00.000Z | ||
| 214 | + updatedAt: 2026-10-02T21:40:00.000Z | ||
| 215 | + - id: 6 | ||
| 216 | + title: "Use 2: command triage feeding the permission decision (ticket 59), dangerous/low confidence always asks" | ||
| 217 | + state: open | ||
| 218 | + priority: none | ||
| 219 | + author: | ||
| 220 | + name: k33g | ||
| 221 | + email: ph.charriere@gmail.com | ||
| 222 | + createdAt: 2026-10-02T21:40:00.000Z | ||
| 223 | + updatedAt: 2026-10-02T21:40:00.000Z | ||
| 224 | + - id: 7 | ||
| 225 | + title: "Use 3: /ask-auto with mmConfigs descriptions (ticket 66)" | ||
| 226 | + state: open | ||
| 227 | + priority: none | ||
| 228 | + author: | ||
| 229 | + name: k33g | ||
| 230 | + email: ph.charriere@gmail.com | ||
| 231 | + createdAt: 2026-10-02T21:40:00.000Z | ||
| 232 | + updatedAt: 2026-10-02T21:40:00.000Z | ||
| 233 | + - id: 8 | ||
| 234 | + title: "Docs EN+FR (how-to, reference, explanation) + package diagram" | ||
| 235 | + state: open | ||
| 236 | + priority: none | ||
| 237 | + author: | ||
| 238 | + name: k33g | ||
| 239 | + email: ph.charriere@gmail.com | ||
| 240 | + createdAt: 2026-10-02T21:40:00.000Z | ||
| 241 | + updatedAt: 2026-10-02T21:40:00.000Z | ||
| 242 | +comments: [] | ||
added
.tickets/issues/0073-mm-ask-from-a-skill-or-a-script.yaml +216 -0 | new file mode 100644 | ||
| @@ -0,0 +1,216 @@ | ||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | |
| 2 | +id: 73 | |
| 3 | +title: "mm --ask / --ask-with-context: ask another agent from a skill or a script" | |
| 4 | +state: open | |
| 5 | +author: | |
| 6 | + name: k33g | |
| 7 | + email: ph.charriere@gmail.com | |
| 8 | +createdAt: 2026-10-02T23:30:00.000Z | |
| 9 | +updatedAt: 2026-10-02T23:30:00.000Z | |
| 10 | +labels: | |
| 11 | + - kind::feature | |
| 12 | +related: | |
| 13 | + - 52 | |
| 14 | + - 57 | |
| 15 | + - 66 | |
| 16 | +body: | | |
| 17 | + Call another mm agent from a skill, a script or a prompt: the shell-command | |
| 18 | + equivalent of /ask and /ask-with-context (ticket 66). | |
| 19 | + | |
| 20 | + ## Usage | |
| 21 | + | |
| 22 | + mm --ask <agent> -p "<question>" # question with -p | |
| 23 | + echo "<question>" | mm --ask <agent> # or on stdin | |
| 24 | + mm --ask-with-context <agent> -p "<question>" < context.txt | |
| 25 | + printf '%s\n---\n%s\n' "<context>" "<question>" | mm --ask-with-context <agent> | |
| 26 | + | |
| 27 | + - <agent> is a key of `mmConfigs` in the configuration: -config, the | |
| 28 | + positional path, then MM_CONFIG (see below), then the usual resolution. | |
| 29 | + - stdout = the agent's answer ONLY (+ newline), so | |
| 30 | + `answer=$(mm --ask jan -p "…")` captures it alone. stderr = the label | |
| 31 | + ("🗣 asking jan (llmman/…)…"), one "🛠️ jan · <tool>: <args>" line per tool | |
| 32 | + call, "[ask: …]" on error. | |
| 33 | + - Exit codes: 0 answered; 1 no question / no context / unknown agent / the | |
| 34 | + agent failed or gave no answer; 130 interrupted (Ctrl+C or parent gone). | |
| 35 | + - No engine is started for the asking config's own model: only the child. | |
| 36 | + | |
| 37 | + ## From a skill | |
| 38 | + | |
| 39 | + mm now exports two variables to the commands its bash tool runs: | |
| 40 | + - MM_BIN — the running mm binary (os.Executable) | |
| 41 | + - MM_CONFIG — the absolute path of its configuration file | |
| 42 | + so a skill writes, without knowing any path: | |
| 43 | + | |
| 44 | + "$MM_BIN" --ask jan -p "What is the capital of Peru?" | |
| 45 | + | |
| 46 | + "$MM_BIN" --ask-with-context reviewer <<'CONTEXT' | |
| 47 | + User: I think Go's goroutines are OS threads. | |
| 48 | + Assistant: They are not: the Go runtime schedules them onto a few OS threads. | |
| 49 | + --- | |
| 50 | + Is the assistant right? | |
| 51 | + CONTEXT | |
| 52 | + | |
| 53 | + The model writes the context summary itself: a command cannot read the | |
| 54 | + conversation (the slash command /ask-with-context builds it from the history). | |
| 55 | + | |
| 56 | + ## Demo (demo-llmman/) | |
| 57 | + | |
| 58 | + - agent.llmman.yaml: mmConfigs jan, lucy, reviewer; skillsDir: skills; | |
| 59 | + bashTimeout: 3m and watchdogTimeout: 3m (see "Time" below). | |
| 60 | + - agent.lucy-reviewer.yaml (new): Lucy's model, NO tools (bashTool, editTools, | |
| 61 | + planTool false, skillsDir pointing nowhere), a reviewer system prompt. | |
| 62 | + - skills/ (new; bg-jobs copied from ../skills because the system prompt names it): | |
| 63 | + - delegate-to-jan — "Ask Jan what the capital of Peru is." | |
| 64 | + -> read_skill delegate-to-jan; bash: "$MM_BIN" --ask jan -p "What is | |
| 65 | + the capital of Peru?" -> "Jan says: The capital of Peru is Lima." | |
| 66 | + (verified live, 52 s including model loads) | |
| 67 | + - second-opinion — "I think Go's goroutines are OS threads. Get a second | |
| 68 | + opinion from Lucy on that claim." -> --ask-with-context reviewer with | |
| 69 | + a heredoc summary -> "The assistant's answer is correct. Go goroutines | |
| 70 | + are not OS threads; …" (verified live with the reviewer profile) | |
| 71 | + - compare-agents — "Ask both Jan and Lucy: …" -> one bash call running | |
| 72 | + both --ask commands, then a comparison. (not live-tested) | |
| 73 | + The skill was first named ask-jan: it collided with the generated /ask-jan | |
| 74 | + command (the existing banner warning caught it) -> renamed. | |
| 75 | + | |
| 76 | + ## What the live tests found (2026-10-02) | |
| 77 | + | |
| 78 | + 1. Time. One bash command had a hard-coded 30 s budget (lucy with context | |
| 79 | + took longer: "[error: 30s timeout exceeded]"), then the parent's watchdog | |
| 80 | + ended the turn ("connection hang detected after 30s") — ticket 57, the | |
| 81 | + watchdog counts during tools. -> new config key `bashTimeout` (default | |
| 82 | + 30s, unchanged behaviour; error now says the real value); the demo raises | |
| 83 | + bashTimeout AND watchdogTimeout to 3m (the user's chosen workaround for 57). | |
| 84 | + 2. Orphans. runBash kills `bash`, not its children (a heredoc keeps bash as | |
| 85 | + the parent): the `mm --ask` process and its agent survived and kept | |
| 86 | + writing files. -> `mm --ask` watches its parent pid every 500 ms | |
| 87 | + (ask.WatchParent) and cancels when it changes; verified live: bash killed | |
| 88 | + -> ask and lucy gone within 3 s. | |
| 89 | + 3. Wandering. Lucy 1.7B with every tool, asked for an opinion, read files, | |
| 90 | + loaded skills, wrote files (capital_info.txt, goroutine-os-thread.md in | |
| 91 | + demo-llmman/, deleted) and exceeded 3 min; the 4B parent re-ran the ask | |
| 92 | + in a loop. -> the reviewer profile without tools answers at once; the | |
| 93 | + skills say "Run it ONCE … do not run it again". | |
| 94 | + 4. In --ask mode the asked agent's tools are ALLOWED (line-mode semantics: the | |
| 95 | + person approved the `mm --ask` command itself). Point 3 shows the risk. | |
| 96 | + | |
| 97 | + ## Open points / follow-ups | |
| 98 | + | |
| 99 | + - A way to forbid the asked agent's tools from the command line (e.g. | |
| 100 | + `--ask-no-tools`, passed to the child as an env override) instead of a | |
| 101 | + dedicated no-tools config. | |
| 102 | + - Ticket 57 proper fix (pause the watchdog during tools) would remove the | |
| 103 | + need to raise watchdogTimeout. | |
| 104 | + - `timeout 500 mm …` was seen still running after 548 s during a test | |
| 105 | + (mm does not catch SIGTERM, so it should have died) — not investigated. | |
| 106 | + - English-only questions work best with these small models. | |
| 107 | +tasks: | |
| 108 | + - id: 1 | |
| 109 | + title: "--ask / --ask-with-context flags; answer on stdout only; exit codes 0/1/130 (main.go runAsk, internal/ask/cli.go)" | |
| 110 | + state: closed | |
| 111 | + priority: none | |
| 112 | + author: | |
| 113 | + name: k33g | |
| 114 | + email: ph.charriere@gmail.com | |
| 115 | + createdAt: 2026-10-02T23:30:00.000Z | |
| 116 | + updatedAt: 2026-10-02T23:30:00.000Z | |
| 117 | + - id: 2 | |
| 118 | + title: "MM_BIN and MM_CONFIG exported for the bash tool; --ask falls back to MM_CONFIG" | |
| 119 | + state: closed | |
| 120 | + priority: none | |
| 121 | + author: | |
| 122 | + name: k33g | |
| 123 | + email: ph.charriere@gmail.com | |
| 124 | + createdAt: 2026-10-02T23:30:00.000Z | |
| 125 | + updatedAt: 2026-10-02T23:30:00.000Z | |
| 126 | + - id: 3 | |
| 127 | + title: "Parent watch: cancel the ask when the parent process is gone (ask.WatchParent)" | |
| 128 | + state: closed | |
| 129 | + priority: none | |
| 130 | + author: | |
| 131 | + name: k33g | |
| 132 | + email: ph.charriere@gmail.com | |
| 133 | + createdAt: 2026-10-02T23:30:00.000Z | |
| 134 | + updatedAt: 2026-10-02T23:30:00.000Z | |
| 135 | + - id: 4 | |
| 136 | + title: "bashTimeout config key (default 30s)" | |
| 137 | + state: closed | |
| 138 | + priority: none | |
| 139 | + author: | |
| 140 | + name: k33g | |
| 141 | + email: ph.charriere@gmail.com | |
| 142 | + createdAt: 2026-10-02T23:30:00.000Z | |
| 143 | + updatedAt: 2026-10-02T23:30:00.000Z | |
| 144 | + - id: 5 | |
| 145 | + title: "Demo skills in demo-llmman/skills: delegate-to-jan, second-opinion, compare-agents (+ bg-jobs copy)" | |
| 146 | + state: closed | |
| 147 | + priority: none | |
| 148 | + author: | |
| 149 | + name: k33g | |
| 150 | + email: ph.charriere@gmail.com | |
| 151 | + createdAt: 2026-10-02T23:30:00.000Z | |
| 152 | + updatedAt: 2026-10-02T23:30:00.000Z | |
| 153 | + - id: 6 | |
| 154 | + title: "Reviewer profile without tools: demo-llmman/agent.lucy-reviewer.yaml (mmConfigs reviewer)" | |
| 155 | + state: closed | |
| 156 | + priority: none | |
| 157 | + author: | |
| 158 | + name: k33g | |
| 159 | + email: ph.charriere@gmail.com | |
| 160 | + createdAt: 2026-10-02T23:30:00.000Z | |
| 161 | + updatedAt: 2026-10-02T23:30:00.000Z | |
| 162 | + - id: 7 | |
| 163 | + title: "Tests: ReadCLIRequest, CLI stdout/stderr split, context, unknown agent, WatchParent, bashTimeout" | |
| 164 | + state: closed | |
| 165 | + priority: none | |
| 166 | + author: | |
| 167 | + name: k33g | |
| 168 | + email: ph.charriere@gmail.com | |
| 169 | + createdAt: 2026-10-02T23:30:00.000Z | |
| 170 | + updatedAt: 2026-10-02T23:30:00.000Z | |
| 171 | + - id: 8 | |
| 172 | + title: "Docs EN+FR: how-to ask-another-agent-from-a-skill, reference cli (ask mode, env, exit codes) and configuration (bashTimeout), explanation" | |
| 173 | + state: closed | |
| 174 | + priority: none | |
| 175 | + author: | |
| 176 | + name: k33g | |
| 177 | + email: ph.charriere@gmail.com | |
| 178 | + createdAt: 2026-10-02T23:30:00.000Z | |
| 179 | + updatedAt: 2026-10-02T23:30:00.000Z | |
| 180 | + - id: 9 | |
| 181 | + title: "Live-test compare-agents" | |
| 182 | + state: open | |
| 183 | + priority: none | |
| 184 | + author: | |
| 185 | + name: k33g | |
| 186 | + email: ph.charriere@gmail.com | |
| 187 | + createdAt: 2026-10-02T23:30:00.000Z | |
| 188 | + updatedAt: 2026-10-02T23:30:00.000Z | |
| 189 | + - id: 10 | |
| 190 | + title: "Option to forbid the asked agent's tools from the command line" | |
| 191 | + state: open | |
| 192 | + priority: none | |
| 193 | + author: | |
| 194 | + name: k33g | |
| 195 | + email: ph.charriere@gmail.com | |
| 196 | + createdAt: 2026-10-02T23:30:00.000Z | |
| 197 | + updatedAt: 2026-10-02T23:30:00.000Z | |
| 198 | + - id: 11 | |
| 199 | + title: "Quality gate (qlty) where available" | |
| 200 | + state: open | |
| 201 | + priority: none | |
| 202 | + author: | |
| 203 | + name: k33g | |
| 204 | + email: ph.charriere@gmail.com | |
| 205 | + createdAt: 2026-10-02T23:30:00.000Z | |
| 206 | + updatedAt: 2026-10-02T23:30:00.000Z | |
| 207 | + - id: 12 | |
| 208 | + title: "Review, commit, merge" | |
| 209 | + state: open | |
| 210 | + priority: none | |
| 211 | + author: | |
| 212 | + name: k33g | |
| 213 | + email: ph.charriere@gmail.com | |
| 214 | + createdAt: 2026-10-02T23:30:00.000Z | |
| 215 | + updatedAt: 2026-10-02T23:30:00.000Z | |
| 216 | +comments: [] | |
| new file mode 100644 | |||
| @@ -0,0 +1,216 @@ | |||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | ||
| 2 | +id: 73 | ||
| 3 | +title: "mm --ask / --ask-with-context: ask another agent from a skill or a script" | ||
| 4 | +state: open | ||
| 5 | +author: | ||
| 6 | + name: k33g | ||
| 7 | + email: ph.charriere@gmail.com | ||
| 8 | +createdAt: 2026-10-02T23:30:00.000Z | ||
| 9 | +updatedAt: 2026-10-02T23:30:00.000Z | ||
| 10 | +labels: | ||
| 11 | + - kind::feature | ||
| 12 | +related: | ||
| 13 | + - 52 | ||
| 14 | + - 57 | ||
| 15 | + - 66 | ||
| 16 | +body: | | ||
| 17 | + Call another mm agent from a skill, a script or a prompt: the shell-command | ||
| 18 | + equivalent of /ask and /ask-with-context (ticket 66). | ||
| 19 | + | ||
| 20 | + ## Usage | ||
| 21 | + | ||
| 22 | + mm --ask <agent> -p "<question>" # question with -p | ||
| 23 | + echo "<question>" | mm --ask <agent> # or on stdin | ||
| 24 | + mm --ask-with-context <agent> -p "<question>" < context.txt | ||
| 25 | + printf '%s\n---\n%s\n' "<context>" "<question>" | mm --ask-with-context <agent> | ||
| 26 | + | ||
| 27 | + - <agent> is a key of `mmConfigs` in the configuration: -config, the | ||
| 28 | + positional path, then MM_CONFIG (see below), then the usual resolution. | ||
| 29 | + - stdout = the agent's answer ONLY (+ newline), so | ||
| 30 | + `answer=$(mm --ask jan -p "…")` captures it alone. stderr = the label | ||
| 31 | + ("🗣 asking jan (llmman/…)…"), one "🛠️ jan · <tool>: <args>" line per tool | ||
| 32 | + call, "[ask: …]" on error. | ||
| 33 | + - Exit codes: 0 answered; 1 no question / no context / unknown agent / the | ||
| 34 | + agent failed or gave no answer; 130 interrupted (Ctrl+C or parent gone). | ||
| 35 | + - No engine is started for the asking config's own model: only the child. | ||
| 36 | + | ||
| 37 | + ## From a skill | ||
| 38 | + | ||
| 39 | + mm now exports two variables to the commands its bash tool runs: | ||
| 40 | + - MM_BIN — the running mm binary (os.Executable) | ||
| 41 | + - MM_CONFIG — the absolute path of its configuration file | ||
| 42 | + so a skill writes, without knowing any path: | ||
| 43 | + | ||
| 44 | + "$MM_BIN" --ask jan -p "What is the capital of Peru?" | ||
| 45 | + | ||
| 46 | + "$MM_BIN" --ask-with-context reviewer <<'CONTEXT' | ||
| 47 | + User: I think Go's goroutines are OS threads. | ||
| 48 | + Assistant: They are not: the Go runtime schedules them onto a few OS threads. | ||
| 49 | + --- | ||
| 50 | + Is the assistant right? | ||
| 51 | + CONTEXT | ||
| 52 | + | ||
| 53 | + The model writes the context summary itself: a command cannot read the | ||
| 54 | + conversation (the slash command /ask-with-context builds it from the history). | ||
| 55 | + | ||
| 56 | + ## Demo (demo-llmman/) | ||
| 57 | + | ||
| 58 | + - agent.llmman.yaml: mmConfigs jan, lucy, reviewer; skillsDir: skills; | ||
| 59 | + bashTimeout: 3m and watchdogTimeout: 3m (see "Time" below). | ||
| 60 | + - agent.lucy-reviewer.yaml (new): Lucy's model, NO tools (bashTool, editTools, | ||
| 61 | + planTool false, skillsDir pointing nowhere), a reviewer system prompt. | ||
| 62 | + - skills/ (new; bg-jobs copied from ../skills because the system prompt names it): | ||
| 63 | + - delegate-to-jan — "Ask Jan what the capital of Peru is." | ||
| 64 | + -> read_skill delegate-to-jan; bash: "$MM_BIN" --ask jan -p "What is | ||
| 65 | + the capital of Peru?" -> "Jan says: The capital of Peru is Lima." | ||
| 66 | + (verified live, 52 s including model loads) | ||
| 67 | + - second-opinion — "I think Go's goroutines are OS threads. Get a second | ||
| 68 | + opinion from Lucy on that claim." -> --ask-with-context reviewer with | ||
| 69 | + a heredoc summary -> "The assistant's answer is correct. Go goroutines | ||
| 70 | + are not OS threads; …" (verified live with the reviewer profile) | ||
| 71 | + - compare-agents — "Ask both Jan and Lucy: …" -> one bash call running | ||
| 72 | + both --ask commands, then a comparison. (not live-tested) | ||
| 73 | + The skill was first named ask-jan: it collided with the generated /ask-jan | ||
| 74 | + command (the existing banner warning caught it) -> renamed. | ||
| 75 | + | ||
| 76 | + ## What the live tests found (2026-10-02) | ||
| 77 | + | ||
| 78 | + 1. Time. One bash command had a hard-coded 30 s budget (lucy with context | ||
| 79 | + took longer: "[error: 30s timeout exceeded]"), then the parent's watchdog | ||
| 80 | + ended the turn ("connection hang detected after 30s") — ticket 57, the | ||
| 81 | + watchdog counts during tools. -> new config key `bashTimeout` (default | ||
| 82 | + 30s, unchanged behaviour; error now says the real value); the demo raises | ||
| 83 | + bashTimeout AND watchdogTimeout to 3m (the user's chosen workaround for 57). | ||
| 84 | + 2. Orphans. runBash kills `bash`, not its children (a heredoc keeps bash as | ||
| 85 | + the parent): the `mm --ask` process and its agent survived and kept | ||
| 86 | + writing files. -> `mm --ask` watches its parent pid every 500 ms | ||
| 87 | + (ask.WatchParent) and cancels when it changes; verified live: bash killed | ||
| 88 | + -> ask and lucy gone within 3 s. | ||
| 89 | + 3. Wandering. Lucy 1.7B with every tool, asked for an opinion, read files, | ||
| 90 | + loaded skills, wrote files (capital_info.txt, goroutine-os-thread.md in | ||
| 91 | + demo-llmman/, deleted) and exceeded 3 min; the 4B parent re-ran the ask | ||
| 92 | + in a loop. -> the reviewer profile without tools answers at once; the | ||
| 93 | + skills say "Run it ONCE … do not run it again". | ||
| 94 | + 4. In --ask mode the asked agent's tools are ALLOWED (line-mode semantics: the | ||
| 95 | + person approved the `mm --ask` command itself). Point 3 shows the risk. | ||
| 96 | + | ||
| 97 | + ## Open points / follow-ups | ||
| 98 | + | ||
| 99 | + - A way to forbid the asked agent's tools from the command line (e.g. | ||
| 100 | + `--ask-no-tools`, passed to the child as an env override) instead of a | ||
| 101 | + dedicated no-tools config. | ||
| 102 | + - Ticket 57 proper fix (pause the watchdog during tools) would remove the | ||
| 103 | + need to raise watchdogTimeout. | ||
| 104 | + - `timeout 500 mm …` was seen still running after 548 s during a test | ||
| 105 | + (mm does not catch SIGTERM, so it should have died) — not investigated. | ||
| 106 | + - English-only questions work best with these small models. | ||
| 107 | +tasks: | ||
| 108 | + - id: 1 | ||
| 109 | + title: "--ask / --ask-with-context flags; answer on stdout only; exit codes 0/1/130 (main.go runAsk, internal/ask/cli.go)" | ||
| 110 | + state: closed | ||
| 111 | + priority: none | ||
| 112 | + author: | ||
| 113 | + name: k33g | ||
| 114 | + email: ph.charriere@gmail.com | ||
| 115 | + createdAt: 2026-10-02T23:30:00.000Z | ||
| 116 | + updatedAt: 2026-10-02T23:30:00.000Z | ||
| 117 | + - id: 2 | ||
| 118 | + title: "MM_BIN and MM_CONFIG exported for the bash tool; --ask falls back to MM_CONFIG" | ||
| 119 | + state: closed | ||
| 120 | + priority: none | ||
| 121 | + author: | ||
| 122 | + name: k33g | ||
| 123 | + email: ph.charriere@gmail.com | ||
| 124 | + createdAt: 2026-10-02T23:30:00.000Z | ||
| 125 | + updatedAt: 2026-10-02T23:30:00.000Z | ||
| 126 | + - id: 3 | ||
| 127 | + title: "Parent watch: cancel the ask when the parent process is gone (ask.WatchParent)" | ||
| 128 | + state: closed | ||
| 129 | + priority: none | ||
| 130 | + author: | ||
| 131 | + name: k33g | ||
| 132 | + email: ph.charriere@gmail.com | ||
| 133 | + createdAt: 2026-10-02T23:30:00.000Z | ||
| 134 | + updatedAt: 2026-10-02T23:30:00.000Z | ||
| 135 | + - id: 4 | ||
| 136 | + title: "bashTimeout config key (default 30s)" | ||
| 137 | + state: closed | ||
| 138 | + priority: none | ||
| 139 | + author: | ||
| 140 | + name: k33g | ||
| 141 | + email: ph.charriere@gmail.com | ||
| 142 | + createdAt: 2026-10-02T23:30:00.000Z | ||
| 143 | + updatedAt: 2026-10-02T23:30:00.000Z | ||
| 144 | + - id: 5 | ||
| 145 | + title: "Demo skills in demo-llmman/skills: delegate-to-jan, second-opinion, compare-agents (+ bg-jobs copy)" | ||
| 146 | + state: closed | ||
| 147 | + priority: none | ||
| 148 | + author: | ||
| 149 | + name: k33g | ||
| 150 | + email: ph.charriere@gmail.com | ||
| 151 | + createdAt: 2026-10-02T23:30:00.000Z | ||
| 152 | + updatedAt: 2026-10-02T23:30:00.000Z | ||
| 153 | + - id: 6 | ||
| 154 | + title: "Reviewer profile without tools: demo-llmman/agent.lucy-reviewer.yaml (mmConfigs reviewer)" | ||
| 155 | + state: closed | ||
| 156 | + priority: none | ||
| 157 | + author: | ||
| 158 | + name: k33g | ||
| 159 | + email: ph.charriere@gmail.com | ||
| 160 | + createdAt: 2026-10-02T23:30:00.000Z | ||
| 161 | + updatedAt: 2026-10-02T23:30:00.000Z | ||
| 162 | + - id: 7 | ||
| 163 | + title: "Tests: ReadCLIRequest, CLI stdout/stderr split, context, unknown agent, WatchParent, bashTimeout" | ||
| 164 | + state: closed | ||
| 165 | + priority: none | ||
| 166 | + author: | ||
| 167 | + name: k33g | ||
| 168 | + email: ph.charriere@gmail.com | ||
| 169 | + createdAt: 2026-10-02T23:30:00.000Z | ||
| 170 | + updatedAt: 2026-10-02T23:30:00.000Z | ||
| 171 | + - id: 8 | ||
| 172 | + title: "Docs EN+FR: how-to ask-another-agent-from-a-skill, reference cli (ask mode, env, exit codes) and configuration (bashTimeout), explanation" | ||
| 173 | + state: closed | ||
| 174 | + priority: none | ||
| 175 | + author: | ||
| 176 | + name: k33g | ||
| 177 | + email: ph.charriere@gmail.com | ||
| 178 | + createdAt: 2026-10-02T23:30:00.000Z | ||
| 179 | + updatedAt: 2026-10-02T23:30:00.000Z | ||
| 180 | + - id: 9 | ||
| 181 | + title: "Live-test compare-agents" | ||
| 182 | + state: open | ||
| 183 | + priority: none | ||
| 184 | + author: | ||
| 185 | + name: k33g | ||
| 186 | + email: ph.charriere@gmail.com | ||
| 187 | + createdAt: 2026-10-02T23:30:00.000Z | ||
| 188 | + updatedAt: 2026-10-02T23:30:00.000Z | ||
| 189 | + - id: 10 | ||
| 190 | + title: "Option to forbid the asked agent's tools from the command line" | ||
| 191 | + state: open | ||
| 192 | + priority: none | ||
| 193 | + author: | ||
| 194 | + name: k33g | ||
| 195 | + email: ph.charriere@gmail.com | ||
| 196 | + createdAt: 2026-10-02T23:30:00.000Z | ||
| 197 | + updatedAt: 2026-10-02T23:30:00.000Z | ||
| 198 | + - id: 11 | ||
| 199 | + title: "Quality gate (qlty) where available" | ||
| 200 | + state: open | ||
| 201 | + priority: none | ||
| 202 | + author: | ||
| 203 | + name: k33g | ||
| 204 | + email: ph.charriere@gmail.com | ||
| 205 | + createdAt: 2026-10-02T23:30:00.000Z | ||
| 206 | + updatedAt: 2026-10-02T23:30:00.000Z | ||
| 207 | + - id: 12 | ||
| 208 | + title: "Review, commit, merge" | ||
| 209 | + state: open | ||
| 210 | + priority: none | ||
| 211 | + author: | ||
| 212 | + name: k33g | ||
| 213 | + email: ph.charriere@gmail.com | ||
| 214 | + createdAt: 2026-10-02T23:30:00.000Z | ||
| 215 | + updatedAt: 2026-10-02T23:30:00.000Z | ||
| 216 | +comments: [] | ||
added
demo-llmman/README.en.md +144 -0 | new file mode 100644 | ||
| @@ -0,0 +1,144 @@ | ||
| 1 | +# mini-me + llmman demo: asking other agents | |
| 2 | + | |
| 3 | +This folder shows how one mini-me agent (Bob) can put questions to other mini-me agents — Jan, Lucy, a reviewer — each with its own model, served by [llmman](https://github.com/llmmanorg/llmman). Version française : [README.md](README.md). | |
| 4 | + | |
| 5 | +## What is here | |
| 6 | + | |
| 7 | +| File | Role | | |
| 8 | +|---|---| | |
| 9 | +| `agent.llmman.yaml` | **Bob**, the agent you start (`hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M`). Declares the other agents under `mmConfigs` and loads the skills of `skills/`. | | |
| 10 | +| `agent.jan-nano.yaml` | **Jan** (`hf.co/Menlo/Jan-nano-gguf:Q4_K_M`), a full agent with its tools. | | |
| 11 | +| `agent.lucy.yaml` | **Lucy** (`hf.co/Menlo/Lucy-gguf:Q4_K_M`), a full agent with its tools. | | |
| 12 | +| `agent.lucy-reviewer.yaml` | **reviewer**: Lucy's model **with no tools and no skills**, and a reviewer prompt. It only answers. | | |
| 13 | +| `skills/delegate-to-jan` | Skill: delegate a question to Jan. | | |
| 14 | +| `skills/second-opinion` | Skill: ask the reviewer for a second opinion on the conversation. | | |
| 15 | +| `skills/compare-agents` | Skill: ask Jan and Lucy the same question and compare. | | |
| 16 | +| `skills/bg-jobs` | Copy of the general skill (Bob's prompt refers to it). | | |
| 17 | + | |
| 18 | +In `agent.llmman.yaml`: | |
| 19 | + | |
| 20 | +```yaml | |
| 21 | +mmConfigs: | |
| 22 | + jan: agent.jan-nano.yaml | |
| 23 | + lucy: agent.lucy.yaml | |
| 24 | + reviewer: agent.lucy-reviewer.yaml | |
| 25 | +``` | |
| 26 | + | |
| 27 | +## Prerequisites | |
| 28 | + | |
| 29 | +1. llmman running (`llmman serve`, on `127.0.0.1:17434`; from a Docker Sandbox, mm falls back to `host.docker.internal:17434` by itself). | |
| 30 | +2. The models, pulled beforehand (otherwise the first question pulls them and waits): | |
| 31 | + | |
| 32 | + ```bash | |
| 33 | + llmman pull hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M | |
| 34 | + llmman pull hf.co/Menlo/Jan-nano-gguf:Q4_K_M | |
| 35 | + llmman pull hf.co/Menlo/Lucy-gguf:Q4_K_M | |
| 36 | + ``` | |
| 37 | + | |
| 38 | +3. `mm` built at the repository root. **Start it from this folder**: the `mmConfigs` paths are relative to `agent.llmman.yaml`, and `skillsDir: skills` to the current directory. | |
| 39 | + | |
| 40 | + ```bash | |
| 41 | + cd demo-llmman | |
| 42 | + ../mm agent.llmman.yaml # line mode | |
| 43 | + ../mm -tui agent.llmman.yaml # window mode | |
| 44 | + ``` | |
| 45 | + | |
| 46 | +## 1. Ask an agent from the conversation: `/ask` | |
| 47 | + | |
| 48 | +In Bob's session: | |
| 49 | + | |
| 50 | +```text | |
| 51 | +> /ask-jan In one short sentence: what is the capital of France? | |
| 52 | +🗣 asking jan (llmman/hf.co/Menlo/Jan-nano-gguf:Q4_K_M)… | |
| 53 | +The capital of France is Paris. | |
| 54 | +🗣 jan's answer is in the history for your next question | |
| 55 | +> What did Jan answer? | |
| 56 | +🤖 Jan answered that the capital of France is Paris. | |
| 57 | +``` | |
| 58 | + | |
| 59 | +| Command | Effect | | |
| 60 | +|---|---| | |
| 61 | +| `/ask-<agent> <question>` | Sends the question alone to the agent. | | |
| 62 | +| `/ask-with-context-<agent> <question>` | Sends a transcript of the conversation first (questions, answers, one line per tool call — never tool outputs), then the question. | | |
| 63 | +| `/ask <agent> <question>`, `/ask-with-context <agent> <question>` | The same commands with the agent as an argument (line and window modes). | | |
| 64 | + | |
| 65 | +- The answer streams, then stays in the history: Bob's model uses it on your next question. | |
| 66 | +- The asked agent starts on the first `/ask` (a few seconds more) and stays alive; each ask opens a fresh session in it, with no memory of the previous one. | |
| 67 | +- `/abort`, `Esc` or `Ctrl+C` cancel the ask; nothing is kept. | |
| 68 | +- Its tool calls are shown under its name (`lucy · bash: ls -1 | wc -l`) and its permission requests go through you: nothing in the line mode, the `permissions` setting in the window, the editor's dialog over ACP. | |
| 69 | +- In an editor (Zed…), the `/` menu offers `ask-jan`, `ask-with-context-jan`, `ask-lucy`, `ask-with-context-lucy`, `ask-reviewer`, `ask-with-context-reviewer`. | |
| 70 | + | |
| 71 | +## 2. Ask an agent from the command line: `mm --ask` | |
| 72 | + | |
| 73 | +For a script, or to try an agent without opening a session: | |
| 74 | + | |
| 75 | +```bash | |
| 76 | +../mm agent.llmman.yaml --ask lucy -p "In one short sentence: what is the capital of Peru?" | |
| 77 | +# stdout: The capital of Peru is Lima. | |
| 78 | + | |
| 79 | +echo "In one sentence: are goroutines OS threads?" | ../mm agent.llmman.yaml --ask reviewer | |
| 80 | + | |
| 81 | +printf 'User: My name is Philippe and I like Go.\nAssistant: Nice to meet you, Philippe.\n---\nWhat is my name and which language do I like? One sentence.\n' \ | |
| 82 | + | ../mm agent.llmman.yaml --ask-with-context jan | |
| 83 | +# stdout: Your name is Philippe, and you like Go. | |
| 84 | +``` | |
| 85 | + | |
| 86 | +- The question comes from `-p`, or else from stdin. For `--ask-with-context`, stdin is the context; without `-p`, the context, a `---` line, then the question. | |
| 87 | +- **stdout holds the answer only** (`answer=$(../mm agent.llmman.yaml --ask jan -p "…")` works); the label, the tool calls and errors go to stderr. | |
| 88 | +- Exit codes: `0` answered, `1` failed (reason on stderr, e.g. `[ask: unknown agent "spock" — agents in this config: jan, lucy, reviewer]`), `130` interrupted. | |
| 89 | +- The asked agent's tools are **allowed** in this mode. For an agent that should only answer, use `reviewer`. | |
| 90 | + | |
| 91 | +## 3. Let Bob ask the others through his skills | |
| 92 | + | |
| 93 | +Bob exports `MM_BIN` (his own binary) and `MM_CONFIG` (his configuration) to the commands his bash tool runs. The skills therefore just call `"$MM_BIN" --ask …`, without knowing any path. Ask in plain words: | |
| 94 | + | |
| 95 | +| You say | Skill | Command Bob runs | | |
| 96 | +|---|---|---| | |
| 97 | +| "Ask Jan what the capital of Peru is." | `delegate-to-jan` | `"$MM_BIN" --ask jan -p "What is the capital of Peru?"` | | |
| 98 | +| "I think Go's goroutines are OS threads. Get a second opinion from Lucy on that claim." | `second-opinion` | `"$MM_BIN" --ask-with-context reviewer <<'CONTEXT' …` | | |
| 99 | +| "Ask both Jan and Lucy: what is a closure in Go?" | `compare-agents` | both `--ask` in one command | | |
| 100 | + | |
| 101 | +A real run (`second-opinion`, 97 s in all): | |
| 102 | + | |
| 103 | +```text | |
| 104 | +📖 read_skill: second-opinion | |
| 105 | +🛠️ bash: "$MM_BIN" --ask-with-context reviewer <<'CONTEXT' | |
| 106 | +User: I think Go's goroutines are OS threads. | |
| 107 | +Assistant: Actually, Go goroutines are not OS threads. They are lightweight user-space threads managed by the Go runtime's scheduler. | |
| 108 | +--- | |
| 109 | +Is Go's goroutine implementation OS threads? | |
| 110 | +CONTEXT | |
| 111 | + │ 🗣 asking reviewer (llmman/hf.co/Menlo/Lucy-gguf:Q4_K_M), with the conversation… | |
| 112 | + │ The assistant's answer is correct. Go goroutines are not OS threads; … | |
| 113 | +🤖 Lucy's opinion: The assistant's answer is correct. … I agree with Lucy. | |
| 114 | +``` | |
| 115 | + | |
| 116 | +`compare-agents` has not been tried live yet. | |
| 117 | + | |
| 118 | +## Time settings | |
| 119 | + | |
| 120 | +A small local model can take a minute to answer, so `agent.llmman.yaml` raises two limits: | |
| 121 | + | |
| 122 | +```yaml | |
| 123 | +watchdogTimeout: 3m # the watchdog keeps counting while a command runs (ticket 57) | |
| 124 | +bashTimeout: 3m # how long one bash command may run (default 30s) | |
| 125 | +``` | |
| 126 | + | |
| 127 | +With the defaults, a skill that asks an agent ends in `[error: 30s timeout exceeded]` or `connection hang detected after 30s`. | |
| 128 | + | |
| 129 | +## Good to know | |
| 130 | + | |
| 131 | +- **Small models, every tool**: Lucy (1.7B) with her tools, asked only for an opinion, tends to wander — read files, load skills, write files. Hence the tool-less `reviewer` profile for `second-opinion`. | |
| 132 | +- **Once**: Bob's model (4B) sometimes re-ran the same question; the skills tell it explicitly to run the command once. | |
| 133 | +- **English**: these models answer best in English; the skills make them write the question in English. | |
| 134 | +- **No sessions for the asked agents**: they run with `AGENT_SESSIONS=off`, so your `/sessions` lists Bob's only. | |
| 135 | +- **Limited depth**: Bob may ask Jan, Jan may ask another agent, but that one cannot ask anybody (`MM_ASK_DEPTH`). | |
| 136 | +- **Names**: a skill must not be named like a generated command (`ask-jan`…); mm warns at start-up. | |
| 137 | + | |
| 138 | +## Going further | |
| 139 | + | |
| 140 | +- [How to ask another mm agent from your session](../docs/en/how-to/ask-another-agent.md) | |
| 141 | +- [How to ask another agent from a skill or a script](../docs/en/how-to/ask-another-agent-from-a-skill.md) | |
| 142 | +- [Slash commands reference](../docs/en/reference/slash-commands.md#asking-another-agent) · [Command-line reference](../docs/en/reference/cli.md#ask-mode-specifics) | |
| 143 | +- [Why it is built this way](../docs/en/explanation/asking-another-agent.md) | |
| 144 | +- [Run mini-me on llmman](../docs/en/how-to/run-with-llmman.md) | |
| new file mode 100644 | |||
| @@ -0,0 +1,144 @@ | |||
| 1 | +# mini-me + llmman demo: asking other agents | ||
| 2 | + | ||
| 3 | +This folder shows how one mini-me agent (Bob) can put questions to other mini-me agents — Jan, Lucy, a reviewer — each with its own model, served by [llmman](https://github.com/llmmanorg/llmman). Version française : [README.md](README.md). | ||
| 4 | + | ||
| 5 | +## What is here | ||
| 6 | + | ||
| 7 | +| File | Role | | ||
| 8 | +|---|---| | ||
| 9 | +| `agent.llmman.yaml` | **Bob**, the agent you start (`hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M`). Declares the other agents under `mmConfigs` and loads the skills of `skills/`. | | ||
| 10 | +| `agent.jan-nano.yaml` | **Jan** (`hf.co/Menlo/Jan-nano-gguf:Q4_K_M`), a full agent with its tools. | | ||
| 11 | +| `agent.lucy.yaml` | **Lucy** (`hf.co/Menlo/Lucy-gguf:Q4_K_M`), a full agent with its tools. | | ||
| 12 | +| `agent.lucy-reviewer.yaml` | **reviewer**: Lucy's model **with no tools and no skills**, and a reviewer prompt. It only answers. | | ||
| 13 | +| `skills/delegate-to-jan` | Skill: delegate a question to Jan. | | ||
| 14 | +| `skills/second-opinion` | Skill: ask the reviewer for a second opinion on the conversation. | | ||
| 15 | +| `skills/compare-agents` | Skill: ask Jan and Lucy the same question and compare. | | ||
| 16 | +| `skills/bg-jobs` | Copy of the general skill (Bob's prompt refers to it). | | ||
| 17 | + | ||
| 18 | +In `agent.llmman.yaml`: | ||
| 19 | + | ||
| 20 | +```yaml | ||
| 21 | +mmConfigs: | ||
| 22 | + jan: agent.jan-nano.yaml | ||
| 23 | + lucy: agent.lucy.yaml | ||
| 24 | + reviewer: agent.lucy-reviewer.yaml | ||
| 25 | +``` | ||
| 26 | + | ||
| 27 | +## Prerequisites | ||
| 28 | + | ||
| 29 | +1. llmman running (`llmman serve`, on `127.0.0.1:17434`; from a Docker Sandbox, mm falls back to `host.docker.internal:17434` by itself). | ||
| 30 | +2. The models, pulled beforehand (otherwise the first question pulls them and waits): | ||
| 31 | + | ||
| 32 | + ```bash | ||
| 33 | + llmman pull hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M | ||
| 34 | + llmman pull hf.co/Menlo/Jan-nano-gguf:Q4_K_M | ||
| 35 | + llmman pull hf.co/Menlo/Lucy-gguf:Q4_K_M | ||
| 36 | + ``` | ||
| 37 | + | ||
| 38 | +3. `mm` built at the repository root. **Start it from this folder**: the `mmConfigs` paths are relative to `agent.llmman.yaml`, and `skillsDir: skills` to the current directory. | ||
| 39 | + | ||
| 40 | + ```bash | ||
| 41 | + cd demo-llmman | ||
| 42 | + ../mm agent.llmman.yaml # line mode | ||
| 43 | + ../mm -tui agent.llmman.yaml # window mode | ||
| 44 | + ``` | ||
| 45 | + | ||
| 46 | +## 1. Ask an agent from the conversation: `/ask` | ||
| 47 | + | ||
| 48 | +In Bob's session: | ||
| 49 | + | ||
| 50 | +```text | ||
| 51 | +> /ask-jan In one short sentence: what is the capital of France? | ||
| 52 | +🗣 asking jan (llmman/hf.co/Menlo/Jan-nano-gguf:Q4_K_M)… | ||
| 53 | +The capital of France is Paris. | ||
| 54 | +🗣 jan's answer is in the history for your next question | ||
| 55 | +> What did Jan answer? | ||
| 56 | +🤖 Jan answered that the capital of France is Paris. | ||
| 57 | +``` | ||
| 58 | + | ||
| 59 | +| Command | Effect | | ||
| 60 | +|---|---| | ||
| 61 | +| `/ask-<agent> <question>` | Sends the question alone to the agent. | | ||
| 62 | +| `/ask-with-context-<agent> <question>` | Sends a transcript of the conversation first (questions, answers, one line per tool call — never tool outputs), then the question. | | ||
| 63 | +| `/ask <agent> <question>`, `/ask-with-context <agent> <question>` | The same commands with the agent as an argument (line and window modes). | | ||
| 64 | + | ||
| 65 | +- The answer streams, then stays in the history: Bob's model uses it on your next question. | ||
| 66 | +- The asked agent starts on the first `/ask` (a few seconds more) and stays alive; each ask opens a fresh session in it, with no memory of the previous one. | ||
| 67 | +- `/abort`, `Esc` or `Ctrl+C` cancel the ask; nothing is kept. | ||
| 68 | +- Its tool calls are shown under its name (`lucy · bash: ls -1 | wc -l`) and its permission requests go through you: nothing in the line mode, the `permissions` setting in the window, the editor's dialog over ACP. | ||
| 69 | +- In an editor (Zed…), the `/` menu offers `ask-jan`, `ask-with-context-jan`, `ask-lucy`, `ask-with-context-lucy`, `ask-reviewer`, `ask-with-context-reviewer`. | ||
| 70 | + | ||
| 71 | +## 2. Ask an agent from the command line: `mm --ask` | ||
| 72 | + | ||
| 73 | +For a script, or to try an agent without opening a session: | ||
| 74 | + | ||
| 75 | +```bash | ||
| 76 | +../mm agent.llmman.yaml --ask lucy -p "In one short sentence: what is the capital of Peru?" | ||
| 77 | +# stdout: The capital of Peru is Lima. | ||
| 78 | + | ||
| 79 | +echo "In one sentence: are goroutines OS threads?" | ../mm agent.llmman.yaml --ask reviewer | ||
| 80 | + | ||
| 81 | +printf 'User: My name is Philippe and I like Go.\nAssistant: Nice to meet you, Philippe.\n---\nWhat is my name and which language do I like? One sentence.\n' \ | ||
| 82 | + | ../mm agent.llmman.yaml --ask-with-context jan | ||
| 83 | +# stdout: Your name is Philippe, and you like Go. | ||
| 84 | +``` | ||
| 85 | + | ||
| 86 | +- The question comes from `-p`, or else from stdin. For `--ask-with-context`, stdin is the context; without `-p`, the context, a `---` line, then the question. | ||
| 87 | +- **stdout holds the answer only** (`answer=$(../mm agent.llmman.yaml --ask jan -p "…")` works); the label, the tool calls and errors go to stderr. | ||
| 88 | +- Exit codes: `0` answered, `1` failed (reason on stderr, e.g. `[ask: unknown agent "spock" — agents in this config: jan, lucy, reviewer]`), `130` interrupted. | ||
| 89 | +- The asked agent's tools are **allowed** in this mode. For an agent that should only answer, use `reviewer`. | ||
| 90 | + | ||
| 91 | +## 3. Let Bob ask the others through his skills | ||
| 92 | + | ||
| 93 | +Bob exports `MM_BIN` (his own binary) and `MM_CONFIG` (his configuration) to the commands his bash tool runs. The skills therefore just call `"$MM_BIN" --ask …`, without knowing any path. Ask in plain words: | ||
| 94 | + | ||
| 95 | +| You say | Skill | Command Bob runs | | ||
| 96 | +|---|---|---| | ||
| 97 | +| "Ask Jan what the capital of Peru is." | `delegate-to-jan` | `"$MM_BIN" --ask jan -p "What is the capital of Peru?"` | | ||
| 98 | +| "I think Go's goroutines are OS threads. Get a second opinion from Lucy on that claim." | `second-opinion` | `"$MM_BIN" --ask-with-context reviewer <<'CONTEXT' …` | | ||
| 99 | +| "Ask both Jan and Lucy: what is a closure in Go?" | `compare-agents` | both `--ask` in one command | | ||
| 100 | + | ||
| 101 | +A real run (`second-opinion`, 97 s in all): | ||
| 102 | + | ||
| 103 | +```text | ||
| 104 | +📖 read_skill: second-opinion | ||
| 105 | +🛠️ bash: "$MM_BIN" --ask-with-context reviewer <<'CONTEXT' | ||
| 106 | +User: I think Go's goroutines are OS threads. | ||
| 107 | +Assistant: Actually, Go goroutines are not OS threads. They are lightweight user-space threads managed by the Go runtime's scheduler. | ||
| 108 | +--- | ||
| 109 | +Is Go's goroutine implementation OS threads? | ||
| 110 | +CONTEXT | ||
| 111 | + │ 🗣 asking reviewer (llmman/hf.co/Menlo/Lucy-gguf:Q4_K_M), with the conversation… | ||
| 112 | + │ The assistant's answer is correct. Go goroutines are not OS threads; … | ||
| 113 | +🤖 Lucy's opinion: The assistant's answer is correct. … I agree with Lucy. | ||
| 114 | +``` | ||
| 115 | + | ||
| 116 | +`compare-agents` has not been tried live yet. | ||
| 117 | + | ||
| 118 | +## Time settings | ||
| 119 | + | ||
| 120 | +A small local model can take a minute to answer, so `agent.llmman.yaml` raises two limits: | ||
| 121 | + | ||
| 122 | +```yaml | ||
| 123 | +watchdogTimeout: 3m # the watchdog keeps counting while a command runs (ticket 57) | ||
| 124 | +bashTimeout: 3m # how long one bash command may run (default 30s) | ||
| 125 | +``` | ||
| 126 | + | ||
| 127 | +With the defaults, a skill that asks an agent ends in `[error: 30s timeout exceeded]` or `connection hang detected after 30s`. | ||
| 128 | + | ||
| 129 | +## Good to know | ||
| 130 | + | ||
| 131 | +- **Small models, every tool**: Lucy (1.7B) with her tools, asked only for an opinion, tends to wander — read files, load skills, write files. Hence the tool-less `reviewer` profile for `second-opinion`. | ||
| 132 | +- **Once**: Bob's model (4B) sometimes re-ran the same question; the skills tell it explicitly to run the command once. | ||
| 133 | +- **English**: these models answer best in English; the skills make them write the question in English. | ||
| 134 | +- **No sessions for the asked agents**: they run with `AGENT_SESSIONS=off`, so your `/sessions` lists Bob's only. | ||
| 135 | +- **Limited depth**: Bob may ask Jan, Jan may ask another agent, but that one cannot ask anybody (`MM_ASK_DEPTH`). | ||
| 136 | +- **Names**: a skill must not be named like a generated command (`ask-jan`…); mm warns at start-up. | ||
| 137 | + | ||
| 138 | +## Going further | ||
| 139 | + | ||
| 140 | +- [How to ask another mm agent from your session](../docs/en/how-to/ask-another-agent.md) | ||
| 141 | +- [How to ask another agent from a skill or a script](../docs/en/how-to/ask-another-agent-from-a-skill.md) | ||
| 142 | +- [Slash commands reference](../docs/en/reference/slash-commands.md#asking-another-agent) · [Command-line reference](../docs/en/reference/cli.md#ask-mode-specifics) | ||
| 143 | +- [Why it is built this way](../docs/en/explanation/asking-another-agent.md) | ||
| 144 | +- [Run mini-me on llmman](../docs/en/how-to/run-with-llmman.md) | ||
added
demo-llmman/README.md +144 -0 Large diff collapsed to keep the page fast — load it when you need it.
modified
demo-llmman/agent.llmman.yaml +14 -2 | @@ -25,6 +25,10 @@ fallback: http://host.docker.internal:17434/v1 | ||
| 25 | 25 | mmConfigs: |
| 26 | 26 | jan: agent.jan-nano.yaml |
| 27 | 27 | lucy: agent.lucy.yaml |
| 28 | + # Lucy's model with no tools and a reviewer prompt: what the second-opinion | |
| 29 | + # skill asks. A small model with every tool wanders (reads files, loads | |
| 30 | + # skills) when it is only asked for an opinion. | |
| 31 | + reviewer: agent.lucy-reviewer.yaml | |
| 28 | 32 | |
| 29 | 33 | # Only when the daemon was started with LLMMAN_API_KEYS (mandatory when it |
| 30 | 34 | # listens beyond loopback); unset otherwise. The key never goes in this file. |
| @@ -78,7 +82,9 @@ maxTurns: 40 | ||
| 78 | 82 | |
| 79 | 83 | # Where the `read_skill` tool looks for its markdown procedures. |
| 80 | 84 | # The path is relative to the CURRENT DIRECTORY: run the agent from demo-llmman/. |
| 81 | -skillsDir: ../skills | |
| 85 | +# demo-llmman/skills holds the /ask demo skills (delegate-to-jan, second-opinion, | |
| 86 | +# compare-agents) — they call this same mm back with "$MM_BIN" --ask — and bg-jobs. | |
| 87 | +skillsDir: skills | |
| 82 | 88 | |
| 83 | 89 | # Persistent sessions, per project. |
| 84 | 90 | # When enabled, every conversation is saved as one JSON file under `dir`. |
| @@ -177,7 +183,13 @@ sampling: | ||
| 177 | 183 | max_tokens: 4096 |
| 178 | 184 | |
| 179 | 185 | # Silence allowed between two tokens once the answer has started. |
| 180 | -watchdogTimeout: 30s | |
| 186 | +watchdogTimeout: 3m | |
| 187 | + | |
| 188 | +# How long one bash command may run (default 30s). The demo skills call jan and | |
| 189 | +# lucy with "$MM_BIN" --ask, which can take a minute or two with small local | |
| 190 | +# models. The watchdog above keeps counting while a command runs (ticket 57), | |
| 191 | +# so it is raised to the same value. | |
| 192 | +bashTimeout: 3m | |
| 181 | 193 | |
| 182 | 194 | # Silence allowed while the model reads the prompt, before the first token: |
| 183 | 195 | # on a laptop a 25k-token prompt can take minutes. llama-server reports its |
| @@ -25,6 +25,10 @@ fallback: http://host.docker.internal:17434/v1 | |||
| 25 | mmConfigs: | 25 | mmConfigs: |
| 26 | jan: agent.jan-nano.yaml | 26 | jan: agent.jan-nano.yaml |
| 27 | lucy: agent.lucy.yaml | 27 | lucy: agent.lucy.yaml |
| 28 | + # Lucy's model with no tools and a reviewer prompt: what the second-opinion | ||
| 29 | + # skill asks. A small model with every tool wanders (reads files, loads | ||
| 30 | + # skills) when it is only asked for an opinion. | ||
| 31 | + reviewer: agent.lucy-reviewer.yaml | ||
| 28 | 32 | ||
| 29 | # Only when the daemon was started with LLMMAN_API_KEYS (mandatory when it | 33 | # Only when the daemon was started with LLMMAN_API_KEYS (mandatory when it |
| 30 | # listens beyond loopback); unset otherwise. The key never goes in this file. | 34 | # listens beyond loopback); unset otherwise. The key never goes in this file. |
| @@ -78,7 +82,9 @@ maxTurns: 40 | |||
| 78 | 82 | ||
| 79 | # Where the `read_skill` tool looks for its markdown procedures. | 83 | # Where the `read_skill` tool looks for its markdown procedures. |
| 80 | # The path is relative to the CURRENT DIRECTORY: run the agent from demo-llmman/. | 84 | # The path is relative to the CURRENT DIRECTORY: run the agent from demo-llmman/. |
| 81 | -skillsDir: ../skills | 85 | +# demo-llmman/skills holds the /ask demo skills (delegate-to-jan, second-opinion, |
| 86 | +# compare-agents) — they call this same mm back with "$MM_BIN" --ask — and bg-jobs. | ||
| 87 | +skillsDir: skills | ||
| 82 | 88 | ||
| 83 | # Persistent sessions, per project. | 89 | # Persistent sessions, per project. |
| 84 | # When enabled, every conversation is saved as one JSON file under `dir`. | 90 | # When enabled, every conversation is saved as one JSON file under `dir`. |
| @@ -177,7 +183,13 @@ sampling: | |||
| 177 | max_tokens: 4096 | 183 | max_tokens: 4096 |
| 178 | 184 | ||
| 179 | # Silence allowed between two tokens once the answer has started. | 185 | # Silence allowed between two tokens once the answer has started. |
| 180 | -watchdogTimeout: 30s | 186 | +watchdogTimeout: 3m |
| 187 | + | ||
| 188 | +# How long one bash command may run (default 30s). The demo skills call jan and | ||
| 189 | +# lucy with "$MM_BIN" --ask, which can take a minute or two with small local | ||
| 190 | +# models. The watchdog above keeps counting while a command runs (ticket 57), | ||
| 191 | +# so it is raised to the same value. | ||
| 192 | +bashTimeout: 3m | ||
| 181 | 193 | ||
| 182 | # Silence allowed while the model reads the prompt, before the first token: | 194 | # Silence allowed while the model reads the prompt, before the first token: |
| 183 | # on a laptop a 25k-token prompt can take minutes. llama-server reports its | 195 | # on a laptop a 25k-token prompt can take minutes. llama-server reports its |
added
demo-llmman/agent.lucy-reviewer.yaml +140 -0 Large diff collapsed to keep the page fast — load it when you need it.
added
demo-llmman/skills/bg-jobs/SKILL.md +82 -0 | new file mode 100644 | ||
| @@ -0,0 +1,82 @@ | ||
| 1 | +--- | |
| 2 | +name: bg-jobs | |
| 3 | +description: Start, wait on, inspect and stop a long-running background job — a server, a watcher, a build that does not end — without blocking the turn. | |
| 4 | +keywords: background, job, server, serve, start, daemon, nohup, watch, tail, log, pid, kill, stop, port, running | |
| 5 | +--- | |
| 6 | + | |
| 7 | +# Background jobs | |
| 8 | + | |
| 9 | +## When to use it | |
| 10 | + | |
| 11 | +Any command that **serves, watches, or runs until stopped**: an HTTP server, `npm run dev`, `go run` on a web app, a file watcher, a queue worker. Read this before you start one, and before you wait on, inspect or stop one. | |
| 12 | + | |
| 13 | +A command that never returns will hold the turn for its whole budget and then be killed. The answer the user asked for never arrives. | |
| 14 | + | |
| 15 | +## Start it | |
| 16 | + | |
| 17 | +Both streams redirected, the pid kept: | |
| 18 | + | |
| 19 | +```bash | |
| 20 | +nohup <command> > /tmp/<job>.log 2>&1 & echo $! > /tmp/<job>.pid | |
| 21 | +``` | |
| 22 | + | |
| 23 | +Three parts, and all three matter: | |
| 24 | + | |
| 25 | +- **`> /tmp/<job>.log 2>&1`** — both streams. Redirecting only stdout is the classic mistake: the job keeps the tool's own error pipe open, and the call cannot finish until the job does. You get the 30-second budget spent on nothing. | |
| 26 | +- **`&`** — the shell returns at once. | |
| 27 | +- **`echo $! > /tmp/<job>.pid`** — without the pid you cannot stop it later except by guessing at `pkill` patterns, which also kills things you did not start. | |
| 28 | + | |
| 29 | +Use one name per job, and reuse it for the log and the pid file. | |
| 30 | + | |
| 31 | +## Wait for it to be ready | |
| 32 | + | |
| 33 | +**Do not `sleep` and hope.** Poll for the thing you actually need, with a bound: | |
| 34 | + | |
| 35 | +```bash | |
| 36 | +for i in $(seq 1 30); do | |
| 37 | + curl -fsS localhost:8080/ >/dev/null 2>&1 && echo ready && break | |
| 38 | + sleep 0.5 | |
| 39 | +done | |
| 40 | +``` | |
| 41 | + | |
| 42 | +For something that is not an HTTP server, poll the log for the line it prints when it is up: | |
| 43 | + | |
| 44 | +```bash | |
| 45 | +for i in $(seq 1 30); do | |
| 46 | + grep -q "listening on" /tmp/<job>.log && echo ready && break | |
| 47 | + sleep 0.5 | |
| 48 | +done | |
| 49 | +``` | |
| 50 | + | |
| 51 | +If the loop ends without `ready`, the job did not start — go read the log. | |
| 52 | + | |
| 53 | +## Inspect it | |
| 54 | + | |
| 55 | +```bash | |
| 56 | +tail -n 40 /tmp/<job>.log # what it said | |
| 57 | +kill -0 "$(cat /tmp/<job>.pid)" 2>/dev/null && echo alive || echo dead | |
| 58 | +``` | |
| 59 | + | |
| 60 | +`kill -0` sends no signal; it only asks whether the process is there. A job that is `dead` right after starting almost always says why in the last lines of its log — read them before changing anything. | |
| 61 | + | |
| 62 | +## Stop it | |
| 63 | + | |
| 64 | +```bash | |
| 65 | +kill "$(cat /tmp/<job>.pid)" 2>/dev/null | |
| 66 | +sleep 0.5 | |
| 67 | +kill -0 "$(cat /tmp/<job>.pid)" 2>/dev/null && kill -9 "$(cat /tmp/<job>.pid)" | |
| 68 | +rm -f /tmp/<job>.pid | |
| 69 | +``` | |
| 70 | + | |
| 71 | +Ask politely first (`kill` sends TERM, which lets a server close its listener), then insist. Removing the pid file afterwards stops a later command from acting on a pid the system has since reused for something else. | |
| 72 | + | |
| 73 | +## Before you finish | |
| 74 | + | |
| 75 | +**Stop every job you started**, and **say which ones you left running** and why. A server still holding port 8080 after the turn is a surprise the user will hit later, when nothing on screen explains it. | |
| 76 | + | |
| 77 | +## Traps | |
| 78 | + | |
| 79 | +- **One shell per call.** Each `bash` call is a new shell in the same directory: a job started in one call is still running in the next, but shell variables are gone. That is exactly why the pid goes to a file and not to `$PID`. | |
| 80 | +- **The port is already in use.** A previous run left something behind. `lsof -i :8080` or `ss -lptn 'sport = :8080'` names the holder; stop that before starting again, rather than moving to another port and forgetting. | |
| 81 | +- **Nothing is interactive.** There is no stdin. A command that asks a question will hang until it is killed; pass the answer as a flag, or do not run it. | |
| 82 | +- **`nohup` writes `nohup.out`** in the working directory when you forget to redirect — if you see that file appear, a redirect is missing. | |
| new file mode 100644 | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | +--- | ||
| 2 | +name: bg-jobs | ||
| 3 | +description: Start, wait on, inspect and stop a long-running background job — a server, a watcher, a build that does not end — without blocking the turn. | ||
| 4 | +keywords: background, job, server, serve, start, daemon, nohup, watch, tail, log, pid, kill, stop, port, running | ||
| 5 | +--- | ||
| 6 | + | ||
| 7 | +# Background jobs | ||
| 8 | + | ||
| 9 | +## When to use it | ||
| 10 | + | ||
| 11 | +Any command that **serves, watches, or runs until stopped**: an HTTP server, `npm run dev`, `go run` on a web app, a file watcher, a queue worker. Read this before you start one, and before you wait on, inspect or stop one. | ||
| 12 | + | ||
| 13 | +A command that never returns will hold the turn for its whole budget and then be killed. The answer the user asked for never arrives. | ||
| 14 | + | ||
| 15 | +## Start it | ||
| 16 | + | ||
| 17 | +Both streams redirected, the pid kept: | ||
| 18 | + | ||
| 19 | +```bash | ||
| 20 | +nohup <command> > /tmp/<job>.log 2>&1 & echo $! > /tmp/<job>.pid | ||
| 21 | +``` | ||
| 22 | + | ||
| 23 | +Three parts, and all three matter: | ||
| 24 | + | ||
| 25 | +- **`> /tmp/<job>.log 2>&1`** — both streams. Redirecting only stdout is the classic mistake: the job keeps the tool's own error pipe open, and the call cannot finish until the job does. You get the 30-second budget spent on nothing. | ||
| 26 | +- **`&`** — the shell returns at once. | ||
| 27 | +- **`echo $! > /tmp/<job>.pid`** — without the pid you cannot stop it later except by guessing at `pkill` patterns, which also kills things you did not start. | ||
| 28 | + | ||
| 29 | +Use one name per job, and reuse it for the log and the pid file. | ||
| 30 | + | ||
| 31 | +## Wait for it to be ready | ||
| 32 | + | ||
| 33 | +**Do not `sleep` and hope.** Poll for the thing you actually need, with a bound: | ||
| 34 | + | ||
| 35 | +```bash | ||
| 36 | +for i in $(seq 1 30); do | ||
| 37 | + curl -fsS localhost:8080/ >/dev/null 2>&1 && echo ready && break | ||
| 38 | + sleep 0.5 | ||
| 39 | +done | ||
| 40 | +``` | ||
| 41 | + | ||
| 42 | +For something that is not an HTTP server, poll the log for the line it prints when it is up: | ||
| 43 | + | ||
| 44 | +```bash | ||
| 45 | +for i in $(seq 1 30); do | ||
| 46 | + grep -q "listening on" /tmp/<job>.log && echo ready && break | ||
| 47 | + sleep 0.5 | ||
| 48 | +done | ||
| 49 | +``` | ||
| 50 | + | ||
| 51 | +If the loop ends without `ready`, the job did not start — go read the log. | ||
| 52 | + | ||
| 53 | +## Inspect it | ||
| 54 | + | ||
| 55 | +```bash | ||
| 56 | +tail -n 40 /tmp/<job>.log # what it said | ||
| 57 | +kill -0 "$(cat /tmp/<job>.pid)" 2>/dev/null && echo alive || echo dead | ||
| 58 | +``` | ||
| 59 | + | ||
| 60 | +`kill -0` sends no signal; it only asks whether the process is there. A job that is `dead` right after starting almost always says why in the last lines of its log — read them before changing anything. | ||
| 61 | + | ||
| 62 | +## Stop it | ||
| 63 | + | ||
| 64 | +```bash | ||
| 65 | +kill "$(cat /tmp/<job>.pid)" 2>/dev/null | ||
| 66 | +sleep 0.5 | ||
| 67 | +kill -0 "$(cat /tmp/<job>.pid)" 2>/dev/null && kill -9 "$(cat /tmp/<job>.pid)" | ||
| 68 | +rm -f /tmp/<job>.pid | ||
| 69 | +``` | ||
| 70 | + | ||
| 71 | +Ask politely first (`kill` sends TERM, which lets a server close its listener), then insist. Removing the pid file afterwards stops a later command from acting on a pid the system has since reused for something else. | ||
| 72 | + | ||
| 73 | +## Before you finish | ||
| 74 | + | ||
| 75 | +**Stop every job you started**, and **say which ones you left running** and why. A server still holding port 8080 after the turn is a surprise the user will hit later, when nothing on screen explains it. | ||
| 76 | + | ||
| 77 | +## Traps | ||
| 78 | + | ||
| 79 | +- **One shell per call.** Each `bash` call is a new shell in the same directory: a job started in one call is still running in the next, but shell variables are gone. That is exactly why the pid goes to a file and not to `$PID`. | ||
| 80 | +- **The port is already in use.** A previous run left something behind. `lsof -i :8080` or `ss -lptn 'sport = :8080'` names the holder; stop that before starting again, rather than moving to another port and forgetting. | ||
| 81 | +- **Nothing is interactive.** There is no stdin. A command that asks a question will hang until it is killed; pass the answer as a flag, or do not run it. | ||
| 82 | +- **`nohup` writes `nohup.out`** in the working directory when you forget to redirect — if you see that file appear, a redirect is missing. | ||
added
demo-llmman/skills/compare-agents/SKILL.md +23 -0 Large diff collapsed to keep the page fast — load it when you need it.
added
demo-llmman/skills/delegate-to-jan/SKILL.md +23 -0 Large diff collapsed to keep the page fast — load it when you need it.
added
demo-llmman/skills/second-opinion/SKILL.md +28 -0 Large diff collapsed to keep the page fast — load it when you need it.
added
demo/newfile.txt +0 -0 | new file mode 100644 |
| new file mode 100644 |
modified
docs/en/README.md +1 -0 | @@ -14,6 +14,7 @@ This documentation is organised along the four [Diátaxis](https://diataxis.fr) | ||
| 14 | 14 | - [Run mini-me on llmman](how-to/run-with-llmman.md) — `provider: llmman`, the demo config in `demo-llmman/` |
| 15 | 15 | - [Run mini-me on Ollama](how-to/run-with-ollama.md) — `provider: ollama`, the demo config in `demo-ollama/` |
| 16 | 16 | - [Ask another mm agent from your session](how-to/ask-another-agent.md) — `mmConfigs`, `/ask-<name>`, `/ask-with-context-<name>` |
| 17 | +- [Ask another agent from a skill or a script](how-to/ask-another-agent-from-a-skill.md) — `"$MM_BIN" --ask <agent>`, `--ask-with-context`, the demo skills | |
| 17 | 18 | - [Use mini-me from an editor (ACP)](how-to/use-from-an-editor.md) |
| 18 | 19 | - [Run mini-me in a Docker Sandbox](how-to/run-in-a-docker-sandbox.md) — the template and the two kits under `docker-sbx/`, window mode and editor |
| 19 | 20 | - [Run mini-me with the v3 sandbox kits](how-to/run-with-sandbox-kits-v3.md) — the same two kits for the kit specification v3, under `docker-sbx-v3/` |
| @@ -14,6 +14,7 @@ This documentation is organised along the four [Diátaxis](https://diataxis.fr) | |||
| 14 | - [Run mini-me on llmman](how-to/run-with-llmman.md) — `provider: llmman`, the demo config in `demo-llmman/` | 14 | - [Run mini-me on llmman](how-to/run-with-llmman.md) — `provider: llmman`, the demo config in `demo-llmman/` |
| 15 | - [Run mini-me on Ollama](how-to/run-with-ollama.md) — `provider: ollama`, the demo config in `demo-ollama/` | 15 | - [Run mini-me on Ollama](how-to/run-with-ollama.md) — `provider: ollama`, the demo config in `demo-ollama/` |
| 16 | - [Ask another mm agent from your session](how-to/ask-another-agent.md) — `mmConfigs`, `/ask-<name>`, `/ask-with-context-<name>` | 16 | - [Ask another mm agent from your session](how-to/ask-another-agent.md) — `mmConfigs`, `/ask-<name>`, `/ask-with-context-<name>` |
| 17 | +- [Ask another agent from a skill or a script](how-to/ask-another-agent-from-a-skill.md) — `"$MM_BIN" --ask <agent>`, `--ask-with-context`, the demo skills | ||
| 17 | - [Use mini-me from an editor (ACP)](how-to/use-from-an-editor.md) | 18 | - [Use mini-me from an editor (ACP)](how-to/use-from-an-editor.md) |
| 18 | - [Run mini-me in a Docker Sandbox](how-to/run-in-a-docker-sandbox.md) — the template and the two kits under `docker-sbx/`, window mode and editor | 19 | - [Run mini-me in a Docker Sandbox](how-to/run-in-a-docker-sandbox.md) — the template and the two kits under `docker-sbx/`, window mode and editor |
| 19 | - [Run mini-me with the v3 sandbox kits](how-to/run-with-sandbox-kits-v3.md) — the same two kits for the kit specification v3, under `docker-sbx-v3/` | 20 | - [Run mini-me with the v3 sandbox kits](how-to/run-with-sandbox-kits-v3.md) — the same two kits for the kit specification v3, under `docker-sbx-v3/` |
modified
docs/en/explanation/asking-another-agent.md +4 -0 | @@ -22,6 +22,10 @@ | ||
| 22 | 22 | |
| 23 | 23 | **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. |
| 24 | 24 | |
| 25 | +**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. | |
| 26 | + | |
| 27 | +**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. | |
| 28 | + | |
| 25 | 29 | ## Rejected alternatives |
| 26 | 30 | |
| 27 | 31 | - **`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. |
| @@ -22,6 +22,10 @@ | |||
| 22 | 22 | ||
| 23 | **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. | 23 | **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. |
| 24 | 24 | ||
| 25 | +**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. | ||
| 26 | + | ||
| 27 | +**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. | ||
| 28 | + | ||
| 25 | ## Rejected alternatives | 29 | ## Rejected alternatives |
| 26 | 30 | ||
| 27 | - **`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. | 31 | - **`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. |
added
docs/en/how-to/ask-another-agent-from-a-skill.md +61 -0 Large diff collapsed to keep the page fast — load it when you need it.
modified
docs/en/reference/cli.md +22 -2 Large diff collapsed to keep the page fast — load it when you need it.
modified
docs/en/reference/configuration.md +2 -0 Large diff collapsed to keep the page fast — load it when you need it.
modified
docs/fr/README.md +1 -0 Large diff collapsed to keep the page fast — load it when you need it.
modified
docs/fr/explanation/asking-another-agent.md +4 -0 Large diff collapsed to keep the page fast — load it when you need it.
added
docs/fr/how-to/ask-another-agent-from-a-skill.md +61 -0 Large diff collapsed to keep the page fast — load it when you need it.
modified
docs/fr/reference/cli.md +22 -2 Large diff collapsed to keep the page fast — load it when you need it.
modified
docs/fr/reference/configuration.md +2 -0 Large diff collapsed to keep the page fast — load it when you need it.
added
internal/ask/cli.go +134 -0 Large diff collapsed to keep the page fast — load it when you need it.
added
internal/ask/cli_test.go +85 -0 Large diff collapsed to keep the page fast — load it when you need it.
added
internal/ask/orphan.go +39 -0 Large diff collapsed to keep the page fast — load it when you need it.
added
internal/ask/orphan_test.go +33 -0 Large diff collapsed to keep the page fast — load it when you need it.
modified
internal/config/agents_test.go +31 -0 Large diff collapsed to keep the page fast — load it when you need it.
modified
internal/config/config.go +10 -0 Large diff collapsed to keep the page fast — load it when you need it.
modified
internal/tools/bash_test.go +16 -0 Large diff collapsed to keep the page fast — load it when you need it.
modified
internal/tools/tools.go +7 -9 Large diff collapsed to keep the page fast — load it when you need it.
modified
main.go +101 -9 Large diff collapsed to keep the page fast — load it when you need it.