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

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

Download ZIP

1st steps for a sdk #48

Merged@k33g wants to merge feature/mini-me-as-a-sdk into main
Merged as b044d58138c1.
65 files changed
modified .tickets/issues/0071-mini-me-as-a-sdk.yaml +10 -2
@@ -6,7 +6,7 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-02T05:32:33.878Z
9-updatedAt: 2026-10-22T17:07:15.939Z
9+updatedAt: 2026-10-26T05:00:00.000Z
1010 labels:
1111 - priority::urgent
1212 - kind::feature
@@ -103,4 +103,12 @@ body: |
103103 - **Stability promise**: `v0` and experimental until step 4 is done?
104104 - **Priority**: is headless/stream-json wanted first, as a quick win?
105105 tasks: []
106-comments: []
106+comments:
107+ - id: 1
108+ author:
109+ name: k33g
110+ email: ph.charriere@gmail.com
111+ createdAt: 2026-10-26T05:00:00.000Z
112+ body: |
113+ Update 2026-10-26: a smaller first version is proposed in ticket 139 — a public package with ONE method (`minime.Load` + `agent.Complete(ctx, prompt, minime.OnEvent(fn))`, streamed or not, cancelled by ctx, no STDIO), built as a thin façade over today's engine, the way ACP already uses it (`ui.SetActive(sink)` + `engine.Generate`). It would come BEFORE step 1 of this plan, with the same rules (own types, no Genkit in the API) so this plan can then remove the globals behind it without changing the API.
114+ Facts that changed since 2026-10-14: `config.Cfg` is now read in 92 files; the wiring in `main.go` has grown (autoPull, skill and tool routing, struggle signals, decision models), which is one more reason to move it out of `package main` first. `ui.Sink.Allow(ctx, call)` is where an SDK tool-confirmation callback would plug in.
@@ -6,7 +6,7 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-10-02T05:32:33.878Z8 createdAt: 2026-10-02T05:32:33.878Z
9-updatedAt: 2026-10-22T17:07:15.939Z9+updatedAt: 2026-10-26T05:00:00.000Z
10 labels:10 labels:
11 - priority::urgent11 - priority::urgent
12 - kind::feature12 - kind::feature
@@ -103,4 +103,12 @@ body: |
103 - **Stability promise**: `v0` and experimental until step 4 is done?103 - **Stability promise**: `v0` and experimental until step 4 is done?
104 - **Priority**: is headless/stream-json wanted first, as a quick win?104 - **Priority**: is headless/stream-json wanted first, as a quick win?
105 tasks: []105 tasks: []
106-comments: []106+comments:
107+ - id: 1
108+ author:
109+ name: k33g
110+ email: ph.charriere@gmail.com
111+ createdAt: 2026-10-26T05:00:00.000Z
112+ body: |
113+ Update 2026-10-26: a smaller first version is proposed in ticket 139 — a public package with ONE method (`minime.Load` + `agent.Complete(ctx, prompt, minime.OnEvent(fn))`, streamed or not, cancelled by ctx, no STDIO), built as a thin façade over today's engine, the way ACP already uses it (`ui.SetActive(sink)` + `engine.Generate`). It would come BEFORE step 1 of this plan, with the same rules (own types, no Genkit in the API) so this plan can then remove the globals behind it without changing the API.
114+ Facts that changed since 2026-10-14: `config.Cfg` is now read in 92 files; the wiring in `main.go` has grown (autoPull, skill and tool routing, struggle signals, decision models), which is one more reason to move it out of `package main` first. `ui.Sink.Allow(ctx, call)` is where an SDK tool-confirmation callback would plug in.
modified .tickets/issues/0105-mini-me-as-a-sdk-2.yaml +9 -2
@@ -6,7 +6,7 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-20T07:51:18.410Z
9-updatedAt: 2026-10-22T17:07:42.565Z
9+updatedAt: 2026-10-26T05:00:00.000Z
1010 labels: []
1111 epic: SDK
1212 related:
@@ -14,4 +14,11 @@ related:
1414 body: |
1515 Check how it's possible to create a specific package that "exposes" the various methods
1616 tasks: []
17-comments: []
17+comments:
18+ - id: 1
19+ author:
20+ name: k33g
21+ email: ph.charriere@gmail.com
22+ createdAt: 2026-10-26T05:00:00.000Z
23+ body: |
24+ Answer 2026-10-26: yes, it is possible — Go forbids importing `internal/` from another module, so the package that exposes the methods must sit outside `internal/` (proposed: `minime/`) and the module needs an importable path (`rickub.com/bots-garden/mini-me`, go-get on Rickub to verify). The agent wiring now in `package main` would move to an internal package used by both the binary and this public package. The full proposal, with its first single method (`Complete`), is in ticket 139.
@@ -6,7 +6,7 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-10-20T07:51:18.410Z8 createdAt: 2026-10-20T07:51:18.410Z
9-updatedAt: 2026-10-22T17:07:42.565Z9+updatedAt: 2026-10-26T05:00:00.000Z
10 labels: []10 labels: []
11 epic: SDK11 epic: SDK
12 related:12 related:
@@ -14,4 +14,11 @@ related:
14 body: |14 body: |
15 Check how it's possible to create a specific package that "exposes" the various methods15 Check how it's possible to create a specific package that "exposes" the various methods
16 tasks: []16 tasks: []
17-comments: []17+comments:
18+ - id: 1
19+ author:
20+ name: k33g
21+ email: ph.charriere@gmail.com
22+ createdAt: 2026-10-26T05:00:00.000Z
23+ body: |
24+ Answer 2026-10-26: yes, it is possible — Go forbids importing `internal/` from another module, so the package that exposes the methods must sit outside `internal/` (proposed: `minime/`) and the module needs an importable path (`rickub.com/bots-garden/mini-me`, go-get on Rickub to verify). The agent wiring now in `package main` would move to an internal package used by both the binary and this public package. The full proposal, with its first single method (`Complete`), is in ticket 139.
modified .tickets/issues/0139-some-api-ideas.yaml +134 -3
@@ -6,13 +6,144 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-23T09:54:13.140Z
9-updatedAt: 2026-10-23T09:57:11.218Z
10-labels: []
9+updatedAt: 2026-10-26T05:00:00.000Z
10+labels:
11+ - kind::feature
1112 epic: SDK
13+related:
14+ - 71
15+ - 105
16+ - 113
1217 body: |
1318 il faudrait par exemple créer une lib avec une méthode par exemple `prompt`
1419 (equivalent de mm -p "hello this is my question"
1520
1621 et on aurait la possibilité via le pattern go de passer les éléments necessaires (les reglages du fichiers de config, des tools, ...)
17-tasks: []
22+
23+ ---
24+
25+ ## Request (2026-10-26)
26+ A first version of mini-me as a library with ONE method: from an agent configuration, run a completion, get the result streamed or not, and be able to cancel it. No STDIO: a Go program must not need the `mm` binary installed. In the end, mini-me should be usable both as an agent (the binary) and as a library. Nothing implemented yet: this section records the analysis and the proposals.
27+
28+ ## Proposed API (the same in every proposal below)
29+ ```go
30+ agent, err := minime.Load(ctx, "agent.yaml") // builds the agent, runs nothing
31+
32+ // not streamed
33+ res, err := agent.Complete(ctx, "Explain this repository")
34+ fmt.Println(res.Text)
35+
36+ // streamed: an option on the same method
37+ res, err := agent.Complete(ctx, "Explain this repository",
38+ minime.OnEvent(func(ev minime.Event) { // Text, Thinking, ToolCall, ToolResult, Notice, Struggle
39+ if ev.Kind == minime.Text { fmt.Print(ev.Text) }
40+ }))
41+
42+ // cancel: the Go idiom, the context
43+ ctx, cancel := context.WithCancel(ctx)
44+ ```
45+ - One method, `Complete`. `Load` only builds the agent once (reading the YAML, starting MCP / LSP servers on every call would be wasteful).
46+ - The public types belong to `minime`, never to Genkit or `internal/` (same rule as ticket 71: Genkit changes, ticket 76).
47+
48+ ## What blocks an import today (checked 2026-10-26)
49+ | Obstacle | Where | Consequence |
50+ |---|---|---|
51+ | The module is named `mm` | `go.mod` | not go-gettable; would become `rickub.com/bots-garden/mini-me` — whether Rickub serves the `?go-get=1` meta tag is NOT verified |
52+ | Every package is under `internal/` | 35 packages | another module cannot import them: a public package is needed |
53+ | The agent's wiring is in `package main` | `main.go`: `assembleTools`, `autoPull`, skill/tool routing, hooks, struggle signals | the SDK cannot reuse it; copying it would make SDK and binary drift |
54+ | Global state | `config.Cfg` (read in 92 files), `ui.Out`, `ui.SetActive`, `skills.Declare`, the spinner | one agent per process, one completion at a time |
55+ | Tool confirmation is a terminal question | `yolo: false` | a library has no terminal: another rule is needed |
56+
57+ ## What already fits
58+ The editor mode (ACP) already does what the SDK needs, without STDIO for the answer itself (`internal/acp/acp.go` ~413–451): `ui.SetActive(sink)` then `engine.Generate(ctx, messages, tools)`.
59+ - `engine.New(ctx)` opens the provider of the config (llmman, Ollama, DMR…).
60+ - `engine.Generate` runs the whole turn (model calls, tools, hooks, watchdog, loop detector, routing) and returns the final answer plus the whole conversation.
61+ - `ui.Sink` receives the stream: `Text`, `Reasoning`, `ToolStart` / `ToolRunning` / `ToolEnd`, and `Allow(ctx, call) bool` — the place for a tool-confirmation callback.
62+ - Cancelling the `ctx` already stops the turn, a running `bash` included (Esc in Zed works that way).
63+
64+ ## Proposals
65+ - **A — Thin façade over the existing engine (fastest).** A public package `minime/` calls the engine as ACP does. The wiring of `main.go` moves to an internal package (`internal/assemble`), called by both `main` and the SDK. Documented limits: one agent loaded per process (`config.Load` fills the global `config.Cfg`), completions serialised under a lock (`ui.SetActive` is ONE sink for the process). Moderate cost, low risk.
66+ - **B — Per-instance core (the real library).** Replace the global state with an `Agent` value carrying its config, sink and engine; terminal, window and editor become its clients. Several agents and completions in parallel. High cost (at least the 92 files reading `config.Cfg`), regression risk everywhere. This is step 1 of ticket 71.
67+ - **C — A first, then B behind the same API (recommended).** v1 = the façade; since its API exposes nothing internal, the globals can then be removed package by package without changing one SDK signature, and the "one agent per process" rule disappears without breaking users.
68+ - **D — `mm serve`, HTTP + SSE (later, for other languages).** The same `Complete` behind an HTTP server for Python / JavaScript. Needs `mm` running somewhere (a container is enough), so it does not meet "no binary" for Go — a complement, not v1. See ticket 113.
69+
70+ Sketch of the façade (proposal A / C):
71+ ```go
72+ func Load(ctx context.Context, path string) (*Agent, error) {
73+ config.Load(path) // fills config.Cfg (global)
74+ e, _ := engine.New(ctx)
75+ tools := assemble.Tools(e, …) // today in main.go → moved under internal/
76+ return &Agent{e: e, tools: tools, history: []*ai.Message{system}}, nil
77+ }
78+
79+ func (a *Agent) Complete(ctx context.Context, prompt string, opts ...Option) (Result, error) {
80+ mu.Lock(); defer mu.Unlock() // one turn at a time: the sink is global
81+ ui.SetActive(eventSink{onEvent}) // turns Text/ToolStart/… into minime.Event
82+ defer ui.SetActive(nil)
83+ resp, full, err := a.e.Generate(ctx, append(a.history, user(prompt)), a.tools)
84+ a.history = full
85+ return Result{Text: resp.Text()}, err
86+ }
87+ ```
88+ Not streamed = the same path: without `OnEvent` the sink drops the chunks and `Complete` returns the final text.
89+
90+ ## Traps to handle
91+ - The engine still writes some lines straight to `ui.Out` (the spinner, "stream cut — retrying this model call once"…): they must go to the sink or be off in SDK mode — a library never writes to its host's stdout.
92+ - Renaming the module rewrites every import AND the `-X mm/internal/version.stamped` ldflag in `02-build-releases.sh`.
93+ - `ask_user` and the `/ask` hand-offs (`mmConfigs` starts child `mm -acp` processes) need the binary: out of v1, or refused with a clear error.
94+
95+ ## Decisions for the user
96+ 1. Proposal: A, B, C (recommended) or D first.
97+ 2. Does `Complete` keep the conversation between calls (like the REPL, recommended), or is each call isolated (like `mm -p`)?
98+ 3. Tool confirmation with `yolo: false`: a callback (`OnApprove`), refusing when there is none (recommended), or the YAML only (`yolo: false` refuses whatever would ask)?
99+ 4. Module path and package name: `rickub.com/bots-garden/mini-me` + `minime/`?
100+tasks:
101+ - id: 1
102+ title: Decide the proposal, the history and the tool-confirmation rule
103+ state: open
104+ priority: none
105+ author:
106+ name: k33g
107+ email: ph.charriere@gmail.com
108+ createdAt: 2026-10-26T05:00:00.000Z
109+ - id: 2
110+ title: Make the module importable (module path, go-get on Rickub)
111+ state: open
112+ priority: none
113+ author:
114+ name: k33g
115+ email: ph.charriere@gmail.com
116+ createdAt: 2026-10-26T05:00:00.000Z
117+ - id: 3
118+ title: Move the agent wiring out of package main into an internal package
119+ state: open
120+ priority: none
121+ author:
122+ name: k33g
123+ email: ph.charriere@gmail.com
124+ createdAt: 2026-10-26T05:00:00.000Z
125+ - id: 4
126+ title: Public package with Load + Complete (stream option, ctx cancel), unit tests and Example tests
127+ state: open
128+ priority: none
129+ author:
130+ name: k33g
131+ email: ph.charriere@gmail.com
132+ createdAt: 2026-10-26T05:00:00.000Z
133+ - id: 5
134+ title: Engine output that bypasses the sink goes to events (no write to the host's stdout)
135+ state: open
136+ priority: none
137+ author:
138+ name: k33g
139+ email: ph.charriere@gmail.com
140+ createdAt: 2026-10-26T05:00:00.000Z
141+ - id: 6
142+ title: Docs EN + FR (how-to embed mini-me in a Go program, API reference)
143+ state: open
144+ priority: none
145+ author:
146+ name: k33g
147+ email: ph.charriere@gmail.com
148+ createdAt: 2026-10-26T05:00:00.000Z
18149 comments: []
@@ -6,13 +6,144 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-10-23T09:54:13.140Z8 createdAt: 2026-10-23T09:54:13.140Z
9-updatedAt: 2026-10-23T09:57:11.218Z9+updatedAt: 2026-10-26T05:00:00.000Z
10-labels: []10+labels:
11+ - kind::feature
11 epic: SDK12 epic: SDK
13+related:
14+ - 71
15+ - 105
16+ - 113
12 body: |17 body: |
13 il faudrait par exemple créer une lib avec une méthode par exemple `prompt`18 il faudrait par exemple créer une lib avec une méthode par exemple `prompt`
14 (equivalent de mm -p "hello this is my question"19 (equivalent de mm -p "hello this is my question"
15 20
16 et on aurait la possibilité via le pattern go de passer les éléments necessaires (les reglages du fichiers de config, des tools, ...) 21 et on aurait la possibilité via le pattern go de passer les éléments necessaires (les reglages du fichiers de config, des tools, ...)
17-tasks: []22+
23+ ---
24+
25+ ## Request (2026-10-26)
26+ A first version of mini-me as a library with ONE method: from an agent configuration, run a completion, get the result streamed or not, and be able to cancel it. No STDIO: a Go program must not need the `mm` binary installed. In the end, mini-me should be usable both as an agent (the binary) and as a library. Nothing implemented yet: this section records the analysis and the proposals.
27+
28+ ## Proposed API (the same in every proposal below)
29+ ```go
30+ agent, err := minime.Load(ctx, "agent.yaml") // builds the agent, runs nothing
31+
32+ // not streamed
33+ res, err := agent.Complete(ctx, "Explain this repository")
34+ fmt.Println(res.Text)
35+
36+ // streamed: an option on the same method
37+ res, err := agent.Complete(ctx, "Explain this repository",
38+ minime.OnEvent(func(ev minime.Event) { // Text, Thinking, ToolCall, ToolResult, Notice, Struggle
39+ if ev.Kind == minime.Text { fmt.Print(ev.Text) }
40+ }))
41+
42+ // cancel: the Go idiom, the context
43+ ctx, cancel := context.WithCancel(ctx)
44+ ```
45+ - One method, `Complete`. `Load` only builds the agent once (reading the YAML, starting MCP / LSP servers on every call would be wasteful).
46+ - The public types belong to `minime`, never to Genkit or `internal/` (same rule as ticket 71: Genkit changes, ticket 76).
47+
48+ ## What blocks an import today (checked 2026-10-26)
49+ | Obstacle | Where | Consequence |
50+ |---|---|---|
51+ | The module is named `mm` | `go.mod` | not go-gettable; would become `rickub.com/bots-garden/mini-me` — whether Rickub serves the `?go-get=1` meta tag is NOT verified |
52+ | Every package is under `internal/` | 35 packages | another module cannot import them: a public package is needed |
53+ | The agent's wiring is in `package main` | `main.go`: `assembleTools`, `autoPull`, skill/tool routing, hooks, struggle signals | the SDK cannot reuse it; copying it would make SDK and binary drift |
54+ | Global state | `config.Cfg` (read in 92 files), `ui.Out`, `ui.SetActive`, `skills.Declare`, the spinner | one agent per process, one completion at a time |
55+ | Tool confirmation is a terminal question | `yolo: false` | a library has no terminal: another rule is needed |
56+
57+ ## What already fits
58+ The editor mode (ACP) already does what the SDK needs, without STDIO for the answer itself (`internal/acp/acp.go` ~413–451): `ui.SetActive(sink)` then `engine.Generate(ctx, messages, tools)`.
59+ - `engine.New(ctx)` opens the provider of the config (llmman, Ollama, DMR…).
60+ - `engine.Generate` runs the whole turn (model calls, tools, hooks, watchdog, loop detector, routing) and returns the final answer plus the whole conversation.
61+ - `ui.Sink` receives the stream: `Text`, `Reasoning`, `ToolStart` / `ToolRunning` / `ToolEnd`, and `Allow(ctx, call) bool` — the place for a tool-confirmation callback.
62+ - Cancelling the `ctx` already stops the turn, a running `bash` included (Esc in Zed works that way).
63+
64+ ## Proposals
65+ - **A — Thin façade over the existing engine (fastest).** A public package `minime/` calls the engine as ACP does. The wiring of `main.go` moves to an internal package (`internal/assemble`), called by both `main` and the SDK. Documented limits: one agent loaded per process (`config.Load` fills the global `config.Cfg`), completions serialised under a lock (`ui.SetActive` is ONE sink for the process). Moderate cost, low risk.
66+ - **B — Per-instance core (the real library).** Replace the global state with an `Agent` value carrying its config, sink and engine; terminal, window and editor become its clients. Several agents and completions in parallel. High cost (at least the 92 files reading `config.Cfg`), regression risk everywhere. This is step 1 of ticket 71.
67+ - **C — A first, then B behind the same API (recommended).** v1 = the façade; since its API exposes nothing internal, the globals can then be removed package by package without changing one SDK signature, and the "one agent per process" rule disappears without breaking users.
68+ - **D — `mm serve`, HTTP + SSE (later, for other languages).** The same `Complete` behind an HTTP server for Python / JavaScript. Needs `mm` running somewhere (a container is enough), so it does not meet "no binary" for Go — a complement, not v1. See ticket 113.
69+
70+ Sketch of the façade (proposal A / C):
71+ ```go
72+ func Load(ctx context.Context, path string) (*Agent, error) {
73+ config.Load(path) // fills config.Cfg (global)
74+ e, _ := engine.New(ctx)
75+ tools := assemble.Tools(e, …) // today in main.go → moved under internal/
76+ return &Agent{e: e, tools: tools, history: []*ai.Message{system}}, nil
77+ }
78+
79+ func (a *Agent) Complete(ctx context.Context, prompt string, opts ...Option) (Result, error) {
80+ mu.Lock(); defer mu.Unlock() // one turn at a time: the sink is global
81+ ui.SetActive(eventSink{onEvent}) // turns Text/ToolStart/… into minime.Event
82+ defer ui.SetActive(nil)
83+ resp, full, err := a.e.Generate(ctx, append(a.history, user(prompt)), a.tools)
84+ a.history = full
85+ return Result{Text: resp.Text()}, err
86+ }
87+ ```
88+ Not streamed = the same path: without `OnEvent` the sink drops the chunks and `Complete` returns the final text.
89+
90+ ## Traps to handle
91+ - The engine still writes some lines straight to `ui.Out` (the spinner, "stream cut — retrying this model call once"…): they must go to the sink or be off in SDK mode — a library never writes to its host's stdout.
92+ - Renaming the module rewrites every import AND the `-X mm/internal/version.stamped` ldflag in `02-build-releases.sh`.
93+ - `ask_user` and the `/ask` hand-offs (`mmConfigs` starts child `mm -acp` processes) need the binary: out of v1, or refused with a clear error.
94+
95+ ## Decisions for the user
96+ 1. Proposal: A, B, C (recommended) or D first.
97+ 2. Does `Complete` keep the conversation between calls (like the REPL, recommended), or is each call isolated (like `mm -p`)?
98+ 3. Tool confirmation with `yolo: false`: a callback (`OnApprove`), refusing when there is none (recommended), or the YAML only (`yolo: false` refuses whatever would ask)?
99+ 4. Module path and package name: `rickub.com/bots-garden/mini-me` + `minime/`?
100+tasks:
101+ - id: 1
102+ title: Decide the proposal, the history and the tool-confirmation rule
103+ state: open
104+ priority: none
105+ author:
106+ name: k33g
107+ email: ph.charriere@gmail.com
108+ createdAt: 2026-10-26T05:00:00.000Z
109+ - id: 2
110+ title: Make the module importable (module path, go-get on Rickub)
111+ state: open
112+ priority: none
113+ author:
114+ name: k33g
115+ email: ph.charriere@gmail.com
116+ createdAt: 2026-10-26T05:00:00.000Z
117+ - id: 3
118+ title: Move the agent wiring out of package main into an internal package
119+ state: open
120+ priority: none
121+ author:
122+ name: k33g
123+ email: ph.charriere@gmail.com
124+ createdAt: 2026-10-26T05:00:00.000Z
125+ - id: 4
126+ title: Public package with Load + Complete (stream option, ctx cancel), unit tests and Example tests
127+ state: open
128+ priority: none
129+ author:
130+ name: k33g
131+ email: ph.charriere@gmail.com
132+ createdAt: 2026-10-26T05:00:00.000Z
133+ - id: 5
134+ title: Engine output that bypasses the sink goes to events (no write to the host's stdout)
135+ state: open
136+ priority: none
137+ author:
138+ name: k33g
139+ email: ph.charriere@gmail.com
140+ createdAt: 2026-10-26T05:00:00.000Z
141+ - id: 6
142+ title: Docs EN + FR (how-to embed mini-me in a Go program, API reference)
143+ state: open
144+ priority: none
145+ author:
146+ name: k33g
147+ email: ph.charriere@gmail.com
148+ createdAt: 2026-10-26T05:00:00.000Z
18 comments: []149 comments: []
added .tickets/issues/0167-node-js-client-over-acp-a-first-sdk-prototype-fo.yaml +136 -0
new file mode 100644
@@ -0,0 +1,136 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 167
3+title: "Node.js client over ACP: a first SDK prototype for other languages"
4+state: closed
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-26T06:00:00.000Z
9+updatedAt: 2026-10-26T11:00:00.000Z
10+labels:
11+ - kind::feature
12+milestone: v1.0.2
13+epic: SDK
14+related:
15+ - 139
16+ - 71
17+ - 113
18+ - 168
19+ - 169
20+ - 170
21+ - 171
22+ - 172
23+body: |
24+ ## Goal
25+ Prove that mm can be used as a library from another language by driving `mm -acp` over ACP (JSON-RPC on stdin/stdout), with NO change to mm. Node.js first (user's choice, 2026-10-26); Python later if the prototype convinces. Prototype only: one demo folder, not a published package.
26+
27+ This is the "other languages" path. It complements the Go SDK of ticket 139 (in-process, no binary) and does not replace it. Remote use (an agent in another machine or container) stays for `mm serve` (ticket 113 / proposal D of 139).
28+
29+ ## Why ACP fits (checked in internal/acp and docs/en/reference/acp.md on 2026-10-26)
30+ | Wanted | ACP, already in mm |
31+ |---|---|
32+ | run a completion | `session/prompt` |
33+ | stream | `session/update` notifications (text chunks, thoughts, tool calls, plan) |
34+ | not streamed | join the text chunks until `session/prompt` answers (its `stopReason`) |
35+ | cancel | `session/cancel` |
36+ | tool confirmation (`yolo: false`) | mm sends `session/request_permission` to the client → a callback |
37+ | `ask_user` | `elicitation/create`, only when the client advertises `clientCapabilities.elicitation.form` at `initialize` |
38+ | keep the conversation | one ACP session = one history; `session/load` / `session/resume` with `sessions.enabled` |
39+
40+ - mm asks nothing else of the client: it reads files and runs commands itself, so the client does not have to implement `fs/*` or `terminal/*`.
41+ - One agent = one process: several agents run side by side, the global state of the Go code (`config.Cfg`, `ui.SetActive`) is no problem here.
42+ - Everything mm does works unchanged: hooks, MCP, `mmConfigs`, skill/tool routing, struggle signals.
43+
44+ ## Proposed shape (to discuss in the prototype)
45+ ```js
46+ import { Agent } from "./minime.js";
47+
48+ const agent = await Agent.start({
49+ config: "agent.yaml", // passed as AGENT_CONFIG (absolute path)
50+ cwd: process.cwd(), // the session's cwd (session/new)
51+ onPermission: (call) => call.kind === "read", // no callback → refuse
52+ });
53+
54+ const text = await agent.complete("Explain this repository"); // not streamed
55+
56+ for await (const ev of agent.stream("And the tests?")) { // streamed
57+ if (ev.kind === "text") process.stdout.write(ev.text);
58+ }
59+
60+ const ac = new AbortController();
61+ setTimeout(() => ac.abort(), 5000);
62+ await agent.complete("A long task", { signal: ac.signal }); // abort → session/cancel
63+
64+ await agent.close(); // closes stdin, mm exits
65+ ```
66+ - Plain Node.js (built-in `child_process`, `readline`), no dependency, ESM, Node 22 (the sandbox has v22.22.1).
67+ - Events reduced to a few kinds: `text`, `thinking`, `tool_call`, `tool_result`, `done` — not the editor-oriented detail of ACP (diffs, statuses).
68+ - The `mm` binary is found on the PATH or through `MM_BIN` (the convention of the demo hooks).
69+ - stderr of mm (banner, warnings, `[acp]` lines) is drained, optionally passed to a callback, never mixed with the answer.
70+ - Check first whether the official ACP TypeScript library (`@agentclientprotocol/sdk` or similar — not verified, no network in the sandbox) is worth using instead of raw JSON-RPC; raw JSON-RPC keeps the prototype dependency-free.
71+
72+ ## Limits to state in the README
73+ - The `mm` binary must be installed (a later package could ship it per platform, as some npm packages do for native tools).
74+ - Local only: stdio.
75+ - The config is a file path (AGENT_CONFIG); no in-memory config.
76+
77+ ## Done when
78+ - `demo.acp.sdk/nodejs/` (location chosen by the user on 2026-10-26, instead of `demos/node-acp-client/`) holds `minime.js` (the client), one example each for not streamed, streamed and cancelled, and README EN + FR with the results measured on llmman.
79+ - Permissions: a refused and an accepted tool call shown with an agent with `yolo: false`.
80+ - Nothing changed in mm's Go code.
81+tasks:
82+ - id: 1
83+ title: Check the official ACP TypeScript library vs raw JSON-RPC; decide
84+ state: closed
85+ priority: none
86+ author:
87+ name: k33g
88+ email: ph.charriere@gmail.com
89+ createdAt: 2026-10-26T06:00:00.000Z
90+ - id: 2
91+ title: "minime.js: start (initialize + session/new), complete, stream, cancel, close"
92+ state: closed
93+ priority: none
94+ author:
95+ name: k33g
96+ email: ph.charriere@gmail.com
97+ createdAt: 2026-10-26T06:00:00.000Z
98+ - id: 3
99+ title: Permission callback (session/request_permission), refuse by default
100+ state: closed
101+ priority: none
102+ author:
103+ name: k33g
104+ email: ph.charriere@gmail.com
105+ createdAt: 2026-10-26T06:00:00.000Z
106+ - id: 4
107+ title: Examples (not streamed, streamed, cancelled, permission) run on llmman
108+ state: closed
109+ priority: none
110+ author:
111+ name: k33g
112+ email: ph.charriere@gmail.com
113+ createdAt: 2026-10-26T06:00:00.000Z
114+ - id: 5
115+ title: README EN + FR with measured results and limits
116+ state: closed
117+ priority: none
118+ author:
119+ name: k33g
120+ email: ph.charriere@gmail.com
121+ createdAt: 2026-10-26T06:00:00.000Z
122+comments:
123+ - id: 1
124+ author:
125+ name: k33g
126+ email: ph.charriere@gmail.com
127+ createdAt: 2026-10-26T10:30:00.000Z
128+ body: |
129+ Done in `demo.acp.sdk/nodejs/` (with an index `demo.acp.sdk/README.{en,fr}.md` for the other languages, tickets 168–172). Nothing changed in mm's Go code.
130+
131+ - `minime.js`, no dependency (Node >= 20): `Agent.start({config, cwd, mm, onPermission, onStderr})`, `complete(prompt, {signal, onEvent})` → `{text, stopReason, usage}`, `stream(prompt, {signal})` → async iterator (text, thinking, tool_call, tool_result, done), cancel with an `AbortSignal` (→ `session/cancel`, ends `cancelled` with the text so far; leaving the loop early cancels too), `reset()` (new session), `close()`. One Agent = one `mm -acp` process = one conversation; one turn at a time per Agent. Without `onPermission`, every call that needs a confirmation is refused. mm's JSON-RPC errors are rejected with mm's words (`data` included).
132+ - Task 1: raw JSON-RPC chosen; the official ACP TypeScript library was NOT looked at (no network in the sandbox).
133+ - Message shapes captured from `mm -acp` (v1.0.1) before writing: `session/update` kinds `agent_message_chunk`, `agent_thought_chunk`, `tool_call`, `tool_call_update` (rawOutput.output), `usage_update`, `available_commands_update`; `session/request_permission` with options allow / allow_always / reject / never; `session/prompt` result `{stopReason, usage}`.
134+ - Tests: `npm test` (node --test test/minime.test.js), 11 tests against `test/fake-mm.js`, which plays mm's side (answers, a permission, a slow turn to cancel, a crash). A bare `node --test` would also run fake-mm.js and hang.
135+ - Measured on llmman (Qwen3.5 4B, `yolo: false`): complete 2.9 s; stream with a read-only callback (`find … | wc -l` allowed, answer streamed); cancel after 3.0 s (`cancelled`, 383 characters kept; the next question works but does not know the story — mm drops an unanswered question); permission: `pwd` refused → the model invented `/root`, allowed → the real directory. Seen in three runs before `find` was allowed: the same refused command repeated until mm's loop detector stopped the turn, and `stream()` rejected with that message.
136+ - Not done: npm package (it would have to ship the binary), `session/load` / `session/resume`, images and attachments, `ask_user` forms.
new file mode 100644
@@ -0,0 +1,136 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 167
3+title: "Node.js client over ACP: a first SDK prototype for other languages"
4+state: closed
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-26T06:00:00.000Z
9+updatedAt: 2026-10-26T11:00:00.000Z
10+labels:
11+ - kind::feature
12+milestone: v1.0.2
13+epic: SDK
14+related:
15+ - 139
16+ - 71
17+ - 113
18+ - 168
19+ - 169
20+ - 170
21+ - 171
22+ - 172
23+body: |
24+ ## Goal
25+ Prove that mm can be used as a library from another language by driving `mm -acp` over ACP (JSON-RPC on stdin/stdout), with NO change to mm. Node.js first (user's choice, 2026-10-26); Python later if the prototype convinces. Prototype only: one demo folder, not a published package.
26+
27+ This is the "other languages" path. It complements the Go SDK of ticket 139 (in-process, no binary) and does not replace it. Remote use (an agent in another machine or container) stays for `mm serve` (ticket 113 / proposal D of 139).
28+
29+ ## Why ACP fits (checked in internal/acp and docs/en/reference/acp.md on 2026-10-26)
30+ | Wanted | ACP, already in mm |
31+ |---|---|
32+ | run a completion | `session/prompt` |
33+ | stream | `session/update` notifications (text chunks, thoughts, tool calls, plan) |
34+ | not streamed | join the text chunks until `session/prompt` answers (its `stopReason`) |
35+ | cancel | `session/cancel` |
36+ | tool confirmation (`yolo: false`) | mm sends `session/request_permission` to the client → a callback |
37+ | `ask_user` | `elicitation/create`, only when the client advertises `clientCapabilities.elicitation.form` at `initialize` |
38+ | keep the conversation | one ACP session = one history; `session/load` / `session/resume` with `sessions.enabled` |
39+
40+ - mm asks nothing else of the client: it reads files and runs commands itself, so the client does not have to implement `fs/*` or `terminal/*`.
41+ - One agent = one process: several agents run side by side, the global state of the Go code (`config.Cfg`, `ui.SetActive`) is no problem here.
42+ - Everything mm does works unchanged: hooks, MCP, `mmConfigs`, skill/tool routing, struggle signals.
43+
44+ ## Proposed shape (to discuss in the prototype)
45+ ```js
46+ import { Agent } from "./minime.js";
47+
48+ const agent = await Agent.start({
49+ config: "agent.yaml", // passed as AGENT_CONFIG (absolute path)
50+ cwd: process.cwd(), // the session's cwd (session/new)
51+ onPermission: (call) => call.kind === "read", // no callback → refuse
52+ });
53+
54+ const text = await agent.complete("Explain this repository"); // not streamed
55+
56+ for await (const ev of agent.stream("And the tests?")) { // streamed
57+ if (ev.kind === "text") process.stdout.write(ev.text);
58+ }
59+
60+ const ac = new AbortController();
61+ setTimeout(() => ac.abort(), 5000);
62+ await agent.complete("A long task", { signal: ac.signal }); // abort → session/cancel
63+
64+ await agent.close(); // closes stdin, mm exits
65+ ```
66+ - Plain Node.js (built-in `child_process`, `readline`), no dependency, ESM, Node 22 (the sandbox has v22.22.1).
67+ - Events reduced to a few kinds: `text`, `thinking`, `tool_call`, `tool_result`, `done` — not the editor-oriented detail of ACP (diffs, statuses).
68+ - The `mm` binary is found on the PATH or through `MM_BIN` (the convention of the demo hooks).
69+ - stderr of mm (banner, warnings, `[acp]` lines) is drained, optionally passed to a callback, never mixed with the answer.
70+ - Check first whether the official ACP TypeScript library (`@agentclientprotocol/sdk` or similar — not verified, no network in the sandbox) is worth using instead of raw JSON-RPC; raw JSON-RPC keeps the prototype dependency-free.
71+
72+ ## Limits to state in the README
73+ - The `mm` binary must be installed (a later package could ship it per platform, as some npm packages do for native tools).
74+ - Local only: stdio.
75+ - The config is a file path (AGENT_CONFIG); no in-memory config.
76+
77+ ## Done when
78+ - `demo.acp.sdk/nodejs/` (location chosen by the user on 2026-10-26, instead of `demos/node-acp-client/`) holds `minime.js` (the client), one example each for not streamed, streamed and cancelled, and README EN + FR with the results measured on llmman.
79+ - Permissions: a refused and an accepted tool call shown with an agent with `yolo: false`.
80+ - Nothing changed in mm's Go code.
81+tasks:
82+ - id: 1
83+ title: Check the official ACP TypeScript library vs raw JSON-RPC; decide
84+ state: closed
85+ priority: none
86+ author:
87+ name: k33g
88+ email: ph.charriere@gmail.com
89+ createdAt: 2026-10-26T06:00:00.000Z
90+ - id: 2
91+ title: "minime.js: start (initialize + session/new), complete, stream, cancel, close"
92+ state: closed
93+ priority: none
94+ author:
95+ name: k33g
96+ email: ph.charriere@gmail.com
97+ createdAt: 2026-10-26T06:00:00.000Z
98+ - id: 3
99+ title: Permission callback (session/request_permission), refuse by default
100+ state: closed
101+ priority: none
102+ author:
103+ name: k33g
104+ email: ph.charriere@gmail.com
105+ createdAt: 2026-10-26T06:00:00.000Z
106+ - id: 4
107+ title: Examples (not streamed, streamed, cancelled, permission) run on llmman
108+ state: closed
109+ priority: none
110+ author:
111+ name: k33g
112+ email: ph.charriere@gmail.com
113+ createdAt: 2026-10-26T06:00:00.000Z
114+ - id: 5
115+ title: README EN + FR with measured results and limits
116+ state: closed
117+ priority: none
118+ author:
119+ name: k33g
120+ email: ph.charriere@gmail.com
121+ createdAt: 2026-10-26T06:00:00.000Z
122+comments:
123+ - id: 1
124+ author:
125+ name: k33g
126+ email: ph.charriere@gmail.com
127+ createdAt: 2026-10-26T10:30:00.000Z
128+ body: |
129+ Done in `demo.acp.sdk/nodejs/` (with an index `demo.acp.sdk/README.{en,fr}.md` for the other languages, tickets 168–172). Nothing changed in mm's Go code.
130+
131+ - `minime.js`, no dependency (Node >= 20): `Agent.start({config, cwd, mm, onPermission, onStderr})`, `complete(prompt, {signal, onEvent})` → `{text, stopReason, usage}`, `stream(prompt, {signal})` → async iterator (text, thinking, tool_call, tool_result, done), cancel with an `AbortSignal` (→ `session/cancel`, ends `cancelled` with the text so far; leaving the loop early cancels too), `reset()` (new session), `close()`. One Agent = one `mm -acp` process = one conversation; one turn at a time per Agent. Without `onPermission`, every call that needs a confirmation is refused. mm's JSON-RPC errors are rejected with mm's words (`data` included).
132+ - Task 1: raw JSON-RPC chosen; the official ACP TypeScript library was NOT looked at (no network in the sandbox).
133+ - Message shapes captured from `mm -acp` (v1.0.1) before writing: `session/update` kinds `agent_message_chunk`, `agent_thought_chunk`, `tool_call`, `tool_call_update` (rawOutput.output), `usage_update`, `available_commands_update`; `session/request_permission` with options allow / allow_always / reject / never; `session/prompt` result `{stopReason, usage}`.
134+ - Tests: `npm test` (node --test test/minime.test.js), 11 tests against `test/fake-mm.js`, which plays mm's side (answers, a permission, a slow turn to cancel, a crash). A bare `node --test` would also run fake-mm.js and hang.
135+ - Measured on llmman (Qwen3.5 4B, `yolo: false`): complete 2.9 s; stream with a read-only callback (`find … | wc -l` allowed, answer streamed); cancel after 3.0 s (`cancelled`, 383 characters kept; the next question works but does not know the story — mm drops an unanswered question); permission: `pwd` refused → the model invented `/root`, allowed → the real directory. Seen in three runs before `find` was allowed: the same refused command repeated until mm's loop detector stopped the turn, and `stream()` rejected with that message.
136+ - Not done: npm package (it would have to ship the binary), `session/load` / `session/resume`, images and attachments, `ask_user` forms.
added .tickets/issues/0168-go-client-over-acp-sdk-prototype.yaml +72 -0
new file mode 100644
@@ -0,0 +1,72 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 168
3+title: "Go client over ACP: an out-of-process SDK prototype"
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-26T06:30:00.000Z
9+updatedAt: 2026-10-26T06:30:00.000Z
10+labels:
11+ - kind::feature
12+epic: SDK
13+related:
14+ - 167
15+ - 139
16+body: |
17+ ## Goal
18+ A Go program drives `mm -acp` as a child process. Unlike ticket 139 (in-process library, no binary), this one needs the binary but works TODAY with no change to mm, and gives process isolation (one agent per process, so the global state of mm's Go code is no problem).
19+
20+ ## Shared ground
21+ Same idea as ticket 167 (Node.js), in another language: drive `mm -acp` over ACP (JSON-RPC, one message per line on stdin/stdout), with NO change to mm. Ticket 167 holds the ACP mapping (`initialize`, `session/new`, `session/prompt`, `session/update`, `session/cancel`, `session/request_permission`, `elicitation/create`) and the limits (the `mm` binary must be installed, local stdio only, config by `AGENT_CONFIG`). The same API as 167: start an agent from a config file, `complete` (not streamed), `stream`, cancel, a permission callback that refuses by default, close. Start once the Node.js prototype has settled the API.
22+
23+ ## Specific to Go
24+ - mm already IS such a client: `internal/ask` (pool.go, client.go, elicit.go) starts child `mm -acp` processes with `github.com/coder/acp-go-sdk` (`sdk.NewClientSideConnection`) for `/ask`, `ask_agent` and `mm --ask`. The prototype can follow that code — but as its own module under `demos/` (like `demos/decision-chat-golang/hooks/ask-decider`), since `internal/` cannot be imported.
25+ - API in Go idiom: `agent.Complete(ctx, prompt, opts...)`, streaming through a callback or an `iter.Seq2[Event, error]`, cancellation by `ctx` (→ `session/cancel`).
26+ - Worth writing down in the README: when to choose this (isolation, works now) vs ticket 139 (no binary, in-process).
27+
28+ ## Done when
29+ - `demos/go-acp-client/` holds the client, one example each for not streamed, streamed, cancelled and a permission (agent with `yolo: false`), and README EN + FR with results measured on llmman. The module has `go test`-ed parsing of the events (no model needed).
30+ - Nothing changed in mm's Go code.
31+tasks:
32+ - id: 1
33+ title: "Decide: reuse acp-go-sdk (as internal/ask does) — expected — or raw JSON-RPC"
34+ state: open
35+ priority: none
36+ author:
37+ name: k33g
38+ email: ph.charriere@gmail.com
39+ createdAt: 2026-10-26T06:30:00.000Z
40+ - id: 2
41+ title: "Client: start (initialize + session/new), complete, stream, cancel, close"
42+ state: open
43+ priority: none
44+ author:
45+ name: k33g
46+ email: ph.charriere@gmail.com
47+ createdAt: 2026-10-26T06:30:00.000Z
48+ - id: 3
49+ title: "Permission callback (session/request_permission), refuse by default"
50+ state: open
51+ priority: none
52+ author:
53+ name: k33g
54+ email: ph.charriere@gmail.com
55+ createdAt: 2026-10-26T06:30:00.000Z
56+ - id: 4
57+ title: "Examples (not streamed, streamed, cancelled, permission) run on llmman"
58+ state: open
59+ priority: none
60+ author:
61+ name: k33g
62+ email: ph.charriere@gmail.com
63+ createdAt: 2026-10-26T06:30:00.000Z
64+ - id: 5
65+ title: "README EN + FR with measured results and limits"
66+ state: open
67+ priority: none
68+ author:
69+ name: k33g
70+ email: ph.charriere@gmail.com
71+ createdAt: 2026-10-26T06:30:00.000Z
72+comments: []
new file mode 100644
@@ -0,0 +1,72 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 168
3+title: "Go client over ACP: an out-of-process SDK prototype"
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-26T06:30:00.000Z
9+updatedAt: 2026-10-26T06:30:00.000Z
10+labels:
11+ - kind::feature
12+epic: SDK
13+related:
14+ - 167
15+ - 139
16+body: |
17+ ## Goal
18+ A Go program drives `mm -acp` as a child process. Unlike ticket 139 (in-process library, no binary), this one needs the binary but works TODAY with no change to mm, and gives process isolation (one agent per process, so the global state of mm's Go code is no problem).
19+
20+ ## Shared ground
21+ Same idea as ticket 167 (Node.js), in another language: drive `mm -acp` over ACP (JSON-RPC, one message per line on stdin/stdout), with NO change to mm. Ticket 167 holds the ACP mapping (`initialize`, `session/new`, `session/prompt`, `session/update`, `session/cancel`, `session/request_permission`, `elicitation/create`) and the limits (the `mm` binary must be installed, local stdio only, config by `AGENT_CONFIG`). The same API as 167: start an agent from a config file, `complete` (not streamed), `stream`, cancel, a permission callback that refuses by default, close. Start once the Node.js prototype has settled the API.
22+
23+ ## Specific to Go
24+ - mm already IS such a client: `internal/ask` (pool.go, client.go, elicit.go) starts child `mm -acp` processes with `github.com/coder/acp-go-sdk` (`sdk.NewClientSideConnection`) for `/ask`, `ask_agent` and `mm --ask`. The prototype can follow that code — but as its own module under `demos/` (like `demos/decision-chat-golang/hooks/ask-decider`), since `internal/` cannot be imported.
25+ - API in Go idiom: `agent.Complete(ctx, prompt, opts...)`, streaming through a callback or an `iter.Seq2[Event, error]`, cancellation by `ctx` (→ `session/cancel`).
26+ - Worth writing down in the README: when to choose this (isolation, works now) vs ticket 139 (no binary, in-process).
27+
28+ ## Done when
29+ - `demos/go-acp-client/` holds the client, one example each for not streamed, streamed, cancelled and a permission (agent with `yolo: false`), and README EN + FR with results measured on llmman. The module has `go test`-ed parsing of the events (no model needed).
30+ - Nothing changed in mm's Go code.
31+tasks:
32+ - id: 1
33+ title: "Decide: reuse acp-go-sdk (as internal/ask does) — expected — or raw JSON-RPC"
34+ state: open
35+ priority: none
36+ author:
37+ name: k33g
38+ email: ph.charriere@gmail.com
39+ createdAt: 2026-10-26T06:30:00.000Z
40+ - id: 2
41+ title: "Client: start (initialize + session/new), complete, stream, cancel, close"
42+ state: open
43+ priority: none
44+ author:
45+ name: k33g
46+ email: ph.charriere@gmail.com
47+ createdAt: 2026-10-26T06:30:00.000Z
48+ - id: 3
49+ title: "Permission callback (session/request_permission), refuse by default"
50+ state: open
51+ priority: none
52+ author:
53+ name: k33g
54+ email: ph.charriere@gmail.com
55+ createdAt: 2026-10-26T06:30:00.000Z
56+ - id: 4
57+ title: "Examples (not streamed, streamed, cancelled, permission) run on llmman"
58+ state: open
59+ priority: none
60+ author:
61+ name: k33g
62+ email: ph.charriere@gmail.com
63+ createdAt: 2026-10-26T06:30:00.000Z
64+ - id: 5
65+ title: "README EN + FR with measured results and limits"
66+ state: open
67+ priority: none
68+ author:
69+ name: k33g
70+ email: ph.charriere@gmail.com
71+ createdAt: 2026-10-26T06:30:00.000Z
72+comments: []
added .tickets/issues/0169-python-client-over-acp-sdk-prototype.yaml +73 -0
new file mode 100644
@@ -0,0 +1,73 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 169
3+title: "Python client over ACP: an SDK prototype"
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-26T06:30:00.000Z
9+updatedAt: 2026-10-26T06:30:00.000Z
10+labels:
11+ - kind::feature
12+epic: SDK
13+related:
14+ - 167
15+ - 139
16+body: |
17+ ## Goal
18+ A Python program uses mm as a library by driving `mm -acp`. The first language asked for (2026-10-26), started after the Node.js prototype (ticket 167).
19+
20+ ## Shared ground
21+ Same idea as ticket 167 (Node.js), in another language: drive `mm -acp` over ACP (JSON-RPC, one message per line on stdin/stdout), with NO change to mm. Ticket 167 holds the ACP mapping (`initialize`, `session/new`, `session/prompt`, `session/update`, `session/cancel`, `session/request_permission`, `elicitation/create`) and the limits (the `mm` binary must be installed, local stdio only, config by `AGENT_CONFIG`). The same API as 167: start an agent from a config file, `complete` (not streamed), `stream`, cancel, a permission callback that refuses by default, close. Start once the Node.js prototype has settled the API.
22+
23+ ## Specific to Python
24+ - `asyncio` with the standard library only (`asyncio.create_subprocess_exec`, stdin/stdout streams, `json`): no dependency. Python 3.14 is in the sandbox.
25+ - API: `async with minime.Agent("agent.yaml", cwd=".", on_permission=...) as agent`, `await agent.complete(...)`, `async for ev in agent.stream(...)`, cancellation by cancelling the task (→ `session/cancel`).
26+ - Check whether an official ACP Python library exists (`agent-client-protocol` on PyPI is believed to — NOT verified, no network in the sandbox) and whether it is worth a dependency.
27+ - Later, if it becomes a package: ship the `mm` binary inside per-platform wheels (as ruff or uv do) so `pip install` is enough.
28+
29+ ## Done when
30+ - `demos/python-acp-client/` holds the client, one example each for not streamed, streamed, cancelled and a permission (agent with `yolo: false`), and README EN + FR with results measured on llmman.
31+ - Nothing changed in mm's Go code.
32+tasks:
33+ - id: 1
34+ title: "Check the official ACP Python library vs stdlib JSON-RPC; decide"
35+ state: open
36+ priority: none
37+ author:
38+ name: k33g
39+ email: ph.charriere@gmail.com
40+ createdAt: 2026-10-26T06:30:00.000Z
41+ - id: 2
42+ title: "Client: start (initialize + session/new), complete, stream, cancel, close"
43+ state: open
44+ priority: none
45+ author:
46+ name: k33g
47+ email: ph.charriere@gmail.com
48+ createdAt: 2026-10-26T06:30:00.000Z
49+ - id: 3
50+ title: "Permission callback (session/request_permission), refuse by default"
51+ state: open
52+ priority: none
53+ author:
54+ name: k33g
55+ email: ph.charriere@gmail.com
56+ createdAt: 2026-10-26T06:30:00.000Z
57+ - id: 4
58+ title: "Examples (not streamed, streamed, cancelled, permission) run on llmman"
59+ state: open
60+ priority: none
61+ author:
62+ name: k33g
63+ email: ph.charriere@gmail.com
64+ createdAt: 2026-10-26T06:30:00.000Z
65+ - id: 5
66+ title: "README EN + FR with measured results and limits"
67+ state: open
68+ priority: none
69+ author:
70+ name: k33g
71+ email: ph.charriere@gmail.com
72+ createdAt: 2026-10-26T06:30:00.000Z
73+comments: []
new file mode 100644
@@ -0,0 +1,73 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 169
3+title: "Python client over ACP: an SDK prototype"
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-26T06:30:00.000Z
9+updatedAt: 2026-10-26T06:30:00.000Z
10+labels:
11+ - kind::feature
12+epic: SDK
13+related:
14+ - 167
15+ - 139
16+body: |
17+ ## Goal
18+ A Python program uses mm as a library by driving `mm -acp`. The first language asked for (2026-10-26), started after the Node.js prototype (ticket 167).
19+
20+ ## Shared ground
21+ Same idea as ticket 167 (Node.js), in another language: drive `mm -acp` over ACP (JSON-RPC, one message per line on stdin/stdout), with NO change to mm. Ticket 167 holds the ACP mapping (`initialize`, `session/new`, `session/prompt`, `session/update`, `session/cancel`, `session/request_permission`, `elicitation/create`) and the limits (the `mm` binary must be installed, local stdio only, config by `AGENT_CONFIG`). The same API as 167: start an agent from a config file, `complete` (not streamed), `stream`, cancel, a permission callback that refuses by default, close. Start once the Node.js prototype has settled the API.
22+
23+ ## Specific to Python
24+ - `asyncio` with the standard library only (`asyncio.create_subprocess_exec`, stdin/stdout streams, `json`): no dependency. Python 3.14 is in the sandbox.
25+ - API: `async with minime.Agent("agent.yaml", cwd=".", on_permission=...) as agent`, `await agent.complete(...)`, `async for ev in agent.stream(...)`, cancellation by cancelling the task (→ `session/cancel`).
26+ - Check whether an official ACP Python library exists (`agent-client-protocol` on PyPI is believed to — NOT verified, no network in the sandbox) and whether it is worth a dependency.
27+ - Later, if it becomes a package: ship the `mm` binary inside per-platform wheels (as ruff or uv do) so `pip install` is enough.
28+
29+ ## Done when
30+ - `demos/python-acp-client/` holds the client, one example each for not streamed, streamed, cancelled and a permission (agent with `yolo: false`), and README EN + FR with results measured on llmman.
31+ - Nothing changed in mm's Go code.
32+tasks:
33+ - id: 1
34+ title: "Check the official ACP Python library vs stdlib JSON-RPC; decide"
35+ state: open
36+ priority: none
37+ author:
38+ name: k33g
39+ email: ph.charriere@gmail.com
40+ createdAt: 2026-10-26T06:30:00.000Z
41+ - id: 2
42+ title: "Client: start (initialize + session/new), complete, stream, cancel, close"
43+ state: open
44+ priority: none
45+ author:
46+ name: k33g
47+ email: ph.charriere@gmail.com
48+ createdAt: 2026-10-26T06:30:00.000Z
49+ - id: 3
50+ title: "Permission callback (session/request_permission), refuse by default"
51+ state: open
52+ priority: none
53+ author:
54+ name: k33g
55+ email: ph.charriere@gmail.com
56+ createdAt: 2026-10-26T06:30:00.000Z
57+ - id: 4
58+ title: "Examples (not streamed, streamed, cancelled, permission) run on llmman"
59+ state: open
60+ priority: none
61+ author:
62+ name: k33g
63+ email: ph.charriere@gmail.com
64+ createdAt: 2026-10-26T06:30:00.000Z
65+ - id: 5
66+ title: "README EN + FR with measured results and limits"
67+ state: open
68+ priority: none
69+ author:
70+ name: k33g
71+ email: ph.charriere@gmail.com
72+ createdAt: 2026-10-26T06:30:00.000Z
73+comments: []
added .tickets/issues/0170-rust-client-over-acp-sdk-prototype.yaml +80 -0
new file mode 100644
@@ -0,0 +1,80 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 170
3+title: "Rust client over ACP: an SDK prototype"
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-26T06:30:00.000Z
9+updatedAt: 2026-10-26T06:30:00.000Z
10+labels:
11+ - kind::feature
12+epic: SDK
13+related:
14+ - 167
15+ - 139
16+body: |
17+ ## Goal
18+ A Rust program uses mm as a library by driving `mm -acp`.
19+
20+ ## Shared ground
21+ Same idea as ticket 167 (Node.js), in another language: drive `mm -acp` over ACP (JSON-RPC, one message per line on stdin/stdout), with NO change to mm. Ticket 167 holds the ACP mapping (`initialize`, `session/new`, `session/prompt`, `session/update`, `session/cancel`, `session/request_permission`, `elicitation/create`) and the limits (the `mm` binary must be installed, local stdio only, config by `AGENT_CONFIG`). The same API as 167: start an agent from a config file, `complete` (not streamed), `stream`, cancel, a permission callback that refuses by default, close. Start once the Node.js prototype has settled the API.
22+
23+ ## Specific to Rust
24+ - ACP comes from Zed, written in Rust: a Rust crate for the protocol (`agent-client-protocol`) is believed to exist — NOT verified (no network in the sandbox). Otherwise `tokio` (`tokio::process::Command`, line-delimited JSON) + `serde_json`.
25+ - API: `Agent::start(config).await?`, `agent.complete(prompt).await?`, `agent.stream(prompt)` returning a `Stream<Item = Result<Event>>`, cancellation by dropping the future or a `CancellationToken` (→ `session/cancel`).
26+ - No Rust toolchain in this sandbox (`cargo` absent): it must be installed, or the prototype built and run on the user's machine.
27+
28+ ## Done when
29+ - `demos/rust-acp-client/` holds the client, one example each for not streamed, streamed, cancelled and a permission (agent with `yolo: false`), and README EN + FR with results measured on llmman.
30+ - Nothing changed in mm's Go code.
31+tasks:
32+ - id: 1
33+ title: "Check the Rust ACP crate vs tokio + serde_json; decide"
34+ state: open
35+ priority: none
36+ author:
37+ name: k33g
38+ email: ph.charriere@gmail.com
39+ createdAt: 2026-10-26T06:30:00.000Z
40+ - id: 2
41+ title: "Get a Rust toolchain (sandbox kit or the user's machine)"
42+ state: open
43+ priority: none
44+ author:
45+ name: k33g
46+ email: ph.charriere@gmail.com
47+ createdAt: 2026-10-26T06:30:00.000Z
48+ - id: 3
49+ title: "Client: start (initialize + session/new), complete, stream, cancel, close"
50+ state: open
51+ priority: none
52+ author:
53+ name: k33g
54+ email: ph.charriere@gmail.com
55+ createdAt: 2026-10-26T06:30:00.000Z
56+ - id: 4
57+ title: "Permission callback (session/request_permission), refuse by default"
58+ state: open
59+ priority: none
60+ author:
61+ name: k33g
62+ email: ph.charriere@gmail.com
63+ createdAt: 2026-10-26T06:30:00.000Z
64+ - id: 5
65+ title: "Examples (not streamed, streamed, cancelled, permission) run on llmman"
66+ state: open
67+ priority: none
68+ author:
69+ name: k33g
70+ email: ph.charriere@gmail.com
71+ createdAt: 2026-10-26T06:30:00.000Z
72+ - id: 6
73+ title: "README EN + FR with measured results and limits"
74+ state: open
75+ priority: none
76+ author:
77+ name: k33g
78+ email: ph.charriere@gmail.com
79+ createdAt: 2026-10-26T06:30:00.000Z
80+comments: []
new file mode 100644
@@ -0,0 +1,80 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 170
3+title: "Rust client over ACP: an SDK prototype"
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-26T06:30:00.000Z
9+updatedAt: 2026-10-26T06:30:00.000Z
10+labels:
11+ - kind::feature
12+epic: SDK
13+related:
14+ - 167
15+ - 139
16+body: |
17+ ## Goal
18+ A Rust program uses mm as a library by driving `mm -acp`.
19+
20+ ## Shared ground
21+ Same idea as ticket 167 (Node.js), in another language: drive `mm -acp` over ACP (JSON-RPC, one message per line on stdin/stdout), with NO change to mm. Ticket 167 holds the ACP mapping (`initialize`, `session/new`, `session/prompt`, `session/update`, `session/cancel`, `session/request_permission`, `elicitation/create`) and the limits (the `mm` binary must be installed, local stdio only, config by `AGENT_CONFIG`). The same API as 167: start an agent from a config file, `complete` (not streamed), `stream`, cancel, a permission callback that refuses by default, close. Start once the Node.js prototype has settled the API.
22+
23+ ## Specific to Rust
24+ - ACP comes from Zed, written in Rust: a Rust crate for the protocol (`agent-client-protocol`) is believed to exist — NOT verified (no network in the sandbox). Otherwise `tokio` (`tokio::process::Command`, line-delimited JSON) + `serde_json`.
25+ - API: `Agent::start(config).await?`, `agent.complete(prompt).await?`, `agent.stream(prompt)` returning a `Stream<Item = Result<Event>>`, cancellation by dropping the future or a `CancellationToken` (→ `session/cancel`).
26+ - No Rust toolchain in this sandbox (`cargo` absent): it must be installed, or the prototype built and run on the user's machine.
27+
28+ ## Done when
29+ - `demos/rust-acp-client/` holds the client, one example each for not streamed, streamed, cancelled and a permission (agent with `yolo: false`), and README EN + FR with results measured on llmman.
30+ - Nothing changed in mm's Go code.
31+tasks:
32+ - id: 1
33+ title: "Check the Rust ACP crate vs tokio + serde_json; decide"
34+ state: open
35+ priority: none
36+ author:
37+ name: k33g
38+ email: ph.charriere@gmail.com
39+ createdAt: 2026-10-26T06:30:00.000Z
40+ - id: 2
41+ title: "Get a Rust toolchain (sandbox kit or the user's machine)"
42+ state: open
43+ priority: none
44+ author:
45+ name: k33g
46+ email: ph.charriere@gmail.com
47+ createdAt: 2026-10-26T06:30:00.000Z
48+ - id: 3
49+ title: "Client: start (initialize + session/new), complete, stream, cancel, close"
50+ state: open
51+ priority: none
52+ author:
53+ name: k33g
54+ email: ph.charriere@gmail.com
55+ createdAt: 2026-10-26T06:30:00.000Z
56+ - id: 4
57+ title: "Permission callback (session/request_permission), refuse by default"
58+ state: open
59+ priority: none
60+ author:
61+ name: k33g
62+ email: ph.charriere@gmail.com
63+ createdAt: 2026-10-26T06:30:00.000Z
64+ - id: 5
65+ title: "Examples (not streamed, streamed, cancelled, permission) run on llmman"
66+ state: open
67+ priority: none
68+ author:
69+ name: k33g
70+ email: ph.charriere@gmail.com
71+ createdAt: 2026-10-26T06:30:00.000Z
72+ - id: 6
73+ title: "README EN + FR with measured results and limits"
74+ state: open
75+ priority: none
76+ author:
77+ name: k33g
78+ email: ph.charriere@gmail.com
79+ createdAt: 2026-10-26T06:30:00.000Z
80+comments: []
added .tickets/issues/0171-swift-client-over-acp-sdk-prototype.yaml +80 -0
new file mode 100644
@@ -0,0 +1,80 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 171
3+title: "Swift client over ACP: an SDK prototype"
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-26T06:30:00.000Z
9+updatedAt: 2026-10-26T06:30:00.000Z
10+labels:
11+ - kind::feature
12+epic: SDK
13+related:
14+ - 167
15+ - 139
16+body: |
17+ ## Goal
18+ A Swift program (a macOS app, a command-line tool) uses mm as a library by driving `mm -acp` — a path towards a native Mac front end for mm.
19+
20+ ## Shared ground
21+ Same idea as ticket 167 (Node.js), in another language: drive `mm -acp` over ACP (JSON-RPC, one message per line on stdin/stdout), with NO change to mm. Ticket 167 holds the ACP mapping (`initialize`, `session/new`, `session/prompt`, `session/update`, `session/cancel`, `session/request_permission`, `elicitation/create`) and the limits (the `mm` binary must be installed, local stdio only, config by `AGENT_CONFIG`). The same API as 167: start an agent from a config file, `complete` (not streamed), `stream`, cancel, a permission callback that refuses by default, close. Start once the Node.js prototype has settled the API.
22+
23+ ## Specific to Swift
24+ - Foundation `Process` + `Pipe`, `FileHandle.bytes.lines` for the line-delimited JSON, `Codable` for the messages, Swift concurrency: `func complete(_:) async throws -> String`, `func stream(_:) -> AsyncThrowingStream<Event, Error>`, cancellation through `Task.cancel()` (→ `session/cancel`).
25+ - Check whether a Swift ACP package exists (not verified).
26+ - No Swift toolchain in this sandbox (Linux, `swift` absent): built and run on the user's Mac. A sandboxed macOS app cannot start an arbitrary binary without entitlements — fine for a command-line prototype, to note for an app.
27+
28+ ## Done when
29+ - `demos/swift-acp-client/` holds the client, one example each for not streamed, streamed, cancelled and a permission (agent with `yolo: false`), and README EN + FR with results measured on llmman. A Swift package (`Package.swift`) with an executable target.
30+ - Nothing changed in mm's Go code.
31+tasks:
32+ - id: 1
33+ title: "Check for a Swift ACP package; decide"
34+ state: open
35+ priority: none
36+ author:
37+ name: k33g
38+ email: ph.charriere@gmail.com
39+ createdAt: 2026-10-26T06:30:00.000Z
40+ - id: 2
41+ title: "Build and run on the user's Mac (no Swift in the sandbox)"
42+ state: open
43+ priority: none
44+ author:
45+ name: k33g
46+ email: ph.charriere@gmail.com
47+ createdAt: 2026-10-26T06:30:00.000Z
48+ - id: 3
49+ title: "Client: start (initialize + session/new), complete, stream, cancel, close"
50+ state: open
51+ priority: none
52+ author:
53+ name: k33g
54+ email: ph.charriere@gmail.com
55+ createdAt: 2026-10-26T06:30:00.000Z
56+ - id: 4
57+ title: "Permission callback (session/request_permission), refuse by default"
58+ state: open
59+ priority: none
60+ author:
61+ name: k33g
62+ email: ph.charriere@gmail.com
63+ createdAt: 2026-10-26T06:30:00.000Z
64+ - id: 5
65+ title: "Examples (not streamed, streamed, cancelled, permission) run on llmman"
66+ state: open
67+ priority: none
68+ author:
69+ name: k33g
70+ email: ph.charriere@gmail.com
71+ createdAt: 2026-10-26T06:30:00.000Z
72+ - id: 6
73+ title: "README EN + FR with measured results and limits"
74+ state: open
75+ priority: none
76+ author:
77+ name: k33g
78+ email: ph.charriere@gmail.com
79+ createdAt: 2026-10-26T06:30:00.000Z
80+comments: []
new file mode 100644
@@ -0,0 +1,80 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 171
3+title: "Swift client over ACP: an SDK prototype"
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-26T06:30:00.000Z
9+updatedAt: 2026-10-26T06:30:00.000Z
10+labels:
11+ - kind::feature
12+epic: SDK
13+related:
14+ - 167
15+ - 139
16+body: |
17+ ## Goal
18+ A Swift program (a macOS app, a command-line tool) uses mm as a library by driving `mm -acp` — a path towards a native Mac front end for mm.
19+
20+ ## Shared ground
21+ Same idea as ticket 167 (Node.js), in another language: drive `mm -acp` over ACP (JSON-RPC, one message per line on stdin/stdout), with NO change to mm. Ticket 167 holds the ACP mapping (`initialize`, `session/new`, `session/prompt`, `session/update`, `session/cancel`, `session/request_permission`, `elicitation/create`) and the limits (the `mm` binary must be installed, local stdio only, config by `AGENT_CONFIG`). The same API as 167: start an agent from a config file, `complete` (not streamed), `stream`, cancel, a permission callback that refuses by default, close. Start once the Node.js prototype has settled the API.
22+
23+ ## Specific to Swift
24+ - Foundation `Process` + `Pipe`, `FileHandle.bytes.lines` for the line-delimited JSON, `Codable` for the messages, Swift concurrency: `func complete(_:) async throws -> String`, `func stream(_:) -> AsyncThrowingStream<Event, Error>`, cancellation through `Task.cancel()` (→ `session/cancel`).
25+ - Check whether a Swift ACP package exists (not verified).
26+ - No Swift toolchain in this sandbox (Linux, `swift` absent): built and run on the user's Mac. A sandboxed macOS app cannot start an arbitrary binary without entitlements — fine for a command-line prototype, to note for an app.
27+
28+ ## Done when
29+ - `demos/swift-acp-client/` holds the client, one example each for not streamed, streamed, cancelled and a permission (agent with `yolo: false`), and README EN + FR with results measured on llmman. A Swift package (`Package.swift`) with an executable target.
30+ - Nothing changed in mm's Go code.
31+tasks:
32+ - id: 1
33+ title: "Check for a Swift ACP package; decide"
34+ state: open
35+ priority: none
36+ author:
37+ name: k33g
38+ email: ph.charriere@gmail.com
39+ createdAt: 2026-10-26T06:30:00.000Z
40+ - id: 2
41+ title: "Build and run on the user's Mac (no Swift in the sandbox)"
42+ state: open
43+ priority: none
44+ author:
45+ name: k33g
46+ email: ph.charriere@gmail.com
47+ createdAt: 2026-10-26T06:30:00.000Z
48+ - id: 3
49+ title: "Client: start (initialize + session/new), complete, stream, cancel, close"
50+ state: open
51+ priority: none
52+ author:
53+ name: k33g
54+ email: ph.charriere@gmail.com
55+ createdAt: 2026-10-26T06:30:00.000Z
56+ - id: 4
57+ title: "Permission callback (session/request_permission), refuse by default"
58+ state: open
59+ priority: none
60+ author:
61+ name: k33g
62+ email: ph.charriere@gmail.com
63+ createdAt: 2026-10-26T06:30:00.000Z
64+ - id: 5
65+ title: "Examples (not streamed, streamed, cancelled, permission) run on llmman"
66+ state: open
67+ priority: none
68+ author:
69+ name: k33g
70+ email: ph.charriere@gmail.com
71+ createdAt: 2026-10-26T06:30:00.000Z
72+ - id: 6
73+ title: "README EN + FR with measured results and limits"
74+ state: open
75+ priority: none
76+ author:
77+ name: k33g
78+ email: ph.charriere@gmail.com
79+ createdAt: 2026-10-26T06:30:00.000Z
80+comments: []
added .tickets/issues/0172-nushell-script-client-over-acp.yaml +84 -0
new file mode 100644
@@ -0,0 +1,84 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 172
3+title: "Nushell script client over ACP: mm from a shell script"
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-26T06:30:00.000Z
9+updatedAt: 2026-10-26T06:30:00.000Z
10+labels:
11+ - kind::feature
12+epic: SDK
13+related:
14+ - 167
15+ - 139
16+body: |
17+ ## Goal
18+ Use mm from a Nushell script with structured data (tables, records) instead of text: send a question, get the answer and the tool calls as Nushell values.
19+
20+ ## Shared ground
21+ Same idea as ticket 167 (Node.js), in another language: drive `mm -acp` over ACP (JSON-RPC, one message per line on stdin/stdout), with NO change to mm. Ticket 167 holds the ACP mapping (`initialize`, `session/new`, `session/prompt`, `session/update`, `session/cancel`, `session/request_permission`, `elicitation/create`) and the limits (the `mm` binary must be installed, local stdio only, config by `AGENT_CONFIG`). The same API as 167: start an agent from a config file, `complete` (not streamed), `stream`, cancel, a permission callback that refuses by default, close. Start once the Node.js prototype has settled the API.
22+
23+ ## Specific to Nushell — the hard part
24+ - ACP is a conversation on ONE long-lived process: `session/prompt` needs the `sessionId` that `session/new` returns (mm's ids are time-sortable and random, so it cannot be guessed). A Nushell pipeline writes stdin and reads stdout, but answering a message read from stdout on the same process's stdin is not something a plain pipeline does. To study first:
25+ - Nushell's background jobs / `job` commands and whether a pipe can be held open both ways;
26+ - a small helper (a Nushell plugin, or reuse of the Node/Python client of tickets 167/169 behind a command) — then Nushell only parses its JSON output;
27+ - for the simplest case, plain `mm -p` already gives one answer and is easy from Nushell — the ACP client only adds streaming, cancellation and permissions.
28+ - Permissions cannot be asked interactively in a pipeline: refuse by default, or a closure given by the script.
29+ - Streaming: each `session/update` becomes a record, so the script can `where kind == text` or `each` over them.
30+ - `nu` is not installed in this sandbox.
31+
32+ ## Done when
33+ - `demos/nushell-acp-client/` holds the client, one example each for not streamed, streamed, cancelled and a permission (agent with `yolo: false`), and README EN + FR with results measured on llmman. The README compares it with plain `mm -p` from Nushell, so the reader knows when ACP is worth it.
34+ - Nothing changed in mm's Go code.
35+tasks:
36+ - id: 1
37+ title: "Study: can Nushell hold a two-way pipe to one process? Pick the approach (pure nu, plugin, or a helper)"
38+ state: open
39+ priority: none
40+ author:
41+ name: k33g
42+ email: ph.charriere@gmail.com
43+ createdAt: 2026-10-26T06:30:00.000Z
44+ - id: 2
45+ title: "Get Nushell (sandbox or the user's machine)"
46+ state: open
47+ priority: none
48+ author:
49+ name: k33g
50+ email: ph.charriere@gmail.com
51+ createdAt: 2026-10-26T06:30:00.000Z
52+ - id: 3
53+ title: "Client: start (initialize + session/new), complete, stream, cancel, close"
54+ state: open
55+ priority: none
56+ author:
57+ name: k33g
58+ email: ph.charriere@gmail.com
59+ createdAt: 2026-10-26T06:30:00.000Z
60+ - id: 4
61+ title: "Permission callback (session/request_permission), refuse by default"
62+ state: open
63+ priority: none
64+ author:
65+ name: k33g
66+ email: ph.charriere@gmail.com
67+ createdAt: 2026-10-26T06:30:00.000Z
68+ - id: 5
69+ title: "Examples (not streamed, streamed, cancelled, permission) run on llmman"
70+ state: open
71+ priority: none
72+ author:
73+ name: k33g
74+ email: ph.charriere@gmail.com
75+ createdAt: 2026-10-26T06:30:00.000Z
76+ - id: 6
77+ title: "README EN + FR with measured results and limits"
78+ state: open
79+ priority: none
80+ author:
81+ name: k33g
82+ email: ph.charriere@gmail.com
83+ createdAt: 2026-10-26T06:30:00.000Z
84+comments: []
new file mode 100644
@@ -0,0 +1,84 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 172
3+title: "Nushell script client over ACP: mm from a shell script"
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-26T06:30:00.000Z
9+updatedAt: 2026-10-26T06:30:00.000Z
10+labels:
11+ - kind::feature
12+epic: SDK
13+related:
14+ - 167
15+ - 139
16+body: |
17+ ## Goal
18+ Use mm from a Nushell script with structured data (tables, records) instead of text: send a question, get the answer and the tool calls as Nushell values.
19+
20+ ## Shared ground
21+ Same idea as ticket 167 (Node.js), in another language: drive `mm -acp` over ACP (JSON-RPC, one message per line on stdin/stdout), with NO change to mm. Ticket 167 holds the ACP mapping (`initialize`, `session/new`, `session/prompt`, `session/update`, `session/cancel`, `session/request_permission`, `elicitation/create`) and the limits (the `mm` binary must be installed, local stdio only, config by `AGENT_CONFIG`). The same API as 167: start an agent from a config file, `complete` (not streamed), `stream`, cancel, a permission callback that refuses by default, close. Start once the Node.js prototype has settled the API.
22+
23+ ## Specific to Nushell — the hard part
24+ - ACP is a conversation on ONE long-lived process: `session/prompt` needs the `sessionId` that `session/new` returns (mm's ids are time-sortable and random, so it cannot be guessed). A Nushell pipeline writes stdin and reads stdout, but answering a message read from stdout on the same process's stdin is not something a plain pipeline does. To study first:
25+ - Nushell's background jobs / `job` commands and whether a pipe can be held open both ways;
26+ - a small helper (a Nushell plugin, or reuse of the Node/Python client of tickets 167/169 behind a command) — then Nushell only parses its JSON output;
27+ - for the simplest case, plain `mm -p` already gives one answer and is easy from Nushell — the ACP client only adds streaming, cancellation and permissions.
28+ - Permissions cannot be asked interactively in a pipeline: refuse by default, or a closure given by the script.
29+ - Streaming: each `session/update` becomes a record, so the script can `where kind == text` or `each` over them.
30+ - `nu` is not installed in this sandbox.
31+
32+ ## Done when
33+ - `demos/nushell-acp-client/` holds the client, one example each for not streamed, streamed, cancelled and a permission (agent with `yolo: false`), and README EN + FR with results measured on llmman. The README compares it with plain `mm -p` from Nushell, so the reader knows when ACP is worth it.
34+ - Nothing changed in mm's Go code.
35+tasks:
36+ - id: 1
37+ title: "Study: can Nushell hold a two-way pipe to one process? Pick the approach (pure nu, plugin, or a helper)"
38+ state: open
39+ priority: none
40+ author:
41+ name: k33g
42+ email: ph.charriere@gmail.com
43+ createdAt: 2026-10-26T06:30:00.000Z
44+ - id: 2
45+ title: "Get Nushell (sandbox or the user's machine)"
46+ state: open
47+ priority: none
48+ author:
49+ name: k33g
50+ email: ph.charriere@gmail.com
51+ createdAt: 2026-10-26T06:30:00.000Z
52+ - id: 3
53+ title: "Client: start (initialize + session/new), complete, stream, cancel, close"
54+ state: open
55+ priority: none
56+ author:
57+ name: k33g
58+ email: ph.charriere@gmail.com
59+ createdAt: 2026-10-26T06:30:00.000Z
60+ - id: 4
61+ title: "Permission callback (session/request_permission), refuse by default"
62+ state: open
63+ priority: none
64+ author:
65+ name: k33g
66+ email: ph.charriere@gmail.com
67+ createdAt: 2026-10-26T06:30:00.000Z
68+ - id: 5
69+ title: "Examples (not streamed, streamed, cancelled, permission) run on llmman"
70+ state: open
71+ priority: none
72+ author:
73+ name: k33g
74+ email: ph.charriere@gmail.com
75+ createdAt: 2026-10-26T06:30:00.000Z
76+ - id: 6
77+ title: "README EN + FR with measured results and limits"
78+ state: open
79+ priority: none
80+ author:
81+ name: k33g
82+ email: ph.charriere@gmail.com
83+ createdAt: 2026-10-26T06:30:00.000Z
84+comments: []
added .tickets/issues/0173-switch-the-license-from-mit-to-fsl-1-1-mit.yaml +92 -0
Large diff collapsed to keep the page fast — load it when you need it.
added .tickets/issues/0174-testing-model-check-test-a-model-as-a-working-agent.yaml +86 -0
Large diff collapsed to keep the page fast — load it when you need it.
added .tickets/issues/0175-testing-function-calling-test-a-model-s-tool-calls.yaml +88 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified README.md +2 -0
@@ -141,6 +141,8 @@ The `demos/` directory holds ready-made set-ups (most with a README explaining h
141141 | `demos/mini-mes/` | small teams of agents (`riker` coordinating a specifier and a coder, `gopher` a Go specialist) |
142142 | `demos/little-coder/` | a Go + htmx web-app generator for a small local model (Mellum2 12B on llmman, 32 GB RAM): a tested starter, skills, `AGENTS.md`, measured results |
143143 | `demos/team/` | a team of four agents (lead, specifier, coder, tester) on one small model (Ornith 1.5 9B on llmman) building Go + htmx apps through spec and test files, with measured results |
144+| `demo.acp.sdk/` | mini-me as a library from other languages, by driving `mm -acp` over ACP: `nodejs/minime.js` (ticket 167) — `Agent.start`, `complete`, `stream`, cancel with an `AbortSignal`, a permission callback; no dependency, 11 tests with a fake mm, four examples measured on llmman |
145+| `testing/` | model testers run by mm itself: a coordinator (Gemma 4 12B) follows a skill, gives small tasks to a `candidate` agent whose model is under test (Qwen3.5 4B for model-check, Luciole 1B for function-calling), checks each result with a command and writes a Markdown report — `model-check/` (tool calls, exact instructions, Go code that must run, several steps) and `function-calling/` (only tools declared in the candidate's `tools:`) |
144146 | `dev.team/` | a team of five agents for a 32 GB laptop (ticket 152): a Qwen3.5 4B coordinator hands each request to a reformulator, a coder, a reviewer or a tutor (Gemma 4 12B, Mellum2 12B); hooks keep one model in memory at a time; measured: bug fixes, lessons and reviews work, new features not yet |
145147 | `demos/blog-team/` | the smallest team: a lead, a coder and a reviewer in 75 lines of YAML, one model (Mellum2 12B Q8_0 on llmman), written for a blog post |
146148 | `demos/translator/` | a French ↔ English translator (Gemma 4 E4B on llmman): `AGENTS.md` for the style, skills for technical texts, e-mails and idioms, `$styles` for professional / informal / Slack versions, `translate.sh` for files |
@@ -141,6 +141,8 @@ The `demos/` directory holds ready-made set-ups (most with a README explaining h
141 | `demos/mini-mes/` | small teams of agents (`riker` coordinating a specifier and a coder, `gopher` a Go specialist) |141 | `demos/mini-mes/` | small teams of agents (`riker` coordinating a specifier and a coder, `gopher` a Go specialist) |
142 | `demos/little-coder/` | a Go + htmx web-app generator for a small local model (Mellum2 12B on llmman, 32 GB RAM): a tested starter, skills, `AGENTS.md`, measured results |142 | `demos/little-coder/` | a Go + htmx web-app generator for a small local model (Mellum2 12B on llmman, 32 GB RAM): a tested starter, skills, `AGENTS.md`, measured results |
143 | `demos/team/` | a team of four agents (lead, specifier, coder, tester) on one small model (Ornith 1.5 9B on llmman) building Go + htmx apps through spec and test files, with measured results |143 | `demos/team/` | a team of four agents (lead, specifier, coder, tester) on one small model (Ornith 1.5 9B on llmman) building Go + htmx apps through spec and test files, with measured results |
144+| `demo.acp.sdk/` | mini-me as a library from other languages, by driving `mm -acp` over ACP: `nodejs/minime.js` (ticket 167) — `Agent.start`, `complete`, `stream`, cancel with an `AbortSignal`, a permission callback; no dependency, 11 tests with a fake mm, four examples measured on llmman |
145+| `testing/` | model testers run by mm itself: a coordinator (Gemma 4 12B) follows a skill, gives small tasks to a `candidate` agent whose model is under test (Qwen3.5 4B for model-check, Luciole 1B for function-calling), checks each result with a command and writes a Markdown report — `model-check/` (tool calls, exact instructions, Go code that must run, several steps) and `function-calling/` (only tools declared in the candidate's `tools:`) |
144 | `dev.team/` | a team of five agents for a 32 GB laptop (ticket 152): a Qwen3.5 4B coordinator hands each request to a reformulator, a coder, a reviewer or a tutor (Gemma 4 12B, Mellum2 12B); hooks keep one model in memory at a time; measured: bug fixes, lessons and reviews work, new features not yet |146 | `dev.team/` | a team of five agents for a 32 GB laptop (ticket 152): a Qwen3.5 4B coordinator hands each request to a reformulator, a coder, a reviewer or a tutor (Gemma 4 12B, Mellum2 12B); hooks keep one model in memory at a time; measured: bug fixes, lessons and reviews work, new features not yet |
145 | `demos/blog-team/` | the smallest team: a lead, a coder and a reviewer in 75 lines of YAML, one model (Mellum2 12B Q8_0 on llmman), written for a blog post |147 | `demos/blog-team/` | the smallest team: a lead, a coder and a reviewer in 75 lines of YAML, one model (Mellum2 12B Q8_0 on llmman), written for a blog post |
146 | `demos/translator/` | a French ↔ English translator (Gemma 4 E4B on llmman): `AGENTS.md` for the style, skills for technical texts, e-mails and idioms, `$styles` for professional / informal / Slack versions, `translate.sh` for files |148 | `demos/translator/` | a French ↔ English translator (Gemma 4 E4B on llmman): `AGENTS.md` for the style, skills for technical texts, e-mails and idioms, `$styles` for professional / informal / Slack versions, `translate.sh` for files |
added demo.acp.sdk/README.en.md +23 -0
new file mode 100644
@@ -0,0 +1,23 @@
1+# Using mini-me as a library, over ACP
2+
3+*[Version française](README.fr.md)*
4+
5+Programs in other languages use mini-me as a library by driving `mm -acp`: the same JSON-RPC protocol an editor such as Zed speaks, on the child process's stdin and stdout. Nothing changes in mm; every agent file works, with its tools, hooks, MCP servers and other agents.
6+
7+| Folder | Language | Status |
8+|---|---|---|
9+| [`nodejs/`](nodejs/README.en.md) | Node.js (ticket 167) | done: `minime.js`, four examples, tests |
10+| `go/`, `python/`, `rust/`, `swift/`, `nushell/` | tickets 168–172 | not started |
11+
12+What every client does:
13+
14+| Wanted | ACP message |
15+|---|---|
16+| start | `initialize`, then `session/new {cwd}` |
17+| run a completion | `session/prompt` |
18+| stream | the `session/update` notifications: `agent_message_chunk`, `agent_thought_chunk`, `tool_call`, `tool_call_update` |
19+| not streamed | join the text chunks until `session/prompt` answers with its `stopReason` |
20+| cancel | the `session/cancel` notification; the prompt then answers `stopReason: "cancelled"` |
21+| confirm a tool (`yolo: false`) | answer mm's `session/request_permission` request |
22+
23+Limits shared by all: the `mm` binary must be installed, it runs locally (stdio), and the agent is a file (`mm -acp -config <file>`). For a Go program without the binary, see ticket 139 (an in-process SDK).
new file mode 100644
@@ -0,0 +1,23 @@
1+# Using mini-me as a library, over ACP
2+
3+*[Version française](README.fr.md)*
4+
5+Programs in other languages use mini-me as a library by driving `mm -acp`: the same JSON-RPC protocol an editor such as Zed speaks, on the child process's stdin and stdout. Nothing changes in mm; every agent file works, with its tools, hooks, MCP servers and other agents.
6+
7+| Folder | Language | Status |
8+|---|---|---|
9+| [`nodejs/`](nodejs/README.en.md) | Node.js (ticket 167) | done: `minime.js`, four examples, tests |
10+| `go/`, `python/`, `rust/`, `swift/`, `nushell/` | tickets 168–172 | not started |
11+
12+What every client does:
13+
14+| Wanted | ACP message |
15+|---|---|
16+| start | `initialize`, then `session/new {cwd}` |
17+| run a completion | `session/prompt` |
18+| stream | the `session/update` notifications: `agent_message_chunk`, `agent_thought_chunk`, `tool_call`, `tool_call_update` |
19+| not streamed | join the text chunks until `session/prompt` answers with its `stopReason` |
20+| cancel | the `session/cancel` notification; the prompt then answers `stopReason: "cancelled"` |
21+| confirm a tool (`yolo: false`) | answer mm's `session/request_permission` request |
22+
23+Limits shared by all: the `mm` binary must be installed, it runs locally (stdio), and the agent is a file (`mm -acp -config <file>`). For a Go program without the binary, see ticket 139 (an in-process SDK).
added demo.acp.sdk/README.fr.md +23 -0
new file mode 100644
@@ -0,0 +1,23 @@
1+# Utiliser mini-me comme bibliothèque, par ACP
2+
3+*[English version](README.en.md)*
4+
5+Des programmes écrits dans d'autres langages utilisent mini-me comme bibliothèque en pilotant `mm -acp` : le même protocole JSON-RPC que parle un éditeur comme Zed, sur l'entrée et la sortie standard du processus enfant. Rien ne change dans mm ; tout fichier d'agent fonctionne, avec ses outils, ses hooks, ses serveurs MCP et ses autres agents.
6+
7+| Dossier | Langage | État |
8+|---|---|---|
9+| [`nodejs/`](nodejs/README.fr.md) | Node.js (ticket 167) | fait : `minime.js`, quatre exemples, des tests |
10+| `go/`, `python/`, `rust/`, `swift/`, `nushell/` | tickets 168–172 | pas commencés |
11+
12+Ce que fait chaque client :
13+
14+| Besoin | Message ACP |
15+|---|---|
16+| démarrer | `initialize`, puis `session/new {cwd}` |
17+| lancer une complétion | `session/prompt` |
18+| stream | les notifications `session/update` : `agent_message_chunk`, `agent_thought_chunk`, `tool_call`, `tool_call_update` |
19+| sans stream | concaténer les morceaux de texte jusqu'à la réponse de `session/prompt` et son `stopReason` |
20+| annuler | la notification `session/cancel` ; le prompt répond alors `stopReason: "cancelled"` |
21+| confirmer un outil (`yolo: false`) | répondre à la requête `session/request_permission` de mm |
22+
23+Limites communes : le binaire `mm` doit être installé, tout tourne en local (stdio), et l'agent est un fichier (`mm -acp -config <fichier>`). Pour un programme Go sans le binaire, voir le ticket 139 (un SDK en mémoire).
new file mode 100644
@@ -0,0 +1,23 @@
1+# Utiliser mini-me comme bibliothèque, par ACP
2+
3+*[English version](README.en.md)*
4+
5+Des programmes écrits dans d'autres langages utilisent mini-me comme bibliothèque en pilotant `mm -acp` : le même protocole JSON-RPC que parle un éditeur comme Zed, sur l'entrée et la sortie standard du processus enfant. Rien ne change dans mm ; tout fichier d'agent fonctionne, avec ses outils, ses hooks, ses serveurs MCP et ses autres agents.
6+
7+| Dossier | Langage | État |
8+|---|---|---|
9+| [`nodejs/`](nodejs/README.fr.md) | Node.js (ticket 167) | fait : `minime.js`, quatre exemples, des tests |
10+| `go/`, `python/`, `rust/`, `swift/`, `nushell/` | tickets 168–172 | pas commencés |
11+
12+Ce que fait chaque client :
13+
14+| Besoin | Message ACP |
15+|---|---|
16+| démarrer | `initialize`, puis `session/new {cwd}` |
17+| lancer une complétion | `session/prompt` |
18+| stream | les notifications `session/update` : `agent_message_chunk`, `agent_thought_chunk`, `tool_call`, `tool_call_update` |
19+| sans stream | concaténer les morceaux de texte jusqu'à la réponse de `session/prompt` et son `stopReason` |
20+| annuler | la notification `session/cancel` ; le prompt répond alors `stopReason: "cancelled"` |
21+| confirmer un outil (`yolo: false`) | répondre à la requête `session/request_permission` de mm |
22+
23+Limites communes : le binaire `mm` doit être installé, tout tourne en local (stdio), et l'agent est un fichier (`mm -acp -config <fichier>`). Pour un programme Go sans le binaire, voir le ticket 139 (un SDK en mémoire).
added demo.acp.sdk/nodejs/README.en.md +86 -0
Large diff collapsed to keep the page fast — load it when you need it.
added demo.acp.sdk/nodejs/README.fr.md +86 -0
Large diff collapsed to keep the page fast — load it when you need it.
added demo.acp.sdk/nodejs/agent.yaml +43 -0
Large diff collapsed to keep the page fast — load it when you need it.
added demo.acp.sdk/nodejs/examples/cancel.js +21 -0
Large diff collapsed to keep the page fast — load it when you need it.
added demo.acp.sdk/nodejs/examples/complete.js +10 -0
Large diff collapsed to keep the page fast — load it when you need it.
added demo.acp.sdk/nodejs/examples/permission.js +18 -0
Large diff collapsed to keep the page fast — load it when you need it.
added demo.acp.sdk/nodejs/examples/stream.js +40 -0
Large diff collapsed to keep the page fast — load it when you need it.
added demo.acp.sdk/nodejs/minime.js +307 -0
Large diff collapsed to keep the page fast — load it when you need it.
added demo.acp.sdk/nodejs/package.json +10 -0
Large diff collapsed to keep the page fast — load it when you need it.
added demo.acp.sdk/nodejs/test/fake-mm.js +89 -0
Large diff collapsed to keep the page fast — load it when you need it.
added demo.acp.sdk/nodejs/test/minime.test.js +110 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified demos/coding-helpers-unload-option/README.en.md +4 -0
@@ -12,6 +12,10 @@ The same team as [`demos/coding-helpers`](../coding-helpers/) — a coordinator
1212
1313 The two specialists are copies of those of `demos/coding-helpers`. Only `agent.yaml` differs: `unloadModels: true` on both entries, and no `hooks:` block.
1414
15+![How unloadModels works: mm unloads the coordinator's model before the specialist starts, then the specialist's model once it has answered, so the two models are never loaded together](coding-helpers-unload-option-flow.svg)
16+
17+Editable source: `coding-helpers-unload-option-flow.drawio` (draw.io); `coding-helpers-unload-option-flow.svg` is the same picture.
18+
1519 ## Run
1620
1721 ```bash
@@ -12,6 +12,10 @@ The same team as [`demos/coding-helpers`](../coding-helpers/) — a coordinator
12 12
13 The two specialists are copies of those of `demos/coding-helpers`. Only `agent.yaml` differs: `unloadModels: true` on both entries, and no `hooks:` block.13 The two specialists are copies of those of `demos/coding-helpers`. Only `agent.yaml` differs: `unloadModels: true` on both entries, and no `hooks:` block.
14 14
15+![How unloadModels works: mm unloads the coordinator's model before the specialist starts, then the specialist's model once it has answered, so the two models are never loaded together](coding-helpers-unload-option-flow.svg)
16+
17+Editable source: `coding-helpers-unload-option-flow.drawio` (draw.io); `coding-helpers-unload-option-flow.svg` is the same picture.
18+
15 ## Run19 ## Run
16 20
17 ```bash21 ```bash
modified demos/coding-helpers-unload-option/README.fr.md +4 -0
Large diff collapsed to keep the page fast — load it when you need it.
added demos/coding-helpers-unload-option/coding-helpers-unload-option-flow.drawio +31 -0
Large diff collapsed to keep the page fast — load it when you need it.
added demos/coding-helpers-unload-option/coding-helpers-unload-option-flow.png +0 -0
Large diff collapsed to keep the page fast — load it when you need it.
added demos/coding-helpers-unload-option/coding-helpers-unload-option-flow.svg +66 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/README.en.md +12 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/README.fr.md +12 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/common/bench-lib.sh +174 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/common/run.sh +28 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/function-calling/.gitignore +6 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/function-calling/README.en.md +88 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/function-calling/README.fr.md +88 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/function-calling/agent.candidate.yaml +98 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/function-calling/agent.yaml +95 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/function-calling/bench.sh +5 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/function-calling/reports/2026-10-26-0901-Luciole-1B-Instruct-1.1-GGUF-Q4_K_M.md +46 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/function-calling/skills/function-calling-check/SKILL.md +31 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/function-calling/skills/function-calling-check/bench.sh +38 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/function-calling/skills/function-calling-check/check.py +143 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/function-calling/skills/function-calling-check/tests.tsv +8 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/function-calling/tools/call.sh +50 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/.gitignore +6 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/README.en.md +92 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/README.fr.md +92 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/agent.candidate.yaml +52 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/agent.yaml +96 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/bench.sh +5 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/reports/.current +1 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/reports/2026-10-26-1242-Luciole-8B-Instruct-1.1-GGUF-Q4_K_M .md +44 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/skills/model-check/SKILL.md +32 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/skills/model-check/bench.sh +80 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/skills/model-check/fixtures/calc/calc.go +12 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/skills/model-check/fixtures/calc/calc_test.go +21 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/skills/model-check/fixtures/calc/go.mod +3 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/skills/model-check/fixtures/config.yaml +4 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/skills/model-check/fixtures/go.mod +5 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/skills/model-check/fixtures/numbers.txt +37 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/skills/model-check/fixtures/todo.txt +8 -0
Large diff collapsed to keep the page fast — load it when you need it.
added testing/model-check/skills/model-check/tests.tsv +8 -0
Large diff collapsed to keep the page fast — load it when you need it.