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

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

Download ZIP

🛟 Updated.Unverified

k33g committed 2026-10-07T06:33:29+02:00 Browse files
8941766 parent: 30a5de4
modified .tickets/epics.yaml +27 -0
@@ -18,3 +18,30 @@ epics:
1818 - title: Providers (LLM Engine)
1919 state: open
2020 color: "#0e8a16"
21+ - title: Documentation
22+ state: open
23+ color: "#bfd4f2"
24+ - title: Demos
25+ state: open
26+ color: "#fbca04"
27+ - title: Debug
28+ state: open
29+ color: "#b60205"
30+ - title: Models
31+ state: open
32+ color: "#5319e7"
33+ - title: Providers
34+ state: open
35+ color: "#d4c5f9"
36+ - title: ToDo
37+ state: open
38+ color: "#c2e0c6"
39+ - title: Questions
40+ state: open
41+ color: "#bfdadc"
42+ - title: SDK
43+ state: open
44+ color: "#d93f0b"
45+ - title: Loop
46+ state: open
47+ color: "#1d76db"
@@ -18,3 +18,30 @@ epics:
18 - title: Providers (LLM Engine)18 - title: Providers (LLM Engine)
19 state: open19 state: open
20 color: "#0e8a16"20 color: "#0e8a16"
21+ - title: Documentation
22+ state: open
23+ color: "#bfd4f2"
24+ - title: Demos
25+ state: open
26+ color: "#fbca04"
27+ - title: Debug
28+ state: open
29+ color: "#b60205"
30+ - title: Models
31+ state: open
32+ color: "#5319e7"
33+ - title: Providers
34+ state: open
35+ color: "#d4c5f9"
36+ - title: ToDo
37+ state: open
38+ color: "#c2e0c6"
39+ - title: Questions
40+ state: open
41+ color: "#bfdadc"
42+ - title: SDK
43+ state: open
44+ color: "#d93f0b"
45+ - title: Loop
46+ state: open
47+ color: "#1d76db"
modified .tickets/issues/0005-follow-token-consumption.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-15T23:04:05.027Z
9-updatedAt: 2026-09-15T23:04:05.027Z
9+updatedAt: 2026-10-06T13:00:56.375Z
1010 labels: []
11+epic: Improve TUI
1112 body: ""
1213 tasks: []
1314 comments: []
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-15T23:04:05.027Z8 createdAt: 2026-09-15T23:04:05.027Z
9-updatedAt: 2026-09-15T23:04:05.027Z9+updatedAt: 2026-10-06T13:00:56.375Z
10 labels: []10 labels: []
11+epic: Improve TUI
11 body: ""12 body: ""
12 tasks: []13 tasks: []
13 comments: []14 comments: []
modified .tickets/issues/0010-check-how-the-context-compression-is-working.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-16T04:09:48.463Z
9-updatedAt: 2026-09-16T06:00:00.000Z
9+updatedAt: 2026-10-06T13:03:01.126Z
1010 labels: []
11+epic: Documentation
1112 body: |
1213 ## Summary
1314
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-16T04:09:48.463Z8 createdAt: 2026-09-16T04:09:48.463Z
9-updatedAt: 2026-09-16T06:00:00.000Z9+updatedAt: 2026-10-06T13:03:01.126Z
10 labels: []10 labels: []
11+epic: Documentation
11 body: |12 body: |
12 ## Summary13 ## Summary
13 14
modified .tickets/issues/0014-check-all-the-shortcuts-in-the-tui.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-16T05:51:16.287Z
9-updatedAt: 2026-09-18T18:43:57.408Z
9+updatedAt: 2026-10-06T13:03:40.148Z
1010 labels: []
11+epic: Improve TUI
1112 body: ""
1213 tasks:
1314 - id: 1
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-16T05:51:16.287Z8 createdAt: 2026-09-16T05:51:16.287Z
9-updatedAt: 2026-09-18T18:43:57.408Z9+updatedAt: 2026-10-06T13:03:40.148Z
10 labels: []10 labels: []
11+epic: Improve TUI
11 body: ""12 body: ""
12 tasks:13 tasks:
13 - id: 114 - id: 1
modified .tickets/issues/0016-check-and-review-the-compress-mechanism.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-17T06:17:29.481Z
9-updatedAt: 2026-09-18T18:46:34.272Z
9+updatedAt: 2026-10-06T13:04:37.034Z
1010 labels: []
11+epic: Documentation
1112 related:
1213 - 10
1314 body: ""
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-17T06:17:29.481Z8 createdAt: 2026-09-17T06:17:29.481Z
9-updatedAt: 2026-09-18T18:46:34.272Z9+updatedAt: 2026-10-06T13:04:37.034Z
10 labels: []10 labels: []
11+epic: Documentation
11 related:12 related:
12 - 1013 - 10
13 body: ""14 body: ""
modified .tickets/issues/0019-try-to-auto-improve-the-source-code-of-mini-me-w.yaml +2 -1
@@ -6,11 +6,12 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-17T13:22:40.786Z
9-updatedAt: 2026-09-18T18:50:10.764Z
9+updatedAt: 2026-10-06T13:05:39.475Z
1010 labels:
1111 - priority::low
1212 - kind::chore
1313 - enhancement
14+epic: Debug
1415 body: |
1516 - Use the sessions' logs
1617 - Create a Claude Skill for this
@@ -6,11 +6,12 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-17T13:22:40.786Z8 createdAt: 2026-09-17T13:22:40.786Z
9-updatedAt: 2026-09-18T18:50:10.764Z9+updatedAt: 2026-10-06T13:05:39.475Z
10 labels:10 labels:
11 - priority::low11 - priority::low
12 - kind::chore12 - kind::chore
13 - enhancement13 - enhancement
14+epic: Debug
14 body: |15 body: |
15 - Use the sessions' logs16 - Use the sessions' logs
16 - Create a Claude Skill for this17 - Create a Claude Skill for this
modified .tickets/issues/0036-hooks.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-21T06:32:48.566Z
9-updatedAt: 2026-09-23T11:50:03.431Z
9+updatedAt: 2026-10-06T13:16:31.213Z
1010 labels: []
11+epic: Loop
1112 body: |
1213 ## Overview
1314 Design a hook system for mini-me to allow extensibility at key points in the agent lifecycle
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-21T06:32:48.566Z8 createdAt: 2026-09-21T06:32:48.566Z
9-updatedAt: 2026-09-23T11:50:03.431Z9+updatedAt: 2026-10-06T13:16:31.213Z
10 labels: []10 labels: []
11+epic: Loop
11 body: |12 body: |
12 ## Overview13 ## Overview
13 Design a hook system for mini-me to allow extensibility at key points in the agent lifecycle14 Design a hook system for mini-me to allow extensibility at key points in the agent lifecycle
modified .tickets/issues/0044-can-mini-me-use-the-multi-model-mode-of-llamacpp.yaml +2 -1
@@ -6,10 +6,11 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-25T04:44:02.972Z
9-updatedAt: 2026-09-25T04:44:12.561Z
9+updatedAt: 2026-10-06T13:06:04.590Z
1010 labels:
1111 - question
1212 - llama.cpp
13+epic: Models
1314 body: ""
1415 tasks: []
1516 comments: []
@@ -6,10 +6,11 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-25T04:44:02.972Z8 createdAt: 2026-09-25T04:44:02.972Z
9-updatedAt: 2026-09-25T04:44:12.561Z9+updatedAt: 2026-10-06T13:06:04.590Z
10 labels:10 labels:
11 - question11 - question
12 - llama.cpp12 - llama.cpp
13+epic: Models
13 body: ""14 body: ""
14 tasks: []15 tasks: []
15 comments: []16 comments: []
modified .tickets/issues/0045-sampling-parameters.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-25T07:14:21.206Z
9-updatedAt: 2026-09-25T07:14:51.120Z
9+updatedAt: 2026-10-06T13:06:21.857Z
1010 labels: []
11+epic: Documentation
1112 body: |
1213 Create a document to explain how to use the sampling parameters
1314 tasks: []
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-25T07:14:21.206Z8 createdAt: 2026-09-25T07:14:21.206Z
9-updatedAt: 2026-09-25T07:14:51.120Z9+updatedAt: 2026-10-06T13:06:21.857Z
10 labels: []10 labels: []
11+epic: Documentation
11 body: |12 body: |
12 Create a document to explain how to use the sampling parameters13 Create a document to explain how to use the sampling parameters
13 tasks: []14 tasks: []
modified .tickets/issues/0046-add-builtin-tools-as-plugins-with-wasm.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-27T02:30:34.975Z
9-updatedAt: 2026-09-27T03:45:08.358Z
9+updatedAt: 2026-10-06T13:09:56.640Z
1010 labels: []
11+epic: Builtin tools
1112 body: |
1213 example: safe / unsafe with wasm -> LlamaGuard
1314
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-27T02:30:34.975Z8 createdAt: 2026-09-27T02:30:34.975Z
9-updatedAt: 2026-09-27T03:45:08.358Z9+updatedAt: 2026-10-06T13:09:56.640Z
10 labels: []10 labels: []
11+epic: Builtin tools
11 body: |12 body: |
12 example: safe / unsafe with wasm -> LlamaGuard13 example: safe / unsafe with wasm -> LlamaGuard
13 14
modified .tickets/issues/0049-recreate-the-readme.yaml +2 -1
@@ -6,9 +6,10 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-28T18:44:44.821Z
9-updatedAt: 2026-09-29T06:27:22.776Z
9+updatedAt: 2026-10-06T13:08:12.646Z
1010 labels: []
1111 milestone: v0.3.0
12+epic: ToDo
1213 body: ""
1314 tasks: []
1415 comments: []
@@ -6,9 +6,10 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-28T18:44:44.821Z8 createdAt: 2026-09-28T18:44:44.821Z
9-updatedAt: 2026-09-29T06:27:22.776Z9+updatedAt: 2026-10-06T13:08:12.646Z
10 labels: []10 labels: []
11 milestone: v0.3.011 milestone: v0.3.0
12+epic: ToDo
12 body: ""13 body: ""
13 tasks: []14 tasks: []
14 comments: []15 comments: []
modified .tickets/issues/0051-query-other-models-from-the-prompt.yaml +3 -2
@@ -1,18 +1,19 @@
11 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
22 id: 51
33 title: Query other models from the prompt
4-state: open
4+state: closed
55 author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-29T04:49:19.839Z
9-updatedAt: 2026-09-29T06:24:02.144Z
9+updatedAt: 2026-10-06T13:08:32.615Z
1010 labels:
1111 - priority::high
1212 - kind::feature
1313 - enhancement
1414 - builtin tool
1515 milestone: v0.3.0
16+epic: Models
1617 body: |
1718 - Add a list of model (and provider) to the agent config file (with an alias / nickname)
1819 - Add a builtin tool "query_model"
@@ -1,18 +1,19 @@
1 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.1 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2 id: 512 id: 51
3 title: Query other models from the prompt3 title: Query other models from the prompt
4-state: open4+state: closed
5 author:5 author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-29T04:49:19.839Z8 createdAt: 2026-09-29T04:49:19.839Z
9-updatedAt: 2026-09-29T06:24:02.144Z9+updatedAt: 2026-10-06T13:08:32.615Z
10 labels:10 labels:
11 - priority::high11 - priority::high
12 - kind::feature12 - kind::feature
13 - enhancement13 - enhancement
14 - builtin tool14 - builtin tool
15 milestone: v0.3.015 milestone: v0.3.0
16+epic: Models
16 body: |17 body: |
17 - Add a list of model (and provider) to the agent config file (with an alias / nickname)18 - Add a list of model (and provider) to the agent config file (with an alias / nickname)
18 - Add a builtin tool "query_model"19 - Add a builtin tool "query_model"
renamed .tickets/issues/0053-tool-order-changes-on-every-question-breaks-the.yaml +2 -2
similarity index 98%
rename from .tickets/issues/0053-tool-order-changes-on-every-question.yaml
rename to .tickets/issues/0053-tool-order-changes-on-every-question-breaks-the.yaml
@@ -1,12 +1,12 @@
11 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
22 id: 53
33 title: Tool order changes on every question (breaks the KV prefix cache)
4-state: open
4+state: closed
55 author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-30T05:52:16.000Z
9-updatedAt: 2026-09-30T06:11:23.000Z
9+updatedAt: 2026-10-06T13:09:01.955Z
1010 labels:
1111 - kind::bug
1212 - priority::high
similarity index 98%
rename from .tickets/issues/0053-tool-order-changes-on-every-question.yaml
rename to .tickets/issues/0053-tool-order-changes-on-every-question-breaks-the.yaml
@@ -1,12 +1,12 @@
1 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.1 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2 id: 532 id: 53
3 title: Tool order changes on every question (breaks the KV prefix cache)3 title: Tool order changes on every question (breaks the KV prefix cache)
4-state: open4+state: closed
5 author:5 author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-30T05:52:16.000Z8 createdAt: 2026-09-30T05:52:16.000Z
9-updatedAt: 2026-09-30T06:11:23.000Z9+updatedAt: 2026-10-06T13:09:01.955Z
10 labels:10 labels:
11 - kind::bug11 - kind::bug
12 - priority::high12 - priority::high
modified .tickets/issues/0054-how-to-force-the-json-output.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-30T06:35:54.771Z
9-updatedAt: 2026-09-30T06:35:54.771Z
9+updatedAt: 2026-10-06T13:11:09.040Z
1010 labels: []
11+epic: Questions
1112 body: ""
1213 tasks: []
1314 comments: []
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-30T06:35:54.771Z8 createdAt: 2026-09-30T06:35:54.771Z
9-updatedAt: 2026-09-30T06:35:54.771Z9+updatedAt: 2026-10-06T13:11:09.040Z
10 labels: []10 labels: []
11+epic: Questions
11 body: ""12 body: ""
12 tasks: []13 tasks: []
13 comments: []14 comments: []
modified .tickets/issues/0055-how-to-query-another-model-and-force-the-json-ou.yaml +4 -2
@@ -6,12 +6,14 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-30T06:37:48.693Z
9-updatedAt: 2026-09-30T06:38:40.601Z
9+updatedAt: 2026-10-06T13:14:33.928Z
1010 labels: []
11+epic: Models
1112 related:
1213 - 54
1314 - 52
1415 - 51
15-body: ""
16+body: |
17+ Extranal yaml file with structured JSON
1618 tasks: []
1719 comments: []
@@ -6,12 +6,14 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-30T06:37:48.693Z8 createdAt: 2026-09-30T06:37:48.693Z
9-updatedAt: 2026-09-30T06:38:40.601Z9+updatedAt: 2026-10-06T13:14:33.928Z
10 labels: []10 labels: []
11+epic: Models
11 related:12 related:
12 - 5413 - 54
13 - 5214 - 52
14 - 5115 - 51
15-body: ""16+body: |
17+ Extranal yaml file with structured JSON
16 tasks: []18 tasks: []
17 comments: []19 comments: []
modified .tickets/issues/0056-blog-post-idea-how-to-query-a-decision-model-fro.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-30T06:50:30.091Z
9-updatedAt: 2026-09-30T06:50:30.091Z
9+updatedAt: 2026-10-06T13:12:26.692Z
1010 labels: []
11+epic: ToDo
1112 body: ""
1213 tasks: []
1314 comments: []
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-30T06:50:30.091Z8 createdAt: 2026-09-30T06:50:30.091Z
9-updatedAt: 2026-09-30T06:50:30.091Z9+updatedAt: 2026-10-06T13:12:26.692Z
10 labels: []10 labels: []
11+epic: ToDo
11 body: ""12 body: ""
12 tasks: []13 tasks: []
13 comments: []14 comments: []
renamed .tickets/issues/0057-watchdog-kills-the-turn-while-a-tool-runs-or-a-p.yaml +5 -4
similarity index 93%
rename from .tickets/issues/0057-watchdog-kills-the-turn-while-a-tool-runs.yaml
rename to .tickets/issues/0057-watchdog-kills-the-turn-while-a-tool-runs-or-a-p.yaml
@@ -1,15 +1,16 @@
11 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
22 id: 57
33 title: Watchdog kills the turn while a tool runs or a permission is pending
4-state: open
4+state: closed
55 author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-30T11:38:05.000Z
9-updatedAt: 2026-09-30T11:38:05.000Z
9+updatedAt: 2026-10-06T13:13:01.356Z
1010 labels:
1111 - kind::bug
1212 - priority::medium
13+epic: Models
1314 related:
1415 - 53
1516 body: |
@@ -63,7 +64,7 @@ tasks:
6364 createdAt: 2026-09-30T11:38:05.000Z
6465 updatedAt: 2026-09-30T11:38:05.000Z
6566 - id: 2
66- title: "toolTimeout config key (default, validation, YAML comments in agent.*.yaml and config.samples)"
67+ title: toolTimeout config key (default, validation, YAML comments in agent.*.yaml and config.samples)
6768 state: open
6869 priority: none
6970 author:
@@ -81,7 +82,7 @@ tasks:
8182 createdAt: 2026-09-30T11:38:05.000Z
8283 updatedAt: 2026-09-30T11:38:05.000Z
8384 - id: 4
84- title: "Exclude the permission wait (ACP and window sinks) from both budgets; decide on a cap"
85+ title: Exclude the permission wait (ACP and window sinks) from both budgets; decide on a cap
8586 state: open
8687 priority: none
8788 author:
similarity index 93%
rename from .tickets/issues/0057-watchdog-kills-the-turn-while-a-tool-runs.yaml
rename to .tickets/issues/0057-watchdog-kills-the-turn-while-a-tool-runs-or-a-p.yaml
@@ -1,15 +1,16 @@
1 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.1 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2 id: 572 id: 57
3 title: Watchdog kills the turn while a tool runs or a permission is pending3 title: Watchdog kills the turn while a tool runs or a permission is pending
4-state: open4+state: closed
5 author:5 author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-30T11:38:05.000Z8 createdAt: 2026-09-30T11:38:05.000Z
9-updatedAt: 2026-09-30T11:38:05.000Z9+updatedAt: 2026-10-06T13:13:01.356Z
10 labels:10 labels:
11 - kind::bug11 - kind::bug
12 - priority::medium12 - priority::medium
13+epic: Models
13 related:14 related:
14 - 5315 - 53
15 body: |16 body: |
@@ -63,7 +64,7 @@ tasks:
63 createdAt: 2026-09-30T11:38:05.000Z64 createdAt: 2026-09-30T11:38:05.000Z
64 updatedAt: 2026-09-30T11:38:05.000Z65 updatedAt: 2026-09-30T11:38:05.000Z
65 - id: 266 - id: 2
66- title: "toolTimeout config key (default, validation, YAML comments in agent.*.yaml and config.samples)"67+ title: toolTimeout config key (default, validation, YAML comments in agent.*.yaml and config.samples)
67 state: open68 state: open
68 priority: none69 priority: none
69 author:70 author:
@@ -81,7 +82,7 @@ tasks:
81 createdAt: 2026-09-30T11:38:05.000Z82 createdAt: 2026-09-30T11:38:05.000Z
82 updatedAt: 2026-09-30T11:38:05.000Z83 updatedAt: 2026-09-30T11:38:05.000Z
83 - id: 484 - id: 4
84- title: "Exclude the permission wait (ACP and window sinks) from both budgets; decide on a cap"85+ title: Exclude the permission wait (ACP and window sinks) from both budgets; decide on a cap
85 state: open86 state: open
86 priority: none87 priority: none
87 author:88 author:
modified .tickets/issues/0058-add-more-tools-to-the-sbx-template-redis-cli-to.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-01T04:39:22.452Z
9-updatedAt: 2026-10-01T04:39:22.452Z
9+updatedAt: 2026-10-06T13:13:18.155Z
1010 labels: []
11+epic: ToDo
1112 body: ""
1213 tasks: []
1314 comments: []
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-10-01T04:39:22.452Z8 createdAt: 2026-10-01T04:39:22.452Z
9-updatedAt: 2026-10-01T04:39:22.452Z9+updatedAt: 2026-10-06T13:13:18.155Z
10 labels: []10 labels: []
11+epic: ToDo
11 body: ""12 body: ""
12 tasks: []13 tasks: []
13 comments: []14 comments: []
modified .tickets/issues/0061-llmman-provider-download-the-model-automatically.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-01T05:48:44.919Z
9-updatedAt: 2026-10-01T05:48:44.919Z
9+updatedAt: 2026-10-06T13:07:28.156Z
1010 labels: []
11+epic: Providers (LLM Engine)
1112 body: ""
1213 tasks: []
1314 comments: []
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-10-01T05:48:44.919Z8 createdAt: 2026-10-01T05:48:44.919Z
9-updatedAt: 2026-10-01T05:48:44.919Z9+updatedAt: 2026-10-06T13:07:28.156Z
10 labels: []10 labels: []
11+epic: Providers (LLM Engine)
11 body: ""12 body: ""
12 tasks: []13 tasks: []
13 comments: []14 comments: []
modified .tickets/issues/0063-explain-how-the-hallucination-loops-hare-handled.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-01T06:38:27.789Z
9-updatedAt: 2026-10-01T06:38:27.789Z
9+updatedAt: 2026-10-06T13:02:37.363Z
1010 labels: []
11+epic: Documentation
1112 body: ""
1213 tasks: []
1314 comments: []
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-10-01T06:38:27.789Z8 createdAt: 2026-10-01T06:38:27.789Z
9-updatedAt: 2026-10-01T06:38:27.789Z9+updatedAt: 2026-10-06T13:02:37.363Z
10 labels: []10 labels: []
11+epic: Documentation
11 body: ""12 body: ""
12 tasks: []13 tasks: []
13 comments: []14 comments: []
modified .tickets/issues/0064-create-a-demo-with-context-7.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-01T06:39:02.823Z
9-updatedAt: 2026-10-01T06:39:02.823Z
9+updatedAt: 2026-10-06T13:03:26.126Z
1010 labels: []
11+epic: Demos
1112 body: ""
1213 tasks: []
1314 comments: []
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-10-01T06:39:02.823Z8 createdAt: 2026-10-01T06:39:02.823Z
9-updatedAt: 2026-10-01T06:39:02.823Z9+updatedAt: 2026-10-06T13:03:26.126Z
10 labels: []10 labels: []
11+epic: Demos
11 body: ""12 body: ""
12 tasks: []13 tasks: []
13 comments: []14 comments: []
modified .tickets/issues/0065-do-we-need-rag-features.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-01T06:39:46.034Z
9-updatedAt: 2026-10-01T06:39:46.034Z
9+updatedAt: 2026-10-06T13:13:31.383Z
1010 labels: []
11+epic: Questions
1112 body: ""
1213 tasks: []
1314 comments: []
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-10-01T06:39:46.034Z8 createdAt: 2026-10-01T06:39:46.034Z
9-updatedAt: 2026-10-01T06:39:46.034Z9+updatedAt: 2026-10-06T13:13:31.383Z
10 labels: []10 labels: []
11+epic: Questions
11 body: ""12 body: ""
12 tasks: []13 tasks: []
13 comments: []14 comments: []
modified .tickets/issues/0067-enable-disable-reasoning-mode.yaml +3 -2
@@ -1,14 +1,15 @@
11 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
22 id: 67
33 title: Enable / Disable reasoning mode
4-state: open
4+state: closed
55 author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-02T06:09:42.599Z
9-updatedAt: 2026-10-06T14:00:00.000Z
9+updatedAt: 2026-10-06T13:13:56.879Z
1010 labels:
1111 - kind::feature
12+epic: Models
1213 related:
1314 - 62
1415 - 76
@@ -1,14 +1,15 @@
1 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.1 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2 id: 672 id: 67
3 title: Enable / Disable reasoning mode3 title: Enable / Disable reasoning mode
4-state: open4+state: closed
5 author:5 author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-10-02T06:09:42.599Z8 createdAt: 2026-10-02T06:09:42.599Z
9-updatedAt: 2026-10-06T14:00:00.000Z9+updatedAt: 2026-10-06T13:13:56.879Z
10 labels:10 labels:
11 - kind::feature11 - kind::feature
12+epic: Models
12 related:13 related:
13 - 6214 - 62
14 - 7615 - 76
modified .tickets/issues/0068-recall-the-last-commands-last.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-02T07:01:13.955Z
9-updatedAt: 2026-10-02T07:01:13.955Z
9+updatedAt: 2026-10-06T13:14:55.214Z
1010 labels: []
11+epic: Improve TUI
1112 body: ""
1213 tasks: []
1314 comments: []
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-10-02T07:01:13.955Z8 createdAt: 2026-10-02T07:01:13.955Z
9-updatedAt: 2026-10-02T07:01:13.955Z9+updatedAt: 2026-10-06T13:14:55.214Z
10 labels: []10 labels: []
11+epic: Improve TUI
11 body: ""12 body: ""
12 tasks: []13 tasks: []
13 comments: []14 comments: []
modified .tickets/issues/0069-create-skills-to-search-some-specific-knowlege-o.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-02T09:26:19.729Z
9-updatedAt: 2026-10-02T09:27:01.494Z
9+updatedAt: 2026-10-06T13:11:52.354Z
1010 labels: []
11+epic: ToDo
1112 body: |
1213 For example Genkit skill with the appropriate links to the documentation (for fetching)
1314 tasks: []
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-10-02T09:26:19.729Z8 createdAt: 2026-10-02T09:26:19.729Z
9-updatedAt: 2026-10-02T09:27:01.494Z9+updatedAt: 2026-10-06T13:11:52.354Z
10 labels: []10 labels: []
11+epic: ToDo
11 body: |12 body: |
12 For example Genkit skill with the appropriate links to the documentation (for fetching)13 For example Genkit skill with the appropriate links to the documentation (for fetching)
13 tasks: []14 tasks: []
modified .tickets/issues/0070-add-github-gitlab-other-identity-to-the-mini-me.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-02T14:22:29.427Z
9-updatedAt: 2026-10-02T14:22:29.427Z
9+updatedAt: 2026-10-06T13:11:38.195Z
1010 labels: []
11+epic: Questions
1112 body: ""
1213 tasks: []
1314 comments: []
@@ -6,8 +6,9 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-10-02T14:22:29.427Z8 createdAt: 2026-10-02T14:22:29.427Z
9-updatedAt: 2026-10-02T14:22:29.427Z9+updatedAt: 2026-10-06T13:11:38.195Z
10 labels: []10 labels: []
11+epic: Questions
11 body: ""12 body: ""
12 tasks: []13 tasks: []
13 comments: []14 comments: []
modified .tickets/issues/0071-mini-me-as-a-sdk.yaml +2 -1
@@ -6,8 +6,9 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-02T05:32:33.878Z
9-updatedAt: 2026-10-02T21:15:00.000Z
9+updatedAt: 2026-10-06T13:15:18.350Z
1010 labels: []
11+epic: SDK
1112 body: ""
1213 tasks: []
1314 comments: []
@@ -6,8 +6,9 @@ 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-02T21:15:00.000Z9+updatedAt: 2026-10-06T13:15:18.350Z
10 labels: []10 labels: []
11+epic: SDK
11 body: ""12 body: ""
12 tasks: []13 tasks: []
13 comments: []14 comments: []
renamed .tickets/issues/0072-use-a-decision-model-decision-4b-as-a-local-deci.yaml +4 -3
similarity index 97%
rename from .tickets/issues/0072-use-a-decision-model-as-a-local-decider.yaml
rename to .tickets/issues/0072-use-a-decision-model-decision-4b-as-a-local-deci.yaml
@@ -6,9 +6,10 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-02T21:40:00.000Z
9-updatedAt: 2026-10-02T21:40:00.000Z
9+updatedAt: 2026-10-06T13:10:38.836Z
1010 labels:
1111 - kind::feature
12+epic: Models
1213 related:
1314 - 15
1415 - 59
@@ -186,7 +187,7 @@ tasks:
186187 createdAt: 2026-10-02T21:40:00.000Z
187188 updatedAt: 2026-10-02T21:40:00.000Z
188189 - id: 3
189- title: "Decide config shape (decisionModel block, per-use switches) with the user"
190+ title: Decide config shape (decisionModel block, per-use switches) with the user
190191 state: open
191192 priority: none
192193 author:
@@ -231,7 +232,7 @@ tasks:
231232 createdAt: 2026-10-02T21:40:00.000Z
232233 updatedAt: 2026-10-02T21:40:00.000Z
233234 - id: 8
234- title: "Docs EN+FR (how-to, reference, explanation) + package diagram"
235+ title: Docs EN+FR (how-to, reference, explanation) + package diagram
235236 state: open
236237 priority: none
237238 author:
similarity index 97%
rename from .tickets/issues/0072-use-a-decision-model-as-a-local-decider.yaml
rename to .tickets/issues/0072-use-a-decision-model-decision-4b-as-a-local-deci.yaml
@@ -6,9 +6,10 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-10-02T21:40:00.000Z8 createdAt: 2026-10-02T21:40:00.000Z
9-updatedAt: 2026-10-02T21:40:00.000Z9+updatedAt: 2026-10-06T13:10:38.836Z
10 labels:10 labels:
11 - kind::feature11 - kind::feature
12+epic: Models
12 related:13 related:
13 - 1514 - 15
14 - 5915 - 59
@@ -186,7 +187,7 @@ tasks:
186 createdAt: 2026-10-02T21:40:00.000Z187 createdAt: 2026-10-02T21:40:00.000Z
187 updatedAt: 2026-10-02T21:40:00.000Z188 updatedAt: 2026-10-02T21:40:00.000Z
188 - id: 3189 - id: 3
189- title: "Decide config shape (decisionModel block, per-use switches) with the user"190+ title: Decide config shape (decisionModel block, per-use switches) with the user
190 state: open191 state: open
191 priority: none192 priority: none
192 author:193 author:
@@ -231,7 +232,7 @@ tasks:
231 createdAt: 2026-10-02T21:40:00.000Z232 createdAt: 2026-10-02T21:40:00.000Z
232 updatedAt: 2026-10-02T21:40:00.000Z233 updatedAt: 2026-10-02T21:40:00.000Z
233 - id: 8234 - id: 8
234- title: "Docs EN+FR (how-to, reference, explanation) + package diagram"235+ title: Docs EN+FR (how-to, reference, explanation) + package diagram
235 state: open236 state: open
236 priority: none237 priority: none
237 author:238 author:
renamed .tickets/issues/0077-ebook-a-chapter-on-mcp.yaml +6 -5
similarity index 90%
rename from .tickets/issues/0077-ebook-chapter-on-mcp.yaml
rename to .tickets/issues/0077-ebook-a-chapter-on-mcp.yaml
@@ -6,10 +6,11 @@ author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-06T18:00:00.000Z
9-updatedAt: 2026-10-06T18:00:00.000Z
9+updatedAt: 2026-10-06T13:02:08.728Z
1010 labels:
1111 - documentation
1212 - priority::low
13+epic: Documentation
1314 body: |
1415 The ebook (« Créer un agent de code pas à pas », `ebook/`, French
1516 AsciiDoc, built with the ebook-builder skill) never covers the MCP client,
@@ -75,7 +76,7 @@ body: |
7576 7. What is not there (stdio) and why.
7677 tasks:
7778 - id: 1
78- title: "Verify the facts against the code at writing time (stdio status, ACP mcpServers, permissions/yolo, gateway)"
79+ title: Verify the facts against the code at writing time (stdio status, ACP mcpServers, permissions/yolo, gateway)
7980 state: open
8081 priority: none
8182 author:
@@ -84,7 +85,7 @@ tasks:
8485 createdAt: 2026-10-06T18:00:00.000Z
8586 updatedAt: 2026-10-06T18:00:00.000Z
8687 - id: 2
87- title: "Write ebook/chapters/14-mcp.adoc (FR, one physical line per paragraph, Latin-1 in SVG text) and include it in book.adoc"
88+ title: Write ebook/chapters/14-mcp.adoc (FR, one physical line per paragraph, Latin-1 in SVG text) and include it in book.adoc
8889 state: open
8990 priority: none
9091 author:
@@ -102,7 +103,7 @@ tasks:
102103 createdAt: 2026-10-06T18:00:00.000Z
103104 updatedAt: 2026-10-06T18:00:00.000Z
104105 - id: 4
105- title: "Update the conclusion (drop 'MCP' from future work) and the introduction's chapter list if it has one"
106+ title: Update the conclusion (drop 'MCP' from future work) and the introduction's chapter list if it has one
106107 state: open
107108 priority: none
108109 author:
@@ -111,7 +112,7 @@ tasks:
111112 createdAt: 2026-10-06T18:00:00.000Z
112113 updatedAt: 2026-10-06T18:00:00.000Z
113114 - id: 5
114- title: "Fix the misleading 'stdio or HTTP' comments in the code (config.go, tool_wrapper.go) — or implement stdio first"
115+ title: Fix the misleading 'stdio or HTTP' comments in the code (config.go, tool_wrapper.go) — or implement stdio first
115116 state: open
116117 priority: none
117118 author:
similarity index 90%
rename from .tickets/issues/0077-ebook-chapter-on-mcp.yaml
rename to .tickets/issues/0077-ebook-a-chapter-on-mcp.yaml
@@ -6,10 +6,11 @@ author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-10-06T18:00:00.000Z8 createdAt: 2026-10-06T18:00:00.000Z
9-updatedAt: 2026-10-06T18:00:00.000Z9+updatedAt: 2026-10-06T13:02:08.728Z
10 labels:10 labels:
11 - documentation11 - documentation
12 - priority::low12 - priority::low
13+epic: Documentation
13 body: |14 body: |
14 The ebook (« Créer un agent de code pas à pas », `ebook/`, French15 The ebook (« Créer un agent de code pas à pas », `ebook/`, French
15 AsciiDoc, built with the ebook-builder skill) never covers the MCP client,16 AsciiDoc, built with the ebook-builder skill) never covers the MCP client,
@@ -75,7 +76,7 @@ body: |
75 7. What is not there (stdio) and why.76 7. What is not there (stdio) and why.
76 tasks:77 tasks:
77 - id: 178 - id: 1
78- title: "Verify the facts against the code at writing time (stdio status, ACP mcpServers, permissions/yolo, gateway)"79+ title: Verify the facts against the code at writing time (stdio status, ACP mcpServers, permissions/yolo, gateway)
79 state: open80 state: open
80 priority: none81 priority: none
81 author:82 author:
@@ -84,7 +85,7 @@ tasks:
84 createdAt: 2026-10-06T18:00:00.000Z85 createdAt: 2026-10-06T18:00:00.000Z
85 updatedAt: 2026-10-06T18:00:00.000Z86 updatedAt: 2026-10-06T18:00:00.000Z
86 - id: 287 - id: 2
87- title: "Write ebook/chapters/14-mcp.adoc (FR, one physical line per paragraph, Latin-1 in SVG text) and include it in book.adoc"88+ title: Write ebook/chapters/14-mcp.adoc (FR, one physical line per paragraph, Latin-1 in SVG text) and include it in book.adoc
88 state: open89 state: open
89 priority: none90 priority: none
90 author:91 author:
@@ -102,7 +103,7 @@ tasks:
102 createdAt: 2026-10-06T18:00:00.000Z103 createdAt: 2026-10-06T18:00:00.000Z
103 updatedAt: 2026-10-06T18:00:00.000Z104 updatedAt: 2026-10-06T18:00:00.000Z
104 - id: 4105 - id: 4
105- title: "Update the conclusion (drop 'MCP' from future work) and the introduction's chapter list if it has one"106+ title: Update the conclusion (drop 'MCP' from future work) and the introduction's chapter list if it has one
106 state: open107 state: open
107 priority: none108 priority: none
108 author:109 author:
@@ -111,7 +112,7 @@ tasks:
111 createdAt: 2026-10-06T18:00:00.000Z112 createdAt: 2026-10-06T18:00:00.000Z
112 updatedAt: 2026-10-06T18:00:00.000Z113 updatedAt: 2026-10-06T18:00:00.000Z
113 - id: 5114 - id: 5
114- title: "Fix the misleading 'stdio or HTTP' comments in the code (config.go, tool_wrapper.go) — or implement stdio first"115+ title: Fix the misleading 'stdio or HTTP' comments in the code (config.go, tool_wrapper.go) — or implement stdio first
115 state: open116 state: open
116 priority: none117 priority: none
117 author:118 author:
added .tickets/issues/0078-unload-a-model-from-the-memory-slash-command-and.yaml +13 -0
new file mode 100644
@@ -0,0 +1,13 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 78
3+title: Unload a model from the memory (slash command and CLI commad)
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-07T03:15:17.113Z
9+updatedAt: 2026-10-07T03:15:17.113Z
10+labels: []
11+body: ""
12+tasks: []
13+comments: []
new file mode 100644
@@ -0,0 +1,13 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 78
3+title: Unload a model from the memory (slash command and CLI commad)
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-07T03:15:17.113Z
9+updatedAt: 2026-10-07T03:15:17.113Z
10+labels: []
11+body: ""
12+tasks: []
13+comments: []
renamed demo-dmr/MCP-GITHUB-SBX.en.md +0 -0
similarity index 100%
rename from demo/MCP-GITHUB-SBX.en.md
rename to demo-dmr/MCP-GITHUB-SBX.en.md
similarity index 100%
rename from demo/MCP-GITHUB-SBX.en.md
rename to demo-dmr/MCP-GITHUB-SBX.en.md
renamed demo-dmr/MCP-GITHUB-SBX.md +0 -0
similarity index 100%
rename from demo/MCP-GITHUB-SBX.md
rename to demo-dmr/MCP-GITHUB-SBX.md
similarity index 100%
rename from demo/MCP-GITHUB-SBX.md
rename to demo-dmr/MCP-GITHUB-SBX.md
renamed demo-dmr/MCP-GITHUB.en.md +0 -0
similarity index 100%
rename from demo/MCP-GITHUB.en.md
rename to demo-dmr/MCP-GITHUB.en.md
similarity index 100%
rename from demo/MCP-GITHUB.en.md
rename to demo-dmr/MCP-GITHUB.en.md
renamed demo-dmr/MCP-GITHUB.md +0 -0
similarity index 100%
rename from demo/MCP-GITHUB.md
rename to demo-dmr/MCP-GITHUB.md
similarity index 100%
rename from demo/MCP-GITHUB.md
rename to demo-dmr/MCP-GITHUB.md
renamed demo-dmr/MCP_SBX_FIX.md +0 -0
similarity index 100%
rename from demo/MCP_SBX_FIX.md
rename to demo-dmr/MCP_SBX_FIX.md
similarity index 100%
rename from demo/MCP_SBX_FIX.md
rename to demo-dmr/MCP_SBX_FIX.md
renamed demo-dmr/MCP_SERVERS_GUIDE.md +0 -0
similarity index 100%
rename from demo/MCP_SERVERS_GUIDE.md
rename to demo-dmr/MCP_SERVERS_GUIDE.md
similarity index 100%
rename from demo/MCP_SERVERS_GUIDE.md
rename to demo-dmr/MCP_SERVERS_GUIDE.md
renamed demo-dmr/README.md +0 -0
similarity index 100%
rename from demo/README.md
rename to demo-dmr/README.md
similarity index 100%
rename from demo/README.md
rename to demo-dmr/README.md
renamed demo-dmr/agent.dmr.2.yaml +0 -0
similarity index 100%
rename from demo/agent.dmr.2.yaml
rename to demo-dmr/agent.dmr.2.yaml
similarity index 100%
rename from demo/agent.dmr.2.yaml
rename to demo-dmr/agent.dmr.2.yaml
renamed demo-dmr/agent.dmr.github-oauth.yaml +0 -0
similarity index 100%
rename from demo/agent.dmr.github-oauth.yaml
rename to demo-dmr/agent.dmr.github-oauth.yaml
similarity index 100%
rename from demo/agent.dmr.github-oauth.yaml
rename to demo-dmr/agent.dmr.github-oauth.yaml
renamed demo-dmr/agent.dmr.mcp.yaml +0 -0
similarity index 100%
rename from demo/agent.dmr.mcp.yaml
rename to demo-dmr/agent.dmr.mcp.yaml
similarity index 100%
rename from demo/agent.dmr.mcp.yaml
rename to demo-dmr/agent.dmr.mcp.yaml
renamed demo-dmr/agent.dmr.sbx.yaml +0 -0
similarity index 100%
rename from demo/agent.dmr.sbx.yaml
rename to demo-dmr/agent.dmr.sbx.yaml
similarity index 100%
rename from demo/agent.dmr.sbx.yaml
rename to demo-dmr/agent.dmr.sbx.yaml
renamed demo-dmr/agent.dmr.yaml +0 -0
similarity index 100%
rename from demo/agent.dmr.yaml
rename to demo-dmr/agent.dmr.yaml
similarity index 100%
rename from demo/agent.dmr.yaml
rename to demo-dmr/agent.dmr.yaml
renamed demo-dmr/agent.lsp.yaml +0 -0
similarity index 100%
rename from demo/agent.lsp.yaml
rename to demo-dmr/agent.lsp.yaml
similarity index 100%
rename from demo/agent.lsp.yaml
rename to demo-dmr/agent.lsp.yaml
renamed demo-dmr/config_explanation.md +0 -0
similarity index 100%
rename from demo/config_explanation.md
rename to demo-dmr/config_explanation.md
similarity index 100%
rename from demo/config_explanation.md
rename to demo-dmr/config_explanation.md
renamed demo-dmr/main.go +0 -0
similarity index 100%
rename from demo/main.go
rename to demo-dmr/main.go
similarity index 100%
rename from demo/main.go
rename to demo-dmr/main.go
renamed demo-dmr/newfile.txt +0 -0
similarity index 100%
rename from demo/newfile.txt
rename to demo-dmr/newfile.txt
similarity index 100%
rename from demo/newfile.txt
rename to demo-dmr/newfile.txt
renamed demo-dmr/prompt.md +0 -0
similarity index 100%
rename from demo/prompt.md
rename to demo-dmr/prompt.md
similarity index 100%
rename from demo/prompt.md
rename to demo-dmr/prompt.md
renamed demo-dmr/skills/README.md +0 -0
similarity index 100%
rename from demo/skills/README.md
rename to demo-dmr/skills/README.md
similarity index 100%
rename from demo/skills/README.md
rename to demo-dmr/skills/README.md
renamed demo-dmr/skills/bg-jobs/SKILL.md +0 -0
similarity index 100%
rename from demo/skills/bg-jobs/SKILL.md
rename to demo-dmr/skills/bg-jobs/SKILL.md
similarity index 100%
rename from demo/skills/bg-jobs/SKILL.md
rename to demo-dmr/skills/bg-jobs/SKILL.md
renamed demo-dmr/skills/greetings/SKILL.md +0 -0
similarity index 100%
rename from demo/skills/greetings/SKILL.md
rename to demo-dmr/skills/greetings/SKILL.md
similarity index 100%
rename from demo/skills/greetings/SKILL.md
rename to demo-dmr/skills/greetings/SKILL.md
renamed demo-dmr/skills/lsp-navigation/SKILL.md +0 -0
similarity index 100%
rename from demo/skills/lsp-navigation/SKILL.md
rename to demo-dmr/skills/lsp-navigation/SKILL.md
similarity index 100%
rename from demo/skills/lsp-navigation/SKILL.md
rename to demo-dmr/skills/lsp-navigation/SKILL.md
renamed demo-dmr/skills/vulcan-salute/SKILL.md +0 -0
similarity index 100%
rename from demo/skills/vulcan-salute/SKILL.md
rename to demo-dmr/skills/vulcan-salute/SKILL.md
similarity index 100%
rename from demo/skills/vulcan-salute/SKILL.md
rename to demo-dmr/skills/vulcan-salute/SKILL.md
renamed demo-dmr/skills/what-time-is-it/SKILL.md +0 -0
similarity index 100%
rename from demo/skills/what-time-is-it/SKILL.md
rename to demo-dmr/skills/what-time-is-it/SKILL.md
similarity index 100%
rename from demo/skills/what-time-is-it/SKILL.md
rename to demo-dmr/skills/what-time-is-it/SKILL.md
modified demo-llmman/agent.jan-nano.yaml +4 -0
@@ -98,6 +98,10 @@ displayCommands: true
9898 showThinking: true
9999
100100
101+acp:
102+ name: jan
103+ title: Jan (coding agent)
104+
101105 # The system prompt: what the agent is, and what it is allowed to do.
102106 # This is the knob to play with — it is the shortest path to changing behaviour.
103107 system: |
@@ -98,6 +98,10 @@ displayCommands: true
98 showThinking: true98 showThinking: true
99 99
100 100
101+acp:
102+ name: jan
103+ title: Jan (coding agent)
104+
101 # The system prompt: what the agent is, and what it is allowed to do.105 # The system prompt: what the agent is, and what it is allowed to do.
102 # This is the knob to play with — it is the shortest path to changing behaviour.106 # This is the knob to play with — it is the shortest path to changing behaviour.
103 system: |107 system: |
modified demo-llmman/agent.llmman.yaml +4 -0
@@ -30,6 +30,10 @@ mmConfigs:
3030 # skills) when it is only asked for an opinion.
3131 reviewer: agent.lucy-reviewer.yaml
3232
33+acp:
34+ name: bob
35+ title: Bob (coordinator)
36+
3337 # Only when the daemon was started with LLMMAN_API_KEYS (mandatory when it
3438 # listens beyond loopback); unset otherwise. The key never goes in this file.
3539 # apiKeyEnv: LLMMAN_API_KEY
@@ -30,6 +30,10 @@ mmConfigs:
30 # skills) when it is only asked for an opinion.30 # skills) when it is only asked for an opinion.
31 reviewer: agent.lucy-reviewer.yaml31 reviewer: agent.lucy-reviewer.yaml
32 32
33+acp:
34+ name: bob
35+ title: Bob (coordinator)
36+
33 # Only when the daemon was started with LLMMAN_API_KEYS (mandatory when it37 # Only when the daemon was started with LLMMAN_API_KEYS (mandatory when it
34 # listens beyond loopback); unset otherwise. The key never goes in this file.38 # listens beyond loopback); unset otherwise. The key never goes in this file.
35 # apiKeyEnv: LLMMAN_API_KEY39 # apiKeyEnv: LLMMAN_API_KEY
modified demo-llmman/agent.lucy-reviewer.yaml +3 -0
@@ -98,6 +98,9 @@ displayCommands: true
9898 # model thinks — this only says whether to show it.
9999 showThinking: true
100100
101+acp:
102+ name: lucy_reviewer
103+ title: Lucy (reviewer)
101104
102105 # The system prompt: what the agent is, and what it is allowed to do.
103106 # This is the knob to play with — it is the shortest path to changing behaviour.
@@ -98,6 +98,9 @@ displayCommands: true
98 # model thinks — this only says whether to show it.98 # model thinks — this only says whether to show it.
99 showThinking: true99 showThinking: true
100 100
101+acp:
102+ name: lucy_reviewer
103+ title: Lucy (reviewer)
101 104
102 # The system prompt: what the agent is, and what it is allowed to do.105 # The system prompt: what the agent is, and what it is allowed to do.
103 # This is the knob to play with — it is the shortest path to changing behaviour.106 # This is the knob to play with — it is the shortest path to changing behaviour.
modified demo-llmman/agent.lucy.yaml +3 -0
@@ -97,6 +97,9 @@ displayCommands: true
9797 # model thinks — this only says whether to show it.
9898 showThinking: true
9999
100+acp:
101+ name: lucy
102+ title: Lucy (coding agent)
100103
101104 # The system prompt: what the agent is, and what it is allowed to do.
102105 # This is the knob to play with — it is the shortest path to changing behaviour.
@@ -97,6 +97,9 @@ displayCommands: true
97 # model thinks — this only says whether to show it.97 # model thinks — this only says whether to show it.
98 showThinking: true98 showThinking: true
99 99
100+acp:
101+ name: lucy
102+ title: Lucy (coding agent)
100 103
101 # The system prompt: what the agent is, and what it is allowed to do.104 # The system prompt: what the agent is, and what it is allowed to do.
102 # This is the knob to play with — it is the shortest path to changing behaviour.105 # This is the knob to play with — it is the shortest path to changing behaviour.
modified docs/en/how-to/turn-reasoning-off.md +2 -2
@@ -56,8 +56,8 @@ A thinking model (Qwen3.5, Qwen3.x, gpt-oss…) reasons before it answers. On a
5656
5757 Use it with care:
5858 - Reported to work by a user with `llmman` and `llamacpp`; not measured in this project (no test, no timing) and not tried on `dmr`.
59- - The variable's name and its values belong to the model's template, not to `mm`, which forwards them unchecked. A template that does not read the variable, or a value it does not know, is ignored without any error: compare the length of the `💭` block with and without the setting to know whether it took effect.
60- - Qwen3.x templates read `enable_thinking` only: on/off, no levels.
59+ - The variable's name and its values belong to the model's template, not to `mm`, which forwards them unchecked. A template that does not read the variable ignores it without any error: compare the length of the `💭` block with and without the setting to know whether it took effect. A template that reads it may instead **reject a value it does not know**, and then every request fails: Qwen3.8's raises `Unexpected reasoning effort …`.
60+ - Templates differ even within a family. Qwen3.5's reads `enable_thinking` only (on/off). Qwen3.8's (`hf.co/unsloth/Qwen3.8-27B-GGUF`) reads both: `reasoning_effort` is `low`, `medium` or `xhigh` (its default; `high` means `xhigh`), and only when `enable_thinking` is not `false`. Read the template before choosing a value: llmman shows it with `curl -s localhost:17434/api/show -d '{"model":"<id>"}'`, in the `template` field.
6161 - On `ollama`, `reasoning_effort` goes at the top level of `sampling`, not under `chat_template_kwargs`; only `none` has been measured there.
6262 - Compaction summaries do not follow it — see below.
6363 - **Turn it off for one run.** Keep two configuration files, or start the server itself without reasoning (for llama-server, see its `--reasoning-budget` option).
@@ -56,8 +56,8 @@ A thinking model (Qwen3.5, Qwen3.x, gpt-oss…) reasons before it answers. On a
56 56
57 Use it with care:57 Use it with care:
58 - Reported to work by a user with `llmman` and `llamacpp`; not measured in this project (no test, no timing) and not tried on `dmr`.58 - Reported to work by a user with `llmman` and `llamacpp`; not measured in this project (no test, no timing) and not tried on `dmr`.
59- - The variable's name and its values belong to the model's template, not to `mm`, which forwards them unchecked. A template that does not read the variable, or a value it does not know, is ignored without any error: compare the length of the `💭` block with and without the setting to know whether it took effect.59+ - The variable's name and its values belong to the model's template, not to `mm`, which forwards them unchecked. A template that does not read the variable ignores it without any error: compare the length of the `💭` block with and without the setting to know whether it took effect. A template that reads it may instead **reject a value it does not know**, and then every request fails: Qwen3.8's raises `Unexpected reasoning effort …`.
60- - Qwen3.x templates read `enable_thinking` only: on/off, no levels.60+ - Templates differ even within a family. Qwen3.5's reads `enable_thinking` only (on/off). Qwen3.8's (`hf.co/unsloth/Qwen3.8-27B-GGUF`) reads both: `reasoning_effort` is `low`, `medium` or `xhigh` (its default; `high` means `xhigh`), and only when `enable_thinking` is not `false`. Read the template before choosing a value: llmman shows it with `curl -s localhost:17434/api/show -d '{"model":"<id>"}'`, in the `template` field.
61 - On `ollama`, `reasoning_effort` goes at the top level of `sampling`, not under `chat_template_kwargs`; only `none` has been measured there.61 - On `ollama`, `reasoning_effort` goes at the top level of `sampling`, not under `chat_template_kwargs`; only `none` has been measured there.
62 - Compaction summaries do not follow it — see below.62 - Compaction summaries do not follow it — see below.
63 - **Turn it off for one run.** Keep two configuration files, or start the server itself without reasoning (for llama-server, see its `--reasoning-budget` option).63 - **Turn it off for one run.** Keep two configuration files, or start the server itself without reasoning (for llama-server, see its `--reasoning-budget` option).
modified docs/en/reference/configuration.md +1 -1
@@ -59,7 +59,7 @@
5959 | Key | Type | Default | Description |
6060 |-----|------|---------|-------------|
6161 | `acp.name` | string | `bob` | `agentInfo.name` in the `initialize` response. Must not be empty. |
62-| `acp.title` | string | `Bob (bash-first agent)` | `agentInfo.title`, the name the editor may display. Empty: not sent. |
62+| `acp.title` | string | `Bob (bash-first agent)` | `agentInfo.title`, the name the editor may display. Empty: not sent. Also shown by the window mode (`-tui`) next to `mm`, in its header and above each answer — `‣ mm [Homer (coder)]` — unless it is empty or the built-in default. During an `/ask`, the window shows the ASKED agent instead: its `acp.title` (or its `mmConfigs` name) above its answer, and in the header with its model and `asked by <this agent>`, until it has answered. |
6363
6464 The version is not configurable: `agentInfo.version` is always the binary's, as printed by `mm --version`.
6565
@@ -59,7 +59,7 @@
59 | Key | Type | Default | Description |59 | Key | Type | Default | Description |
60 |-----|------|---------|-------------|60 |-----|------|---------|-------------|
61 | `acp.name` | string | `bob` | `agentInfo.name` in the `initialize` response. Must not be empty. |61 | `acp.name` | string | `bob` | `agentInfo.name` in the `initialize` response. Must not be empty. |
62-| `acp.title` | string | `Bob (bash-first agent)` | `agentInfo.title`, the name the editor may display. Empty: not sent. |62+| `acp.title` | string | `Bob (bash-first agent)` | `agentInfo.title`, the name the editor may display. Empty: not sent. Also shown by the window mode (`-tui`) next to `mm`, in its header and above each answer — `‣ mm [Homer (coder)]` — unless it is empty or the built-in default. During an `/ask`, the window shows the ASKED agent instead: its `acp.title` (or its `mmConfigs` name) above its answer, and in the header with its model and `asked by <this agent>`, until it has answered. |
63 63
64 The version is not configurable: `agentInfo.version` is always the binary's, as printed by `mm --version`.64 The version is not configurable: `agentInfo.version` is always the binary's, as printed by `mm --version`.
65 65
modified docs/fr/how-to/turn-reasoning-off.md +2 -2
@@ -56,8 +56,8 @@ Un modèle à raisonnement (Qwen3.5, Qwen3.x, gpt-oss…) réfléchit avant de r
5656
5757 Précautions d'usage :
5858 - Signalé comme fonctionnel par un utilisateur avec `llmman` et `llamacpp` ; non mesuré dans ce projet (ni test, ni chronométrage) et non essayé avec `dmr`.
59- - Le nom de la variable et ses valeurs appartiennent au template du modèle, pas à `mm`, qui les transmet sans les vérifier. Un template qui ne lit pas la variable, ou une valeur qu'il ne connaît pas, est ignoré sans la moindre erreur : comparez la longueur du bloc `💭` avec et sans le réglage pour savoir s'il a pris effet.
60- - Les templates Qwen3.x ne lisent que `enable_thinking` : marche/arrêt, pas de niveaux.
59+ - Le nom de la variable et ses valeurs appartiennent au template du modèle, pas à `mm`, qui les transmet sans les vérifier. Un template qui ne lit pas la variable l'ignore sans la moindre erreur : comparez la longueur du bloc `💭` avec et sans le réglage pour savoir s'il a pris effet. Un template qui la lit peut au contraire **refuser une valeur qu'il ne connaît pas**, et alors chaque requête échoue : celui de Qwen3.8 lève `Unexpected reasoning effort …`.
60+ - Les templates diffèrent même au sein d'une famille. Celui de Qwen3.5 ne lit que `enable_thinking` (marche/arrêt). Celui de Qwen3.8 (`hf.co/unsloth/Qwen3.8-27B-GGUF`) lit les deux : `reasoning_effort` vaut `low`, `medium` ou `xhigh` (sa valeur par défaut ; `high` signifie `xhigh`), et seulement quand `enable_thinking` n'est pas `false`. Lisez le template avant de choisir une valeur : llmman le montre avec `curl -s localhost:17434/api/show -d '{"model":"<id>"}'`, dans le champ `template`.
6161 - Avec `ollama`, `reasoning_effort` se place au premier niveau de `sampling`, pas sous `chat_template_kwargs` ; seule la valeur `none` y a été mesurée.
6262 - Les résumés de compaction ne le suivent pas — voir ci-dessous.
6363 - **Le couper pour une seule exécution.** Gardez deux fichiers de configuration, ou démarrez le serveur lui-même sans raisonnement (pour llama-server, voir son option `--reasoning-budget`).
@@ -56,8 +56,8 @@ Un modèle à raisonnement (Qwen3.5, Qwen3.x, gpt-oss…) réfléchit avant de r
56 56
57 Précautions d'usage :57 Précautions d'usage :
58 - Signalé comme fonctionnel par un utilisateur avec `llmman` et `llamacpp` ; non mesuré dans ce projet (ni test, ni chronométrage) et non essayé avec `dmr`.58 - Signalé comme fonctionnel par un utilisateur avec `llmman` et `llamacpp` ; non mesuré dans ce projet (ni test, ni chronométrage) et non essayé avec `dmr`.
59- - Le nom de la variable et ses valeurs appartiennent au template du modèle, pas à `mm`, qui les transmet sans les vérifier. Un template qui ne lit pas la variable, ou une valeur qu'il ne connaît pas, est ignoré sans la moindre erreur : comparez la longueur du bloc `💭` avec et sans le réglage pour savoir s'il a pris effet.59+ - Le nom de la variable et ses valeurs appartiennent au template du modèle, pas à `mm`, qui les transmet sans les vérifier. Un template qui ne lit pas la variable l'ignore sans la moindre erreur : comparez la longueur du bloc `💭` avec et sans le réglage pour savoir s'il a pris effet. Un template qui la lit peut au contraire **refuser une valeur qu'il ne connaît pas**, et alors chaque requête échoue : celui de Qwen3.8 lève `Unexpected reasoning effort …`.
60- - Les templates Qwen3.x ne lisent que `enable_thinking` : marche/arrêt, pas de niveaux.60+ - Les templates diffèrent même au sein d'une famille. Celui de Qwen3.5 ne lit que `enable_thinking` (marche/arrêt). Celui de Qwen3.8 (`hf.co/unsloth/Qwen3.8-27B-GGUF`) lit les deux : `reasoning_effort` vaut `low`, `medium` ou `xhigh` (sa valeur par défaut ; `high` signifie `xhigh`), et seulement quand `enable_thinking` n'est pas `false`. Lisez le template avant de choisir une valeur : llmman le montre avec `curl -s localhost:17434/api/show -d '{"model":"<id>"}'`, dans le champ `template`.
61 - Avec `ollama`, `reasoning_effort` se place au premier niveau de `sampling`, pas sous `chat_template_kwargs` ; seule la valeur `none` y a été mesurée.61 - Avec `ollama`, `reasoning_effort` se place au premier niveau de `sampling`, pas sous `chat_template_kwargs` ; seule la valeur `none` y a été mesurée.
62 - Les résumés de compaction ne le suivent pas — voir ci-dessous.62 - Les résumés de compaction ne le suivent pas — voir ci-dessous.
63 - **Le couper pour une seule exécution.** Gardez deux fichiers de configuration, ou démarrez le serveur lui-même sans raisonnement (pour llama-server, voir son option `--reasoning-budget`).63 - **Le couper pour une seule exécution.** Gardez deux fichiers de configuration, ou démarrez le serveur lui-même sans raisonnement (pour llama-server, voir son option `--reasoning-budget`).
modified docs/fr/reference/configuration.md +1 -1
@@ -59,7 +59,7 @@
5959 | Clé | Type | Défaut | Description |
6060 |-----|------|--------|-------------|
6161 | `acp.name` | chaîne | `bob` | `agentInfo.name` dans la réponse à `initialize`. Ne doit pas être vide. |
62-| `acp.title` | chaîne | `Bob (bash-first agent)` | `agentInfo.title`, le nom que l'éditeur peut afficher. Vide : non envoyé. |
62+| `acp.title` | chaîne | `Bob (bash-first agent)` | `agentInfo.title`, le nom que l'éditeur peut afficher. Vide : non envoyé. Affiché aussi par le mode fenêtre (`-tui`) à côté de `mm`, dans son en-tête et au-dessus de chaque réponse — `‣ mm [Homer (coder)]` — sauf s'il est vide ou égal à la valeur intégrée. Pendant un `/ask`, la fenêtre montre à la place l'agent INTERROGÉ : son `acp.title` (ou son nom dans `mmConfigs`) au-dessus de sa réponse, et dans l'en-tête avec son modèle et `asked by <cet agent>`, jusqu'à ce qu'il ait répondu. |
6363
6464 La version n'est pas paramétrable : `agentInfo.version` est toujours celle du binaire, telle qu'affichée par `mm --version`.
6565
@@ -59,7 +59,7 @@
59 | Clé | Type | Défaut | Description |59 | Clé | Type | Défaut | Description |
60 |-----|------|--------|-------------|60 |-----|------|--------|-------------|
61 | `acp.name` | chaîne | `bob` | `agentInfo.name` dans la réponse à `initialize`. Ne doit pas être vide. |61 | `acp.name` | chaîne | `bob` | `agentInfo.name` dans la réponse à `initialize`. Ne doit pas être vide. |
62-| `acp.title` | chaîne | `Bob (bash-first agent)` | `agentInfo.title`, le nom que l'éditeur peut afficher. Vide : non envoyé. |62+| `acp.title` | chaîne | `Bob (bash-first agent)` | `agentInfo.title`, le nom que l'éditeur peut afficher. Vide : non envoyé. Affiché aussi par le mode fenêtre (`-tui`) à côté de `mm`, dans son en-tête et au-dessus de chaque réponse — `‣ mm [Homer (coder)]` — sauf s'il est vide ou égal à la valeur intégrée. Pendant un `/ask`, la fenêtre montre à la place l'agent INTERROGÉ : son `acp.title` (ou son nom dans `mmConfigs`) au-dessus de sa réponse, et dans l'en-tête avec son modèle et `asked by <cet agent>`, jusqu'à ce qu'il ait répondu. |
63 63
64 La version n'est pas paramétrable : `agentInfo.version` est toujours celle du binaire, telle qu'affichée par `mm --version`.64 La version n'est pas paramétrable : `agentInfo.version` est toujours celle du binaire, telle qu'affichée par `mm --version`.
65 65
modified internal/ask/exchange.go +26 -4
@@ -3,6 +3,7 @@ package ask
33 import (
44 "fmt"
55 "os"
6+ "strings"
67
78 "github.com/firebase/genkit/go/ai"
89 "gopkg.in/yaml.v3"
@@ -45,19 +46,40 @@ func clipMiddle(s string, max int) string {
4546 //
4647 // ask.Describe("demo-ollama/agent.ollama.yaml") // "ollama/qwen3.5:2b"
4748 func Describe(path string) string {
49+ id := Identify(path)
50+ if id.Model == "" {
51+ return "?"
52+ }
53+ return id.Provider + "/" + id.Model
54+}
55+
56+// Identity is what an agent's config file says about who answers: its
57+// acp.title, its provider and its model. Empty fields were not readable.
58+type Identity struct {
59+ Title, Provider, Model string
60+}
61+
62+// Identify reads an agent's Identity from its config file, best effort like
63+// Describe. A file without `provider` gets mm's default, "dmr".
64+//
65+// ask.Identify("demo-llmman/agent.jan-nano.yaml").Title // "Jan (coding agent)"
66+func Identify(path string) Identity {
4867 data, err := os.ReadFile(path)
4968 if err != nil {
50- return "?"
69+ return Identity{}
5170 }
5271 var head struct {
5372 Provider string `yaml:"provider"`
5473 Model string `yaml:"model"`
74+ ACP struct {
75+ Title string `yaml:"title"`
76+ } `yaml:"acp"`
5577 }
56- if yaml.Unmarshal(data, &head) != nil || head.Model == "" {
57- return "?"
78+ if yaml.Unmarshal(data, &head) != nil {
79+ return Identity{}
5880 }
5981 if head.Provider == "" {
6082 head.Provider = "dmr" // config.Cfg's default
6183 }
62- return head.Provider + "/" + head.Model
84+ return Identity{Title: strings.TrimSpace(head.ACP.Title), Provider: head.Provider, Model: head.Model}
6385 }
@@ -3,6 +3,7 @@ package ask
3 import (3 import (
4 "fmt"4 "fmt"
5 "os"5 "os"
6+ "strings"
6 7
7 "github.com/firebase/genkit/go/ai"8 "github.com/firebase/genkit/go/ai"
8 "gopkg.in/yaml.v3"9 "gopkg.in/yaml.v3"
@@ -45,19 +46,40 @@ func clipMiddle(s string, max int) string {
45 //46 //
46 // ask.Describe("demo-ollama/agent.ollama.yaml") // "ollama/qwen3.5:2b"47 // ask.Describe("demo-ollama/agent.ollama.yaml") // "ollama/qwen3.5:2b"
47 func Describe(path string) string {48 func Describe(path string) string {
49+ id := Identify(path)
50+ if id.Model == "" {
51+ return "?"
52+ }
53+ return id.Provider + "/" + id.Model
54+}
55+
56+// Identity is what an agent's config file says about who answers: its
57+// acp.title, its provider and its model. Empty fields were not readable.
58+type Identity struct {
59+ Title, Provider, Model string
60+}
61+
62+// Identify reads an agent's Identity from its config file, best effort like
63+// Describe. A file without `provider` gets mm's default, "dmr".
64+//
65+// ask.Identify("demo-llmman/agent.jan-nano.yaml").Title // "Jan (coding agent)"
66+func Identify(path string) Identity {
48 data, err := os.ReadFile(path)67 data, err := os.ReadFile(path)
49 if err != nil {68 if err != nil {
50- return "?"69+ return Identity{}
51 }70 }
52 var head struct {71 var head struct {
53 Provider string `yaml:"provider"`72 Provider string `yaml:"provider"`
54 Model string `yaml:"model"`73 Model string `yaml:"model"`
74+ ACP struct {
75+ Title string `yaml:"title"`
76+ } `yaml:"acp"`
55 }77 }
56- if yaml.Unmarshal(data, &head) != nil || head.Model == "" {78+ if yaml.Unmarshal(data, &head) != nil {
57- return "?"79+ return Identity{}
58 }80 }
59 if head.Provider == "" {81 if head.Provider == "" {
60 head.Provider = "dmr" // config.Cfg's default82 head.Provider = "dmr" // config.Cfg's default
61 }83 }
62- return head.Provider + "/" + head.Model84+ return Identity{Title: strings.TrimSpace(head.ACP.Title), Provider: head.Provider, Model: head.Model}
63 }85 }
modified internal/ask/exchange_test.go +18 -0
@@ -54,3 +54,21 @@ func TestDescribe(t *testing.T) {
5454 t.Errorf("Describe(missing) = %q", got)
5555 }
5656 }
57+
58+// Identify adds the acp.title to provider and model; an unreadable file
59+// gives an empty Identity.
60+func TestIdentify(t *testing.T) {
61+ dir := t.TempDir()
62+ p := filepath.Join(dir, "jan.yaml")
63+ body := "provider: llmman\nmodel: hf.co/Menlo/Jan-nano-gguf:Q4_K_M\nacp:\n name: jan\n title: \" Jan (coding agent) \"\n"
64+ if err := os.WriteFile(p, []byte(body), 0o644); err != nil {
65+ t.Fatal(err)
66+ }
67+ want := Identity{Title: "Jan (coding agent)", Provider: "llmman", Model: "hf.co/Menlo/Jan-nano-gguf:Q4_K_M"}
68+ if got := Identify(p); got != want {
69+ t.Errorf("Identify = %+v, want %+v", got, want)
70+ }
71+ if got := Identify(filepath.Join(dir, "missing.yaml")); got != (Identity{}) {
72+ t.Errorf("Identify(missing) = %+v, want empty", got)
73+ }
74+}
@@ -54,3 +54,21 @@ func TestDescribe(t *testing.T) {
54 t.Errorf("Describe(missing) = %q", got)54 t.Errorf("Describe(missing) = %q", got)
55 }55 }
56 }56 }
57+
58+// Identify adds the acp.title to provider and model; an unreadable file
59+// gives an empty Identity.
60+func TestIdentify(t *testing.T) {
61+ dir := t.TempDir()
62+ p := filepath.Join(dir, "jan.yaml")
63+ body := "provider: llmman\nmodel: hf.co/Menlo/Jan-nano-gguf:Q4_K_M\nacp:\n name: jan\n title: \" Jan (coding agent) \"\n"
64+ if err := os.WriteFile(p, []byte(body), 0o644); err != nil {
65+ t.Fatal(err)
66+ }
67+ want := Identity{Title: "Jan (coding agent)", Provider: "llmman", Model: "hf.co/Menlo/Jan-nano-gguf:Q4_K_M"}
68+ if got := Identify(p); got != want {
69+ t.Errorf("Identify = %+v, want %+v", got, want)
70+ }
71+ if got := Identify(filepath.Join(dir, "missing.yaml")); got != (Identity{}) {
72+ t.Errorf("Identify(missing) = %+v, want empty", got)
73+ }
74+}
modified internal/config/config.go +4 -1
@@ -426,6 +426,9 @@ type ContextConfig struct {
426426 // AGENT_CONFIG says otherwise.
427427 const DefaultPath = "agent.yaml"
428428
429+// DefaultACPTitle: acp.title when the file does not set one.
430+const DefaultACPTitle = "Bob (bash-first agent)"
431+
429432 // Cfg: the live settings, pre-filled with the built-in defaults.
430433 //
431434 // Defaults suited to a CODING AGENT — low temperature for precise and
@@ -484,7 +487,7 @@ which ones you left running.`,
484487 },
485488 ACP: ACPConfig{
486489 Name: "bob",
487- Title: "Bob (bash-first agent)",
490+ Title: DefaultACPTitle,
488491 },
489492 Yolo: true,
490493 Context: ContextConfig{
@@ -426,6 +426,9 @@ type ContextConfig struct {
426 // AGENT_CONFIG says otherwise.426 // AGENT_CONFIG says otherwise.
427 const DefaultPath = "agent.yaml"427 const DefaultPath = "agent.yaml"
428 428
429+// DefaultACPTitle: acp.title when the file does not set one.
430+const DefaultACPTitle = "Bob (bash-first agent)"
431+
429 // Cfg: the live settings, pre-filled with the built-in defaults.432 // Cfg: the live settings, pre-filled with the built-in defaults.
430 //433 //
431 // Defaults suited to a CODING AGENT — low temperature for precise and434 // Defaults suited to a CODING AGENT — low temperature for precise and
@@ -484,7 +487,7 @@ which ones you left running.`,
484 },487 },
485 ACP: ACPConfig{488 ACP: ACPConfig{
486 Name: "bob",489 Name: "bob",
487- Title: "Bob (bash-first agent)",490+ Title: DefaultACPTitle,
488 },491 },
489 Yolo: true,492 Yolo: true,
490 Context: ContextConfig{493 Context: ContextConfig{
modified internal/tui/ask.go +6 -0
@@ -11,6 +11,7 @@ import (
1111
1212 "mm/internal/ask"
1313 "mm/internal/command"
14+ "mm/internal/config"
1415 "mm/internal/store"
1516
1617 "github.com/firebase/genkit/go/ai"
@@ -20,6 +21,9 @@ import (
2021 func (r *runner) startAsk(p Prompt, req command.AskRequest) {
2122 r.t.AddUser(p.Display())
2223 r.t.Notice(ask.Label(req))
24+ who := askSpeaker(req.Agent, ask.Identify(config.Cfg.MMConfigs[req.Agent]))
25+ r.asking.Store(&who)
26+ r.t.SetSpeaker(who.label)
2327 ctx, cancel := context.WithCancel(context.Background())
2428 r.cancel = cancel
2529 r.cancelled.Store(false)
@@ -37,6 +41,8 @@ func (r *runner) startAsk(p Prompt, req command.AskRequest) {
3741 // when the other agent answered.
3842 func (r *runner) applyAsk(res outcome) {
3943 r.t.Close()
44+ r.t.SetSpeaker("")
45+ r.asking.Store(nil)
4046 switch {
4147 case res.err != nil && res.cancelled:
4248 r.t.Notice("🛑 Ask aborted — nothing kept.")
@@ -11,6 +11,7 @@ import (
11 11
12 "mm/internal/ask"12 "mm/internal/ask"
13 "mm/internal/command"13 "mm/internal/command"
14+ "mm/internal/config"
14 "mm/internal/store"15 "mm/internal/store"
15 16
16 "github.com/firebase/genkit/go/ai"17 "github.com/firebase/genkit/go/ai"
@@ -20,6 +21,9 @@ import (
20 func (r *runner) startAsk(p Prompt, req command.AskRequest) {21 func (r *runner) startAsk(p Prompt, req command.AskRequest) {
21 r.t.AddUser(p.Display())22 r.t.AddUser(p.Display())
22 r.t.Notice(ask.Label(req))23 r.t.Notice(ask.Label(req))
24+ who := askSpeaker(req.Agent, ask.Identify(config.Cfg.MMConfigs[req.Agent]))
25+ r.asking.Store(&who)
26+ r.t.SetSpeaker(who.label)
23 ctx, cancel := context.WithCancel(context.Background())27 ctx, cancel := context.WithCancel(context.Background())
24 r.cancel = cancel28 r.cancel = cancel
25 r.cancelled.Store(false)29 r.cancelled.Store(false)
@@ -37,6 +41,8 @@ func (r *runner) startAsk(p Prompt, req command.AskRequest) {
37 // when the other agent answered.41 // when the other agent answered.
38 func (r *runner) applyAsk(res outcome) {42 func (r *runner) applyAsk(res outcome) {
39 r.t.Close()43 r.t.Close()
44+ r.t.SetSpeaker("")
45+ r.asking.Store(nil)
40 switch {46 switch {
41 case res.err != nil && res.cancelled:47 case res.err != nil && res.cancelled:
42 r.t.Notice("🛑 Ask aborted — nothing kept.")48 r.t.Notice("🛑 Ask aborted — nothing kept.")
modified internal/tui/ask_test.go +62 -0
@@ -3,9 +3,12 @@ package tui
33 import (
44 "context"
55 "errors"
6+ "os"
7+ "path/filepath"
68 "strings"
79 "testing"
810
11+ "mm/internal/ask"
912 "mm/internal/command"
1013 "mm/internal/config"
1114 "mm/internal/ui"
@@ -19,6 +22,7 @@ type fakeAsker struct {
1922 answer string
2023 fail error
2124 block bool
25+ during func() // called while the other agent is answering
2226 }
2327
2428 func (a *fakeAsker) Run(ctx context.Context, req command.AskRequest, _ []*ai.Message, _ string, sink ui.Sink) ([]*ai.Message, error) {
@@ -31,6 +35,9 @@ func (a *fakeAsker) Run(ctx context.Context, req command.AskRequest, _ []*ai.Mes
3135 if a.fail != nil {
3236 return nil, a.fail
3337 }
38+ if a.during != nil {
39+ a.during()
40+ }
3441 sink.Text(a.answer)
3542 return []*ai.Message{ai.NewUserTextMessage("[asked " + req.Agent + ": " + req.Prompt + "]"), ai.NewModelTextMessage(a.answer)}, nil
3643 }
@@ -93,3 +100,58 @@ func TestWindowAskAbortFailureAndMisuse(t *testing.T) {
93100 t.Errorf("misuse: busy %v, notices:\n%s", r.isBusy(), notices(tr))
94101 }
95102 }
103+
104+// While bob answers, the header names him — his acp.title, his model — and
105+// his answer is labelled with him; afterwards both are this agent's again.
106+func TestWindowAskNamesTheAskedAgent(t *testing.T) {
107+ a := &fakeAsker{answer: "four"}
108+ r, tr := askRunner(t, a)
109+ path := filepath.Join(t.TempDir(), "agent.jan.yaml")
110+ if err := os.WriteFile(path, []byte("provider: llmman\nmodel: hf.co/Menlo/Jan-nano-gguf:Q4_K_M\nacp:\n title: Jan (coding agent)\n"), 0o644); err != nil {
111+ t.Fatal(err)
112+ }
113+ config.Cfg.MMConfigs["bob"] = path
114+ var during string
115+ a.during = func() { during = r.header() }
116+
117+ r.submit(promptOf("/ask-bob what is 2+2?"))
118+ waitIdle(t, r)
119+
120+ if want := "mm [Jan (coding agent)] · Jan-nano:Q4_K_M @ llmman · asked by mm"; !strings.HasPrefix(during, want) {
121+ t.Errorf("header during the ask = %q, want prefix %q", during, want)
122+ }
123+ if got := r.header(); !strings.HasPrefix(got, "mm · m @ p") {
124+ t.Errorf("header after the ask = %q", got)
125+ }
126+ var who []string
127+ for _, e := range tr.Entries() {
128+ if e.Kind == KindAgent {
129+ who = append(who, e.Who)
130+ }
131+ }
132+ if len(who) != 1 || who[0] != "mm [Jan (coding agent)]" {
133+ t.Errorf("answer labels = %q", who)
134+ }
135+ tr.Chunk("mine")
136+ if last := tr.Entries()[len(tr.Entries())-1]; last.Who != "" || last.Text != "mine" {
137+ t.Errorf("this agent's next answer = %+v", last)
138+ }
139+}
140+
141+// The label: the title in brackets; the built-in title and an empty one
142+// leave "mm". An asked agent without a title is named by its mmConfigs key.
143+func TestAgentLabel(t *testing.T) {
144+ for title, want := range map[string]string{
145+ "Homer (coder)": "mm [Homer (coder)]", " Milo ": "mm [Milo]", "": "mm", config.DefaultACPTitle: "mm",
146+ } {
147+ if got := AgentLabel(title); got != want {
148+ t.Errorf("AgentLabel(%q) = %q, want %q", title, got, want)
149+ }
150+ }
151+ if got := askSpeaker("jan", ask.Identity{Model: "x"}).label; got != "mm [jan]" {
152+ t.Errorf("askSpeaker without a title = %q", got)
153+ }
154+ if got := askSpeaker("jan", ask.Identity{Title: config.DefaultACPTitle}).label; got != "mm [jan]" {
155+ t.Errorf("askSpeaker with the built-in title = %q", got)
156+ }
157+}
@@ -3,9 +3,12 @@ package tui
3 import (3 import (
4 "context"4 "context"
5 "errors"5 "errors"
6+ "os"
7+ "path/filepath"
6 "strings"8 "strings"
7 "testing"9 "testing"
8 10
11+ "mm/internal/ask"
9 "mm/internal/command"12 "mm/internal/command"
10 "mm/internal/config"13 "mm/internal/config"
11 "mm/internal/ui"14 "mm/internal/ui"
@@ -19,6 +22,7 @@ type fakeAsker struct {
19 answer string22 answer string
20 fail error23 fail error
21 block bool24 block bool
25+ during func() // called while the other agent is answering
22 }26 }
23 27
24 func (a *fakeAsker) Run(ctx context.Context, req command.AskRequest, _ []*ai.Message, _ string, sink ui.Sink) ([]*ai.Message, error) {28 func (a *fakeAsker) Run(ctx context.Context, req command.AskRequest, _ []*ai.Message, _ string, sink ui.Sink) ([]*ai.Message, error) {
@@ -31,6 +35,9 @@ func (a *fakeAsker) Run(ctx context.Context, req command.AskRequest, _ []*ai.Mes
31 if a.fail != nil {35 if a.fail != nil {
32 return nil, a.fail36 return nil, a.fail
33 }37 }
38+ if a.during != nil {
39+ a.during()
40+ }
34 sink.Text(a.answer)41 sink.Text(a.answer)
35 return []*ai.Message{ai.NewUserTextMessage("[asked " + req.Agent + ": " + req.Prompt + "]"), ai.NewModelTextMessage(a.answer)}, nil42 return []*ai.Message{ai.NewUserTextMessage("[asked " + req.Agent + ": " + req.Prompt + "]"), ai.NewModelTextMessage(a.answer)}, nil
36 }43 }
@@ -93,3 +100,58 @@ func TestWindowAskAbortFailureAndMisuse(t *testing.T) {
93 t.Errorf("misuse: busy %v, notices:\n%s", r.isBusy(), notices(tr))100 t.Errorf("misuse: busy %v, notices:\n%s", r.isBusy(), notices(tr))
94 }101 }
95 }102 }
103+
104+// While bob answers, the header names him — his acp.title, his model — and
105+// his answer is labelled with him; afterwards both are this agent's again.
106+func TestWindowAskNamesTheAskedAgent(t *testing.T) {
107+ a := &fakeAsker{answer: "four"}
108+ r, tr := askRunner(t, a)
109+ path := filepath.Join(t.TempDir(), "agent.jan.yaml")
110+ if err := os.WriteFile(path, []byte("provider: llmman\nmodel: hf.co/Menlo/Jan-nano-gguf:Q4_K_M\nacp:\n title: Jan (coding agent)\n"), 0o644); err != nil {
111+ t.Fatal(err)
112+ }
113+ config.Cfg.MMConfigs["bob"] = path
114+ var during string
115+ a.during = func() { during = r.header() }
116+
117+ r.submit(promptOf("/ask-bob what is 2+2?"))
118+ waitIdle(t, r)
119+
120+ if want := "mm [Jan (coding agent)] · Jan-nano:Q4_K_M @ llmman · asked by mm"; !strings.HasPrefix(during, want) {
121+ t.Errorf("header during the ask = %q, want prefix %q", during, want)
122+ }
123+ if got := r.header(); !strings.HasPrefix(got, "mm · m @ p") {
124+ t.Errorf("header after the ask = %q", got)
125+ }
126+ var who []string
127+ for _, e := range tr.Entries() {
128+ if e.Kind == KindAgent {
129+ who = append(who, e.Who)
130+ }
131+ }
132+ if len(who) != 1 || who[0] != "mm [Jan (coding agent)]" {
133+ t.Errorf("answer labels = %q", who)
134+ }
135+ tr.Chunk("mine")
136+ if last := tr.Entries()[len(tr.Entries())-1]; last.Who != "" || last.Text != "mine" {
137+ t.Errorf("this agent's next answer = %+v", last)
138+ }
139+}
140+
141+// The label: the title in brackets; the built-in title and an empty one
142+// leave "mm". An asked agent without a title is named by its mmConfigs key.
143+func TestAgentLabel(t *testing.T) {
144+ for title, want := range map[string]string{
145+ "Homer (coder)": "mm [Homer (coder)]", " Milo ": "mm [Milo]", "": "mm", config.DefaultACPTitle: "mm",
146+ } {
147+ if got := AgentLabel(title); got != want {
148+ t.Errorf("AgentLabel(%q) = %q, want %q", title, got, want)
149+ }
150+ }
151+ if got := askSpeaker("jan", ask.Identity{Model: "x"}).label; got != "mm [jan]" {
152+ t.Errorf("askSpeaker without a title = %q", got)
153+ }
154+ if got := askSpeaker("jan", ask.Identity{Title: config.DefaultACPTitle}).label; got != "mm [jan]" {
155+ t.Errorf("askSpeaker with the built-in title = %q", got)
156+ }
157+}
modified internal/tui/render.go +5 -1
@@ -60,7 +60,11 @@ func linesOf(e Entry, agentName string, width, previewLines int) []Line {
6060 case KindUser:
6161 lines = append(label("you"), prose(e.Text, width, styleBody)...)
6262 case KindAgent:
63- lines = append(label(agentName), body(e.Text, width)...)
63+ who := agentName
64+ if e.Who != "" {
65+ who = e.Who
66+ }
67+ lines = append(label(who), body(e.Text, width)...)
6468 case KindTool:
6569 lines = toolLines(e, width, previewLines)
6670 case KindThinking:
@@ -60,7 +60,11 @@ func linesOf(e Entry, agentName string, width, previewLines int) []Line {
60 case KindUser:60 case KindUser:
61 lines = append(label("you"), prose(e.Text, width, styleBody)...)61 lines = append(label("you"), prose(e.Text, width, styleBody)...)
62 case KindAgent:62 case KindAgent:
63- lines = append(label(agentName), body(e.Text, width)...)63+ who := agentName
64+ if e.Who != "" {
65+ who = e.Who
66+ }
67+ lines = append(label(who), body(e.Text, width)...)
64 case KindTool:68 case KindTool:
65 lines = toolLines(e, width, previewLines)69 lines = toolLines(e, width, previewLines)
66 case KindThinking:70 case KindThinking:
added internal/tui/speaker.go +35 -0
new file mode 100644
@@ -0,0 +1,35 @@
1+package tui
2+
3+import (
4+ "strings"
5+
6+ "mm/internal/ask"
7+ "mm/internal/config"
8+)
9+
10+// AgentLabel is how the window names an agent, in its header and above each
11+// answer: "mm", plus the agent's acp.title — "mm [Homer (coder)]". The
12+// built-in title is left out, so a file without an `acp:` block keeps "mm".
13+func AgentLabel(title string) string {
14+ title = strings.TrimSpace(title)
15+ if title == "" || title == config.DefaultACPTitle {
16+ return "mm"
17+ }
18+ return "mm [" + title + "]"
19+}
20+
21+// speaker is who the header shows while another agent answers an /ask.
22+type speaker struct {
23+ label, model, provider string
24+}
25+
26+// askSpeaker names the agent `name` from its config file: its acp.title, or
27+// its mmConfigs name when the file gives none (or only the built-in one) —
28+// "mm [Jan (coding agent)]", "mm [jan]".
29+func askSpeaker(name string, id ask.Identity) speaker {
30+ title := id.Title
31+ if title == "" || title == config.DefaultACPTitle {
32+ title = name
33+ }
34+ return speaker{label: AgentLabel(title), model: id.Model, provider: id.Provider}
35+}
new file mode 100644
@@ -0,0 +1,35 @@
1+package tui
2+
3+import (
4+ "strings"
5+
6+ "mm/internal/ask"
7+ "mm/internal/config"
8+)
9+
10+// AgentLabel is how the window names an agent, in its header and above each
11+// answer: "mm", plus the agent's acp.title — "mm [Homer (coder)]". The
12+// built-in title is left out, so a file without an `acp:` block keeps "mm".
13+func AgentLabel(title string) string {
14+ title = strings.TrimSpace(title)
15+ if title == "" || title == config.DefaultACPTitle {
16+ return "mm"
17+ }
18+ return "mm [" + title + "]"
19+}
20+
21+// speaker is who the header shows while another agent answers an /ask.
22+type speaker struct {
23+ label, model, provider string
24+}
25+
26+// askSpeaker names the agent `name` from its config file: its acp.title, or
27+// its mmConfigs name when the file gives none (or only the built-in one) —
28+// "mm [Jan (coding agent)]", "mm [jan]".
29+func askSpeaker(name string, id ask.Identity) speaker {
30+ title := id.Title
31+ if title == "" || title == config.DefaultACPTitle {
32+ title = name
33+ }
34+ return speaker{label: AgentLabel(title), model: id.Model, provider: id.Provider}
35+}
modified internal/tui/transcript.go +17 -5
@@ -44,6 +44,9 @@ const (
4444 type Entry struct {
4545 Kind Kind
4646 Text string // the question, the answer, the notice; a tool's OUTPUT
47+ // Who labels an answer (KindAgent) given by another agent, through /ask:
48+ // "mm [Jan (coding agent)]". Empty = this window's own agent.
49+ Who string
4750 // Full is the question as the model read it when Text is its collapsed
4851 // form — a long paste shown as `[Pasted #1 · …]`. Empty when they agree.
4952 Full string
@@ -76,8 +79,9 @@ func (e Entry) Detail() string {
7679 type Transcript struct {
7780 mu sync.Mutex
7881 entries []Entry
79- open bool // the last entry is an agent run still receiving chunks
80- tools int // tool calls recorded, for the status bar
82+ open bool // the last entry is an agent run still receiving chunks
83+ speaker string // Who of the answers being streamed; "" = this agent
84+ tools int // tool calls recorded, for the status bar
8185 now func() time.Time
8286 }
8387
@@ -131,14 +135,22 @@ func (t *Transcript) Chunk(text string) {
131135 }
132136 t.mu.Lock()
133137 defer t.mu.Unlock()
134- if t.open && len(t.entries) > 0 && t.entries[len(t.entries)-1].Kind == KindAgent {
135- t.entries[len(t.entries)-1].Text += text
138+ if last := len(t.entries) - 1; t.open && last >= 0 && t.entries[last].Kind == KindAgent && t.entries[last].Who == t.speaker {
139+ t.entries[last].Text += text
136140 return
137141 }
138- t.entries = append(t.entries, Entry{Kind: KindAgent, Text: text})
142+ t.entries = append(t.entries, Entry{Kind: KindAgent, Text: text, Who: t.speaker})
139143 t.open = true
140144 }
141145
146+// SetSpeaker names who the next answers come from — another agent during an
147+// /ask — until it is set back to "" (this window's own agent).
148+func (t *Transcript) SetSpeaker(who string) {
149+ t.mu.Lock()
150+ t.speaker = who
151+ t.mu.Unlock()
152+}
153+
142154 // Thinking appends a chunk of reasoning, growing the open thought entry
143155 // rather than starting one per fragment — the same rule as Chunk, with its
144156 // own kind so the conversation can tell an aside from an answer.
@@ -44,6 +44,9 @@ const (
44 type Entry struct {44 type Entry struct {
45 Kind Kind45 Kind Kind
46 Text string // the question, the answer, the notice; a tool's OUTPUT46 Text string // the question, the answer, the notice; a tool's OUTPUT
47+ // Who labels an answer (KindAgent) given by another agent, through /ask:
48+ // "mm [Jan (coding agent)]". Empty = this window's own agent.
49+ Who string
47 // Full is the question as the model read it when Text is its collapsed50 // Full is the question as the model read it when Text is its collapsed
48 // form — a long paste shown as `[Pasted #1 · …]`. Empty when they agree.51 // form — a long paste shown as `[Pasted #1 · …]`. Empty when they agree.
49 Full string52 Full string
@@ -76,8 +79,9 @@ func (e Entry) Detail() string {
76 type Transcript struct {79 type Transcript struct {
77 mu sync.Mutex80 mu sync.Mutex
78 entries []Entry81 entries []Entry
79- open bool // the last entry is an agent run still receiving chunks82+ open bool // the last entry is an agent run still receiving chunks
80- tools int // tool calls recorded, for the status bar83+ speaker string // Who of the answers being streamed; "" = this agent
84+ tools int // tool calls recorded, for the status bar
81 now func() time.Time85 now func() time.Time
82 }86 }
83 87
@@ -131,14 +135,22 @@ func (t *Transcript) Chunk(text string) {
131 }135 }
132 t.mu.Lock()136 t.mu.Lock()
133 defer t.mu.Unlock()137 defer t.mu.Unlock()
134- if t.open && len(t.entries) > 0 && t.entries[len(t.entries)-1].Kind == KindAgent {138+ if last := len(t.entries) - 1; t.open && last >= 0 && t.entries[last].Kind == KindAgent && t.entries[last].Who == t.speaker {
135- t.entries[len(t.entries)-1].Text += text139+ t.entries[last].Text += text
136 return140 return
137 }141 }
138- t.entries = append(t.entries, Entry{Kind: KindAgent, Text: text})142+ t.entries = append(t.entries, Entry{Kind: KindAgent, Text: text, Who: t.speaker})
139 t.open = true143 t.open = true
140 }144 }
141 145
146+// SetSpeaker names who the next answers come from — another agent during an
147+// /ask — until it is set back to "" (this window's own agent).
148+func (t *Transcript) SetSpeaker(who string) {
149+ t.mu.Lock()
150+ t.speaker = who
151+ t.mu.Unlock()
152+}
153+
142 // Thinking appends a chunk of reasoning, growing the open thought entry154 // Thinking appends a chunk of reasoning, growing the open thought entry
143 // rather than starting one per fragment — the same rule as Chunk, with its155 // rather than starting one per fragment — the same rule as Chunk, with its
144 // own kind so the conversation can tell an aside from an answer.156 // own kind so the conversation can tell an aside from an answer.
modified internal/tui/turn.go +13 -1
@@ -114,6 +114,10 @@ type runner struct {
114114 ask *permission
115115 policy consent.Policy // "for this session" and "never", per tool
116116
117+ // asking is the agent answering an /ask in progress, for the header;
118+ // nil the rest of the time.
119+ asking atomic.Pointer[speaker]
120+
117121 // streamed says the sink saw at least one chunk this turn. An answer
118122 // that did not stream (a test model, or a server answering in one block
119123 // without the retry path) is shown from the response instead.
@@ -355,9 +359,17 @@ func (r *runner) record(f store.Failure) {
355359 }
356360
357361 // header is the top line: who is answering, how full the context is, which
358-// session is being saved.
362+// session is being saved. During an /ask, the agent asked is the one
363+// answering, so it names that agent and its model instead.
359364 func (r *runner) header() string {
360365 var b strings.Builder
366+ if s := r.asking.Load(); s != nil {
367+ fmt.Fprintf(&b, "%s · %s @ %s · asked by %s", s.label, shortModel(s.model), s.provider, r.opts.AgentName)
368+ if id := r.keep.CurrentID(); id != "" {
369+ fmt.Fprintf(&b, " · session %s", id)
370+ }
371+ return b.String()
372+ }
361373 fmt.Fprintf(&b, "%s · %s @ %s", r.opts.AgentName, shortModel(r.opts.ModelName), r.opts.Provider)
362374 used := max(r.opts.Model.LastInputTokens(), compact.Estimate(r.messages))
363375 if w := r.opts.Window(); w > 0 {
@@ -114,6 +114,10 @@ type runner struct {
114 ask *permission114 ask *permission
115 policy consent.Policy // "for this session" and "never", per tool115 policy consent.Policy // "for this session" and "never", per tool
116 116
117+ // asking is the agent answering an /ask in progress, for the header;
118+ // nil the rest of the time.
119+ asking atomic.Pointer[speaker]
120+
117 // streamed says the sink saw at least one chunk this turn. An answer121 // streamed says the sink saw at least one chunk this turn. An answer
118 // that did not stream (a test model, or a server answering in one block122 // that did not stream (a test model, or a server answering in one block
119 // without the retry path) is shown from the response instead.123 // without the retry path) is shown from the response instead.
@@ -355,9 +359,17 @@ func (r *runner) record(f store.Failure) {
355 }359 }
356 360
357 // header is the top line: who is answering, how full the context is, which361 // header is the top line: who is answering, how full the context is, which
358-// session is being saved.362+// session is being saved. During an /ask, the agent asked is the one
363+// answering, so it names that agent and its model instead.
359 func (r *runner) header() string {364 func (r *runner) header() string {
360 var b strings.Builder365 var b strings.Builder
366+ if s := r.asking.Load(); s != nil {
367+ fmt.Fprintf(&b, "%s · %s @ %s · asked by %s", s.label, shortModel(s.model), s.provider, r.opts.AgentName)
368+ if id := r.keep.CurrentID(); id != "" {
369+ fmt.Fprintf(&b, " · session %s", id)
370+ }
371+ return b.String()
372+ }
361 fmt.Fprintf(&b, "%s · %s @ %s", r.opts.AgentName, shortModel(r.opts.ModelName), r.opts.Provider)373 fmt.Fprintf(&b, "%s · %s @ %s", r.opts.AgentName, shortModel(r.opts.ModelName), r.opts.Provider)
362 used := max(r.opts.Model.LastInputTokens(), compact.Estimate(r.messages))374 used := max(r.opts.Model.LastInputTokens(), compact.Estimate(r.messages))
363 if w := r.opts.Window(); w > 0 {375 if w := r.opts.Window(); w > 0 {
modified main.go +1 -1
@@ -269,7 +269,7 @@ func runWindow(ctx context.Context, e *engine.Engine, agentTools []ai.ToolRef, d
269269 Detector: d,
270270 System: config.Cfg.System,
271271 Cwd: cwd,
272- AgentName: "mm",
272+ AgentName: tui.AgentLabel(config.Cfg.ACP.Title),
273273 ModelName: config.Cfg.Model,
274274 Provider: e.Backend.Provider,
275275 Skills: skills.Declared(),
@@ -269,7 +269,7 @@ func runWindow(ctx context.Context, e *engine.Engine, agentTools []ai.ToolRef, d
269 Detector: d,269 Detector: d,
270 System: config.Cfg.System,270 System: config.Cfg.System,
271 Cwd: cwd,271 Cwd: cwd,
272- AgentName: "mm",272+ AgentName: tui.AgentLabel(config.Cfg.ACP.Title),
273 ModelName: config.Cfg.Model,273 ModelName: config.Cfg.Model,
274 Provider: e.Backend.Provider,274 Provider: e.Backend.Provider,
275 Skills: skills.Declared(),275 Skills: skills.Declared(),
added mini-mes/gopher/README.en.md +48 -0
new file mode 100644
@@ -0,0 +1,48 @@
1+# Gopher — a mini-me specialised in Go
2+
3+An `mm` agent tuned for Go development: Qwen3.8 27B served by llmman, gopls behind the `lsp` tool, and seven skills describing how to verify, fix, test, start, maintain and review Go code.
4+
5+## Contents
6+
7+| File | Purpose |
8+|---|---|
9+| `agent.gopher.yaml` | The configuration, every setting explained in a comment. |
10+| `skills/go-verify` | The check loop after each change: `gofmt -l`, `go build` + `go vet`, the package's tests then the module's, `-race` for concurrent code, linters only when installed. |
11+| `skills/go-fix` | Fix a build error, a failing or flaky test, a panic: reproduce, read the first error, name the cause, fix, prove. |
12+| `skills/go-test-writing` | Write tests: table-driven, helpers, `testdata/`, fuzzing (always with `-fuzztime`), benchmarks, coverage. |
13+| `skills/go-new-project` | Start a module: CLI, web service or library, minimal layout, first test. |
14+| `skills/go-deps` | Add, upgrade, remove a dependency; `go mod why`; govulncheck. |
15+| `skills/go-review` | Review code or the uncommitted diff, findings ranked by severity. |
16+| `skills/bg-jobs`, `skills/lsp-navigation` | Copies of the skills shipped in the repository's root `skills/`. |
17+
18+## Prerequisites
19+
20+- llmman running (`llmman serve`, port 17434) and the model pulled: `llmman pull hf.co/unsloth/Qwen3.8-27B-GGUF:Q4_K_M` (~17 GB). Otherwise the first question pulls it.
21+- gopls on the `PATH`: `go install golang.org/x/tools/gopls@latest`. Without it, `mm` prints a warning and runs without the `lsp` tool.
22+- Optional: `staticcheck` or `golangci-lint`, which `go-verify` uses when present and never installs.
23+
24+## Run
25+
26+From the Go project to work on:
27+
28+```bash
29+cd ~/src/my-go-project
30+mm -config /path/to/mini-me/mini-mes/gopher/agent.gopher.yaml
31+```
32+
33+`skillsDir` is an **absolute** path in the config: in the terminal, a relative path is resolved from the current directory (your project), not from this folder. Fix it if you move the repository.
34+
35+## Tuning choices
36+
37+- **`medium` reasoning** (`chat_template_kwargs.reasoning_effort`). Qwen3.8's template accepts `low`, `medium` and `xhigh` (default); any other value makes every request fail. `xhigh` at every tool round trip is expensive on a dense 27B.
38+- **Sampling**: `temperature 0.6`, `top_p 0.95`, `top_k 20`, `min_p 0`, Qwen's recommendation for code in thinking mode. The GGUF metadata says 1.0 / 0.95 / 20 for general use. Never `0.0` with reasoning on.
39+- **`max_tokens: 16384`**: the reasoning plus a whole `write_file` must fit in one reply.
40+- **5-minute timeouts** (`firstTokenTimeout`, `watchdogTimeout`, `bashTimeout`): model loading, long prompts, a cold `go test -race`.
41+- **`yolo: false`**: every command and every write is shown to you first; `[s]` allows a tool for the session. With `mm -p`, set `AGENT_YOLO=true`, or the calls are rejected.
42+- **Compression at 30 %** of the window: llmman serves 262,144 tokens for this model; compressing at 75 % would let the prompt grow to ~196k tokens.
43+
44+## Known limits
45+
46+- Neither gopls nor `-race` was exercised in the sandbox used to build this (no gopls, no cgo).
47+- Speeds depend on your machine; the timeouts are generous on purpose.
48+- See also: [Turn reasoning off or tune it](../../docs/en/how-to/turn-reasoning-off.md), [configuration reference](../../docs/en/reference/configuration.md), [skill format](../../docs/en/reference/skill-format.md).
new file mode 100644
@@ -0,0 +1,48 @@
1+# Gopher — a mini-me specialised in Go
2+
3+An `mm` agent tuned for Go development: Qwen3.8 27B served by llmman, gopls behind the `lsp` tool, and seven skills describing how to verify, fix, test, start, maintain and review Go code.
4+
5+## Contents
6+
7+| File | Purpose |
8+|---|---|
9+| `agent.gopher.yaml` | The configuration, every setting explained in a comment. |
10+| `skills/go-verify` | The check loop after each change: `gofmt -l`, `go build` + `go vet`, the package's tests then the module's, `-race` for concurrent code, linters only when installed. |
11+| `skills/go-fix` | Fix a build error, a failing or flaky test, a panic: reproduce, read the first error, name the cause, fix, prove. |
12+| `skills/go-test-writing` | Write tests: table-driven, helpers, `testdata/`, fuzzing (always with `-fuzztime`), benchmarks, coverage. |
13+| `skills/go-new-project` | Start a module: CLI, web service or library, minimal layout, first test. |
14+| `skills/go-deps` | Add, upgrade, remove a dependency; `go mod why`; govulncheck. |
15+| `skills/go-review` | Review code or the uncommitted diff, findings ranked by severity. |
16+| `skills/bg-jobs`, `skills/lsp-navigation` | Copies of the skills shipped in the repository's root `skills/`. |
17+
18+## Prerequisites
19+
20+- llmman running (`llmman serve`, port 17434) and the model pulled: `llmman pull hf.co/unsloth/Qwen3.8-27B-GGUF:Q4_K_M` (~17 GB). Otherwise the first question pulls it.
21+- gopls on the `PATH`: `go install golang.org/x/tools/gopls@latest`. Without it, `mm` prints a warning and runs without the `lsp` tool.
22+- Optional: `staticcheck` or `golangci-lint`, which `go-verify` uses when present and never installs.
23+
24+## Run
25+
26+From the Go project to work on:
27+
28+```bash
29+cd ~/src/my-go-project
30+mm -config /path/to/mini-me/mini-mes/gopher/agent.gopher.yaml
31+```
32+
33+`skillsDir` is an **absolute** path in the config: in the terminal, a relative path is resolved from the current directory (your project), not from this folder. Fix it if you move the repository.
34+
35+## Tuning choices
36+
37+- **`medium` reasoning** (`chat_template_kwargs.reasoning_effort`). Qwen3.8's template accepts `low`, `medium` and `xhigh` (default); any other value makes every request fail. `xhigh` at every tool round trip is expensive on a dense 27B.
38+- **Sampling**: `temperature 0.6`, `top_p 0.95`, `top_k 20`, `min_p 0`, Qwen's recommendation for code in thinking mode. The GGUF metadata says 1.0 / 0.95 / 20 for general use. Never `0.0` with reasoning on.
39+- **`max_tokens: 16384`**: the reasoning plus a whole `write_file` must fit in one reply.
40+- **5-minute timeouts** (`firstTokenTimeout`, `watchdogTimeout`, `bashTimeout`): model loading, long prompts, a cold `go test -race`.
41+- **`yolo: false`**: every command and every write is shown to you first; `[s]` allows a tool for the session. With `mm -p`, set `AGENT_YOLO=true`, or the calls are rejected.
42+- **Compression at 30 %** of the window: llmman serves 262,144 tokens for this model; compressing at 75 % would let the prompt grow to ~196k tokens.
43+
44+## Known limits
45+
46+- Neither gopls nor `-race` was exercised in the sandbox used to build this (no gopls, no cgo).
47+- Speeds depend on your machine; the timeouts are generous on purpose.
48+- See also: [Turn reasoning off or tune it](../../docs/en/how-to/turn-reasoning-off.md), [configuration reference](../../docs/en/reference/configuration.md), [skill format](../../docs/en/reference/skill-format.md).
added mini-mes/gopher/README.md +48 -0
new file mode 100644
@@ -0,0 +1,48 @@
1+# Gopher — un mini-me spécialiste de Go
2+
3+Un agent `mm` réglé pour développer en Go : Qwen3.8 27B servi par llmman, gopls derrière le tool `lsp`, et sept skills qui décrivent comment vérifier, corriger, tester, démarrer, maintenir et relire du code Go.
4+
5+## Contenu
6+
7+| Fichier | Rôle |
8+|---|---|
9+| `agent.gopher.yaml` | La configuration, chaque paramètre expliqué en commentaire. |
10+| `skills/go-verify` | La boucle de vérification après chaque changement : `gofmt -l`, `go build` + `go vet`, tests du paquet puis du module, `-race` si concurrence, linters seulement s'ils sont installés. |
11+| `skills/go-fix` | Corriger une erreur de compilation, un test qui échoue ou instable, un panic : reproduire, lire la première erreur, nommer la cause, corriger, prouver. |
12+| `skills/go-test-writing` | Écrire des tests : table-driven, helpers, `testdata/`, fuzz (toujours avec `-fuzztime`), benchmarks, couverture. |
13+| `skills/go-new-project` | Démarrer un module : CLI, service web ou bibliothèque, structure minimale, premier test. |
14+| `skills/go-deps` | Ajouter, mettre à jour, retirer une dépendance ; `go mod why` ; govulncheck. |
15+| `skills/go-review` | Relire du code ou le diff non commité, constats classés par gravité. |
16+| `skills/bg-jobs`, `skills/lsp-navigation` | Copies des skills livrés dans `skills/` à la racine du dépôt. |
17+
18+## Prérequis
19+
20+- llmman lancé (`llmman serve`, port 17434) et le modèle téléchargé : `llmman pull hf.co/unsloth/Qwen3.8-27B-GGUF:Q4_K_M` (~17 Go). Sinon, la première question le télécharge.
21+- gopls sur le `PATH` : `go install golang.org/x/tools/gopls@latest`. Sans lui, `mm` affiche un avertissement et tourne sans le tool `lsp`.
22+- Facultatif : `staticcheck` ou `golangci-lint`, que `go-verify` utilise s'ils sont présents et n'installe jamais.
23+
24+## Lancer
25+
26+Depuis le projet Go sur lequel travailler :
27+
28+```bash
29+cd ~/src/mon-projet-go
30+mm -config /chemin/vers/mini-me/mini-mes/gopher/agent.gopher.yaml
31+```
32+
33+`skillsDir` est un chemin **absolu** dans la config : en mode terminal, un chemin relatif serait résolu depuis le répertoire courant (votre projet), pas depuis ce dossier. Si vous déplacez le dépôt, corrigez-le.
34+
35+## Choix de réglage
36+
37+- **Raisonnement `medium`** (`chat_template_kwargs.reasoning_effort`). Le template de Qwen3.8 accepte `low`, `medium` et `xhigh` (défaut) ; toute autre valeur fait échouer chaque requête. `xhigh` à chaque aller-retour d'outil coûte cher sur un 27B dense.
38+- **Échantillonnage** : `temperature 0.6`, `top_p 0.95`, `top_k 20`, `min_p 0`, la recommandation de Qwen pour le code en mode raisonnement. Les métadonnées du GGUF indiquent 1.0 / 0.95 / 20 pour un usage général. Jamais `0.0` avec le raisonnement actif.
39+- **`max_tokens: 16384`** : le raisonnement plus un `write_file` complet doivent tenir dans une réponse.
40+- **Délais à 5 min** (`firstTokenTimeout`, `watchdogTimeout`, `bashTimeout`) : chargement du modèle, lecture de longs prompts, `go test -race` à froid.
41+- **`yolo: false`** : chaque commande et chaque écriture vous sont soumises ; `[s]` autorise un outil pour la session. Avec `mm -p`, il faut `AGENT_YOLO=true`, sinon les appels sont refusés.
42+- **Compression à 30 %** de la fenêtre : llmman sert 262 144 tokens pour ce modèle ; compresser à 75 % laisserait le prompt grossir jusqu'à ~196k tokens.
43+
44+## Limites connues
45+
46+- Ni gopls ni `-race` n'ont été exercés dans la sandbox de mise au point (gopls absent, pas de cgo).
47+- Les vitesses dépendent de votre machine ; les délais sont larges exprès.
48+- Voir aussi : [Couper ou régler le raisonnement](../../docs/fr/how-to/turn-reasoning-off.md), [référence de la configuration](../../docs/fr/reference/configuration.md), [format des skills](../../docs/fr/reference/skill-format.md).
new file mode 100644
@@ -0,0 +1,48 @@
1+# Gopher — un mini-me spécialiste de Go
2+
3+Un agent `mm` réglé pour développer en Go : Qwen3.8 27B servi par llmman, gopls derrière le tool `lsp`, et sept skills qui décrivent comment vérifier, corriger, tester, démarrer, maintenir et relire du code Go.
4+
5+## Contenu
6+
7+| Fichier | Rôle |
8+|---|---|
9+| `agent.gopher.yaml` | La configuration, chaque paramètre expliqué en commentaire. |
10+| `skills/go-verify` | La boucle de vérification après chaque changement : `gofmt -l`, `go build` + `go vet`, tests du paquet puis du module, `-race` si concurrence, linters seulement s'ils sont installés. |
11+| `skills/go-fix` | Corriger une erreur de compilation, un test qui échoue ou instable, un panic : reproduire, lire la première erreur, nommer la cause, corriger, prouver. |
12+| `skills/go-test-writing` | Écrire des tests : table-driven, helpers, `testdata/`, fuzz (toujours avec `-fuzztime`), benchmarks, couverture. |
13+| `skills/go-new-project` | Démarrer un module : CLI, service web ou bibliothèque, structure minimale, premier test. |
14+| `skills/go-deps` | Ajouter, mettre à jour, retirer une dépendance ; `go mod why` ; govulncheck. |
15+| `skills/go-review` | Relire du code ou le diff non commité, constats classés par gravité. |
16+| `skills/bg-jobs`, `skills/lsp-navigation` | Copies des skills livrés dans `skills/` à la racine du dépôt. |
17+
18+## Prérequis
19+
20+- llmman lancé (`llmman serve`, port 17434) et le modèle téléchargé : `llmman pull hf.co/unsloth/Qwen3.8-27B-GGUF:Q4_K_M` (~17 Go). Sinon, la première question le télécharge.
21+- gopls sur le `PATH` : `go install golang.org/x/tools/gopls@latest`. Sans lui, `mm` affiche un avertissement et tourne sans le tool `lsp`.
22+- Facultatif : `staticcheck` ou `golangci-lint`, que `go-verify` utilise s'ils sont présents et n'installe jamais.
23+
24+## Lancer
25+
26+Depuis le projet Go sur lequel travailler :
27+
28+```bash
29+cd ~/src/mon-projet-go
30+mm -config /chemin/vers/mini-me/mini-mes/gopher/agent.gopher.yaml
31+```
32+
33+`skillsDir` est un chemin **absolu** dans la config : en mode terminal, un chemin relatif serait résolu depuis le répertoire courant (votre projet), pas depuis ce dossier. Si vous déplacez le dépôt, corrigez-le.
34+
35+## Choix de réglage
36+
37+- **Raisonnement `medium`** (`chat_template_kwargs.reasoning_effort`). Le template de Qwen3.8 accepte `low`, `medium` et `xhigh` (défaut) ; toute autre valeur fait échouer chaque requête. `xhigh` à chaque aller-retour d'outil coûte cher sur un 27B dense.
38+- **Échantillonnage** : `temperature 0.6`, `top_p 0.95`, `top_k 20`, `min_p 0`, la recommandation de Qwen pour le code en mode raisonnement. Les métadonnées du GGUF indiquent 1.0 / 0.95 / 20 pour un usage général. Jamais `0.0` avec le raisonnement actif.
39+- **`max_tokens: 16384`** : le raisonnement plus un `write_file` complet doivent tenir dans une réponse.
40+- **Délais à 5 min** (`firstTokenTimeout`, `watchdogTimeout`, `bashTimeout`) : chargement du modèle, lecture de longs prompts, `go test -race` à froid.
41+- **`yolo: false`** : chaque commande et chaque écriture vous sont soumises ; `[s]` autorise un outil pour la session. Avec `mm -p`, il faut `AGENT_YOLO=true`, sinon les appels sont refusés.
42+- **Compression à 30 %** de la fenêtre : llmman sert 262 144 tokens pour ce modèle ; compresser à 75 % laisserait le prompt grossir jusqu'à ~196k tokens.
43+
44+## Limites connues
45+
46+- Ni gopls ni `-race` n'ont été exercés dans la sandbox de mise au point (gopls absent, pas de cgo).
47+- Les vitesses dépendent de votre machine ; les délais sont larges exprès.
48+- Voir aussi : [Couper ou régler le raisonnement](../../docs/fr/how-to/turn-reasoning-off.md), [référence de la configuration](../../docs/fr/reference/configuration.md), [format des skills](../../docs/fr/reference/skill-format.md).
added mini-mes/gopher/agent.gopher.yaml +276 -0
new file mode 100644
@@ -0,0 +1,276 @@
1+# Gopher — a mini-me specialised in Go development.
2+#
3+# Served by llmman (https://github.com/llmmanorg/llmman) through its
4+# OpenAI-compatible endpoint, with Qwen3.8 27B: a dense 27B thinking model,
5+# strong on code and tool calling, slow-ish on a laptop — several settings
6+# below exist only because of that.
7+#
8+# llmman pull hf.co/unsloth/Qwen3.8-27B-GGUF:Q4_K_M # ~17 GB, once
9+# llmman serve # 127.0.0.1:17434
10+#
11+# Run it FROM THE GO PROJECT you want to work on (bash, the file tools and
12+# gopls all work in the current directory):
13+#
14+# cd ~/src/my-go-project
15+# mm -config /path/to/mini-mes/gopher/agent.gopher.yaml
16+#
17+# Every key is optional: a key left out keeps mm's built-in default. Reference:
18+# docs/en/reference/configuration.md.
19+
20+# ─── Model and server ────────────────────────────────────────────────────────
21+
22+# Which server family mm talks to. `llmman` = OpenAI API under /v1, a
23+# llama-server per model underneath, the served window read from /api/ps, and
24+# the model pulled automatically on the first request if it is missing.
25+provider: llmman
26+
27+# The model id exactly as `llmman list` (or GET /v1/models) spells it.
28+# model: hf.co/unsloth/Qwen3.8-27B-GGUF:Q4_K_M
29+# model: hf.co/unsloth/Qwen3-Coder-Next-GGUF:Q4_K_M
30+# model: hf.co/mistralai/Devstral-Small-2-24B-Instruct-2512:latest
31+
32+# Endpoint tried first: `llmman serve`'s default bind.
33+baseUrl: http://127.0.0.1:17434/v1
34+
35+# Endpoint used when baseUrl does not answer within 2 s — the host's llmman
36+# seen from a Docker sandbox. Harmless on the host itself.
37+fallback: http://host.docker.internal:17434/v1
38+
39+# Only when llmman was started with LLMMAN_API_KEYS (mandatory when it listens
40+# beyond loopback). Names the variable holding the key; the key itself never
41+# goes in this file.
42+# apiKeyEnv: LLMMAN_API_KEY
43+
44+# Tokens the server serves. 0 = ask llmman (/api/ps, once the model is loaded:
45+# the window is learned before the second question). Only the compression below
46+# uses it. Never set it HIGHER than what llmman really serves (see
47+# LLMMAN_CONTEXT_LENGTH): the server would refuse prompts mm thinks still fit.
48+contextWindow: 0
49+
50+# ─── Generation ──────────────────────────────────────────────────────────────
51+
52+# Sent to the server with every request. OpenAI key names; keys the OpenAI API
53+# does not know (top_k, min_p, chat_template_kwargs) are forwarded as they are,
54+# and llama-server reads them. Keys you leave out keep mm's defaults.
55+sampling:
56+ # Qwen's recommendation for a thinking model on precise coding tasks.
57+ # The GGUF's own metadata says temp 1.0 / top_p 0.95 / top_k 20 (general
58+ # use); 0.6 trades a little variety for steadier code. Do NOT use 0.0 with
59+ # reasoning on: Qwen warns that greedy decoding makes thinking models loop.
60+ temperature: 0.6
61+ top_p: 0.95
62+ top_k: 20
63+ min_p: 0.0
64+
65+ # Upper bound for ONE model reply: its reasoning + its answer or tool call.
66+ # A write_file of a whole Go file plus the thinking before it needs room;
67+ # when a tool call hits the limit mm asks the model to split it, twice, then
68+ # stops with "the model hit max_tokens". Raise it if you see that.
69+ max_tokens: 16384
70+
71+ # One tool call per reply. Go work is sequential (edit, then build, then
72+ # test); parallel calls make a model run the test before the edit lands.
73+ parallel_tool_calls: false
74+
75+ # Variables of the model's chat template (llama-server renders them).
76+ # Qwen3.8's template reads both, verified on the GGUF served by llmman:
77+ # enable_thinking true | false — false = no reasoning at all (fastest).
78+ # reasoning_effort low | medium | xhigh (default; `high` means xhigh).
79+ # Any other value makes the template raise an error: every request fails.
80+ # It is only read when enable_thinking is true.
81+ # `medium`: the model thinks before each step, without the long xhigh
82+ # deliberation that a 27B dense model pays for at every tool round trip.
83+ # Switch to `low` for speed, `xhigh` for a hard design or concurrency bug.
84+ # Compaction summaries ignore all this: mm turns reasoning off for them.
85+ chat_template_kwargs:
86+ enable_thinking: true
87+ reasoning_effort: low
88+
89+# Show the model's reasoning (dim italic 💭 block in the terminal, its own
90+# entry in the window, a thought chunk in an editor). Display only: mm reads
91+# the reasoning either way, because that is what keeps the watchdog alive.
92+showThinking: true
93+
94+# ─── Timeouts ────────────────────────────────────────────────────────────────
95+# A 27B dense model on a laptop reads a long prompt slowly, and Go commands
96+# (first `go test ./...`, module downloads, -race builds) take time.
97+
98+# Silence tolerated before a model call's first token, while the server reads
99+# the prompt. llama-server reports its progress through llmman, and each
100+# report restarts this clock; it also covers loading the model (~17 GB) on
101+# the first question.
102+firstTokenTimeout: 5m
103+
104+# Silence tolerated between two streamed tokens. It keeps counting while a
105+# bash command runs, so it must be at least bashTimeout.
106+watchdogTimeout: 5m
107+
108+# How long one bash command may run before it is killed. Five minutes covers
109+# a cold `go test -race ./...` with module downloads.
110+bashTimeout: 5m
111+
112+# ─── Agent loop ──────────────────────────────────────────────────────────────
113+
114+# Max model <-> tools round trips for ONE question. A Go change is read →
115+# edit → build → test → fix, several times over: 60 leaves room for that.
116+maxTurns: 60
117+
118+# Max characters of a tool result handed back to the model (head kept, plus up
119+# to 2000 characters of tail). `go test` and `go vet` failures are verbose;
120+# 20000 keeps the whole report in most cases without flooding the context.
121+maxOutput: 20000
122+
123+# Lines of a command's output echoed in the terminal while it runs. 0 = none.
124+previewLines: 20
125+
126+# Print the numbered list of commands and file changes after each answer.
127+displayCommands: true
128+
129+# ─── Tools ───────────────────────────────────────────────────────────────────
130+
131+# Ask before every tool call that changes something (bash, write_file,
132+# edit_file, lsp rename, fetch_content with output, plan changes). Answers:
133+# [a] once, [s] this tool for the session, [r] reject, [n] never.
134+# Reading files and loading skills never ask.
135+# false = you see each command before it runs; [s] on bash once you trust the
136+# session. Set it to true (or run with AGENT_YOLO=true) for unattended work.
137+# With `mm -p` nobody can answer: calls are rejected unless yolo is true.
138+yolo: false
139+
140+# The `bash` tool: go build, go test, go vet, gofmt, git status…
141+bashTool: true
142+
143+# read_file / edit_file / write_file: exact, diff-checked edits — how the
144+# gopher changes code.
145+editTools: true
146+
147+# The `plan` tool: a visible todo list for multi-step requests.
148+planTool: true
149+
150+# `fetch_content`: fetch a web page as Markdown — pkg.go.dev, go.dev/doc,
151+# a library's README — so the model reads the real API instead of recalling
152+# it. The only built-in tool that reaches the network.
153+fetchContentTool: true
154+
155+# The `lsp` tool, backed by gopls: definition, references, hover, symbols,
156+# diagnostics, rename across the module. Install it with
157+# go install golang.org/x/tools/gopls@latest
158+# and make sure $(go env GOPATH)/bin is on the PATH. Missing = a start-up
159+# warning and no lsp tool; everything else still works.
160+lsp:
161+ servers:
162+ - name: gopls
163+ command: gopls
164+ extensions: [".go"]
165+
166+# ─── Skills ──────────────────────────────────────────────────────────────────
167+
168+# Where `read_skill` finds its procedures. In the terminal a RELATIVE path is
169+# resolved from the directory mm is started in — your Go project, not this
170+# folder — so it is absolute here. Adjust it if you move the repository.
171+# (In an editor, through ACP, a relative path follows this file instead.)
172+#skillsDir: /Users/k33g/kDrive/Rickub/bots-garden/mini-me/mini-mes/gopher/skills
173+skillsDir: skills
174+
175+# ─── Memory ──────────────────────────────────────────────────────────────────
176+
177+# Save each conversation, per project, under .mm/sessions of the directory mm
178+# is started in. /sessions lists them, /resume continues one.
179+# Add `.mm/` to the project's .gitignore.
180+sessions:
181+ enabled: true
182+ dir: .mm/sessions
183+
184+# Automatic history compression, so a long session does not outgrow the
185+# window (and a 27B model does not slow down on an ever-longer prompt).
186+context:
187+ enabled: true
188+
189+ # Compress once the history fills this share of the window. llmman serves
190+ # 262,144 tokens for this model (measured, /api/ps): the default 75 would
191+ # let the prompt reach ~196k tokens, which a 27B dense model reads slowly
192+ # and reasons over poorly. 30 = ~79k. If you lower LLMMAN_CONTEXT_LENGTH,
193+ # raise this in proportion (e.g. 65536 served → 75).
194+ threshold: 30
195+
196+ # Fallback when the window is still unknown (before the model is loaded):
197+ # compress past this many messages. One command = 2 messages.
198+ maxMessages: 120
199+
200+ # Recent questions kept verbatim, with their commands and answers: the model
201+ # works on these, summarising them would make it redo what it just did.
202+ keepLastTurns: 3
203+
204+ # max_tokens of the summary. Reasoning is off for it (mm forces it), so the
205+ # whole budget goes to the summary: file names, decisions, what is left.
206+ summaryMaxTokens: 2000
207+
208+ # One 🗜️ line after each compression.
209+ showStats: true
210+
211+# ─── Identity ────────────────────────────────────────────────────────────────
212+
213+# How the agent introduces itself to an editor over ACP (`mm -acp`).
214+acp:
215+ name: gopher
216+ title: Gopher (Go specialist)
217+
218+# The system prompt: who the agent is and how it works. The shortest path to
219+# changing behaviour. Written for this model: precise rules, the Go toolchain
220+# as the source of truth, skills for each kind of task.
221+system: |
222+ You are Gopher, a senior Go engineer working in a terminal, in the user's
223+ Go module (the current directory). You write simple, idiomatic, tested Go,
224+ in the spirit of Effective Go and the Go Code Review Comments.
225+
226+ TOOLS
227+ - `bash` runs commands: go build, go test, go vet, gofmt, go mod, git status.
228+ - `read_file`, `edit_file`, `write_file` read and change files.
229+ - `lsp` asks gopls: definition, references, hover, symbols, diagnostics,
230+ rename. Prefer it to grep for questions about Go symbols.
231+ - `fetch_content` reads a web page (pkg.go.dev, go.dev/doc) as Markdown.
232+ - `plan` keeps a visible todo list when a request has several steps.
233+ - `read_skill` loads a procedure. Its description lists them.
234+
235+ FACTS COME FROM TOOLS
236+ Never state what a file contains, what a command prints, or whether code
237+ compiles unless a tool returned it in THIS answer. Before using a library
238+ API you are not sure of, read it: `go doc <pkg>.<Symbol>` with bash, or
239+ pkg.go.dev with fetch_content. Check the `go` line of go.mod before using a
240+ language or standard-library feature newer than that version.
241+
242+ SKILLS
243+ Any request to DO something Go-specific — verify, fix a failing build or
244+ test, write tests, start a project, manage dependencies, review code — has
245+ a skill. Call `read_skill` FIRST, before any other tool, then follow it.
246+
247+ EDITING
248+ - Read before you write: `read_file` (numbered=true when you need lines).
249+ - Change an existing file with `edit_file`; `old` is copied character for
250+ character and appears exactly once. `write_file` only creates a file or
251+ rewrites it entirely on purpose. If `edit_file` refuses, read again and
252+ fix `old` — never fall back to `write_file` to force it.
253+ - After every edit to Go code: `gofmt -l` on the file, then the narrowest
254+ `go build` / `go test` that covers it. A change is done when it compiles
255+ and its tests pass, not before.
256+
257+ GO STYLE
258+ - Errors are values: check every one, wrap with `fmt.Errorf("doing x: %w", err)`,
259+ compare with errors.Is / errors.As. No panic for ordinary failures.
260+ - context.Context is the first parameter of anything that blocks or does I/O.
261+ - Every goroutine has a clear owner and a way to stop; no leaks.
262+ - Accept interfaces, return concrete types; small interfaces defined where
263+ they are used. No getters named GetX. MixedCaps, short receiver names.
264+ - Standard library first; a new dependency needs a reason you can state.
265+ - Tests are table-driven with t.Run subtests, and use t.Helper in helpers.
266+
267+ RULES
268+ - Touch only what the request is about. Keep existing behaviour unless asked.
269+ - Never run git commands that change state (commit, push, reset, checkout)
270+ unless the user says so. git status / git diff are fine.
271+ - Never delete, move or rename files unless asked.
272+ - Nothing is interactive: no stdin. Servers and watchers go to the
273+ background — read the `bg-jobs` skill first — and are stopped before you
274+ finish.
275+ - Answer in the user's language, briefly: what changed, what you ran, the
276+ result. Show code only when it helps.
new file mode 100644
@@ -0,0 +1,276 @@
1+# Gopher — a mini-me specialised in Go development.
2+#
3+# Served by llmman (https://github.com/llmmanorg/llmman) through its
4+# OpenAI-compatible endpoint, with Qwen3.8 27B: a dense 27B thinking model,
5+# strong on code and tool calling, slow-ish on a laptop — several settings
6+# below exist only because of that.
7+#
8+# llmman pull hf.co/unsloth/Qwen3.8-27B-GGUF:Q4_K_M # ~17 GB, once
9+# llmman serve # 127.0.0.1:17434
10+#
11+# Run it FROM THE GO PROJECT you want to work on (bash, the file tools and
12+# gopls all work in the current directory):
13+#
14+# cd ~/src/my-go-project
15+# mm -config /path/to/mini-mes/gopher/agent.gopher.yaml
16+#
17+# Every key is optional: a key left out keeps mm's built-in default. Reference:
18+# docs/en/reference/configuration.md.
19+
20+# ─── Model and server ────────────────────────────────────────────────────────
21+
22+# Which server family mm talks to. `llmman` = OpenAI API under /v1, a
23+# llama-server per model underneath, the served window read from /api/ps, and
24+# the model pulled automatically on the first request if it is missing.
25+provider: llmman
26+
27+# The model id exactly as `llmman list` (or GET /v1/models) spells it.
28+# model: hf.co/unsloth/Qwen3.8-27B-GGUF:Q4_K_M
29+# model: hf.co/unsloth/Qwen3-Coder-Next-GGUF:Q4_K_M
30+# model: hf.co/mistralai/Devstral-Small-2-24B-Instruct-2512:latest
31+
32+# Endpoint tried first: `llmman serve`'s default bind.
33+baseUrl: http://127.0.0.1:17434/v1
34+
35+# Endpoint used when baseUrl does not answer within 2 s — the host's llmman
36+# seen from a Docker sandbox. Harmless on the host itself.
37+fallback: http://host.docker.internal:17434/v1
38+
39+# Only when llmman was started with LLMMAN_API_KEYS (mandatory when it listens
40+# beyond loopback). Names the variable holding the key; the key itself never
41+# goes in this file.
42+# apiKeyEnv: LLMMAN_API_KEY
43+
44+# Tokens the server serves. 0 = ask llmman (/api/ps, once the model is loaded:
45+# the window is learned before the second question). Only the compression below
46+# uses it. Never set it HIGHER than what llmman really serves (see
47+# LLMMAN_CONTEXT_LENGTH): the server would refuse prompts mm thinks still fit.
48+contextWindow: 0
49+
50+# ─── Generation ──────────────────────────────────────────────────────────────
51+
52+# Sent to the server with every request. OpenAI key names; keys the OpenAI API
53+# does not know (top_k, min_p, chat_template_kwargs) are forwarded as they are,
54+# and llama-server reads them. Keys you leave out keep mm's defaults.
55+sampling:
56+ # Qwen's recommendation for a thinking model on precise coding tasks.
57+ # The GGUF's own metadata says temp 1.0 / top_p 0.95 / top_k 20 (general
58+ # use); 0.6 trades a little variety for steadier code. Do NOT use 0.0 with
59+ # reasoning on: Qwen warns that greedy decoding makes thinking models loop.
60+ temperature: 0.6
61+ top_p: 0.95
62+ top_k: 20
63+ min_p: 0.0
64+
65+ # Upper bound for ONE model reply: its reasoning + its answer or tool call.
66+ # A write_file of a whole Go file plus the thinking before it needs room;
67+ # when a tool call hits the limit mm asks the model to split it, twice, then
68+ # stops with "the model hit max_tokens". Raise it if you see that.
69+ max_tokens: 16384
70+
71+ # One tool call per reply. Go work is sequential (edit, then build, then
72+ # test); parallel calls make a model run the test before the edit lands.
73+ parallel_tool_calls: false
74+
75+ # Variables of the model's chat template (llama-server renders them).
76+ # Qwen3.8's template reads both, verified on the GGUF served by llmman:
77+ # enable_thinking true | false — false = no reasoning at all (fastest).
78+ # reasoning_effort low | medium | xhigh (default; `high` means xhigh).
79+ # Any other value makes the template raise an error: every request fails.
80+ # It is only read when enable_thinking is true.
81+ # `medium`: the model thinks before each step, without the long xhigh
82+ # deliberation that a 27B dense model pays for at every tool round trip.
83+ # Switch to `low` for speed, `xhigh` for a hard design or concurrency bug.
84+ # Compaction summaries ignore all this: mm turns reasoning off for them.
85+ chat_template_kwargs:
86+ enable_thinking: true
87+ reasoning_effort: low
88+
89+# Show the model's reasoning (dim italic 💭 block in the terminal, its own
90+# entry in the window, a thought chunk in an editor). Display only: mm reads
91+# the reasoning either way, because that is what keeps the watchdog alive.
92+showThinking: true
93+
94+# ─── Timeouts ────────────────────────────────────────────────────────────────
95+# A 27B dense model on a laptop reads a long prompt slowly, and Go commands
96+# (first `go test ./...`, module downloads, -race builds) take time.
97+
98+# Silence tolerated before a model call's first token, while the server reads
99+# the prompt. llama-server reports its progress through llmman, and each
100+# report restarts this clock; it also covers loading the model (~17 GB) on
101+# the first question.
102+firstTokenTimeout: 5m
103+
104+# Silence tolerated between two streamed tokens. It keeps counting while a
105+# bash command runs, so it must be at least bashTimeout.
106+watchdogTimeout: 5m
107+
108+# How long one bash command may run before it is killed. Five minutes covers
109+# a cold `go test -race ./...` with module downloads.
110+bashTimeout: 5m
111+
112+# ─── Agent loop ──────────────────────────────────────────────────────────────
113+
114+# Max model <-> tools round trips for ONE question. A Go change is read →
115+# edit → build → test → fix, several times over: 60 leaves room for that.
116+maxTurns: 60
117+
118+# Max characters of a tool result handed back to the model (head kept, plus up
119+# to 2000 characters of tail). `go test` and `go vet` failures are verbose;
120+# 20000 keeps the whole report in most cases without flooding the context.
121+maxOutput: 20000
122+
123+# Lines of a command's output echoed in the terminal while it runs. 0 = none.
124+previewLines: 20
125+
126+# Print the numbered list of commands and file changes after each answer.
127+displayCommands: true
128+
129+# ─── Tools ───────────────────────────────────────────────────────────────────
130+
131+# Ask before every tool call that changes something (bash, write_file,
132+# edit_file, lsp rename, fetch_content with output, plan changes). Answers:
133+# [a] once, [s] this tool for the session, [r] reject, [n] never.
134+# Reading files and loading skills never ask.
135+# false = you see each command before it runs; [s] on bash once you trust the
136+# session. Set it to true (or run with AGENT_YOLO=true) for unattended work.
137+# With `mm -p` nobody can answer: calls are rejected unless yolo is true.
138+yolo: false
139+
140+# The `bash` tool: go build, go test, go vet, gofmt, git status…
141+bashTool: true
142+
143+# read_file / edit_file / write_file: exact, diff-checked edits — how the
144+# gopher changes code.
145+editTools: true
146+
147+# The `plan` tool: a visible todo list for multi-step requests.
148+planTool: true
149+
150+# `fetch_content`: fetch a web page as Markdown — pkg.go.dev, go.dev/doc,
151+# a library's README — so the model reads the real API instead of recalling
152+# it. The only built-in tool that reaches the network.
153+fetchContentTool: true
154+
155+# The `lsp` tool, backed by gopls: definition, references, hover, symbols,
156+# diagnostics, rename across the module. Install it with
157+# go install golang.org/x/tools/gopls@latest
158+# and make sure $(go env GOPATH)/bin is on the PATH. Missing = a start-up
159+# warning and no lsp tool; everything else still works.
160+lsp:
161+ servers:
162+ - name: gopls
163+ command: gopls
164+ extensions: [".go"]
165+
166+# ─── Skills ──────────────────────────────────────────────────────────────────
167+
168+# Where `read_skill` finds its procedures. In the terminal a RELATIVE path is
169+# resolved from the directory mm is started in — your Go project, not this
170+# folder — so it is absolute here. Adjust it if you move the repository.
171+# (In an editor, through ACP, a relative path follows this file instead.)
172+#skillsDir: /Users/k33g/kDrive/Rickub/bots-garden/mini-me/mini-mes/gopher/skills
173+skillsDir: skills
174+
175+# ─── Memory ──────────────────────────────────────────────────────────────────
176+
177+# Save each conversation, per project, under .mm/sessions of the directory mm
178+# is started in. /sessions lists them, /resume continues one.
179+# Add `.mm/` to the project's .gitignore.
180+sessions:
181+ enabled: true
182+ dir: .mm/sessions
183+
184+# Automatic history compression, so a long session does not outgrow the
185+# window (and a 27B model does not slow down on an ever-longer prompt).
186+context:
187+ enabled: true
188+
189+ # Compress once the history fills this share of the window. llmman serves
190+ # 262,144 tokens for this model (measured, /api/ps): the default 75 would
191+ # let the prompt reach ~196k tokens, which a 27B dense model reads slowly
192+ # and reasons over poorly. 30 = ~79k. If you lower LLMMAN_CONTEXT_LENGTH,
193+ # raise this in proportion (e.g. 65536 served → 75).
194+ threshold: 30
195+
196+ # Fallback when the window is still unknown (before the model is loaded):
197+ # compress past this many messages. One command = 2 messages.
198+ maxMessages: 120
199+
200+ # Recent questions kept verbatim, with their commands and answers: the model
201+ # works on these, summarising them would make it redo what it just did.
202+ keepLastTurns: 3
203+
204+ # max_tokens of the summary. Reasoning is off for it (mm forces it), so the
205+ # whole budget goes to the summary: file names, decisions, what is left.
206+ summaryMaxTokens: 2000
207+
208+ # One 🗜️ line after each compression.
209+ showStats: true
210+
211+# ─── Identity ────────────────────────────────────────────────────────────────
212+
213+# How the agent introduces itself to an editor over ACP (`mm -acp`).
214+acp:
215+ name: gopher
216+ title: Gopher (Go specialist)
217+
218+# The system prompt: who the agent is and how it works. The shortest path to
219+# changing behaviour. Written for this model: precise rules, the Go toolchain
220+# as the source of truth, skills for each kind of task.
221+system: |
222+ You are Gopher, a senior Go engineer working in a terminal, in the user's
223+ Go module (the current directory). You write simple, idiomatic, tested Go,
224+ in the spirit of Effective Go and the Go Code Review Comments.
225+
226+ TOOLS
227+ - `bash` runs commands: go build, go test, go vet, gofmt, go mod, git status.
228+ - `read_file`, `edit_file`, `write_file` read and change files.
229+ - `lsp` asks gopls: definition, references, hover, symbols, diagnostics,
230+ rename. Prefer it to grep for questions about Go symbols.
231+ - `fetch_content` reads a web page (pkg.go.dev, go.dev/doc) as Markdown.
232+ - `plan` keeps a visible todo list when a request has several steps.
233+ - `read_skill` loads a procedure. Its description lists them.
234+
235+ FACTS COME FROM TOOLS
236+ Never state what a file contains, what a command prints, or whether code
237+ compiles unless a tool returned it in THIS answer. Before using a library
238+ API you are not sure of, read it: `go doc <pkg>.<Symbol>` with bash, or
239+ pkg.go.dev with fetch_content. Check the `go` line of go.mod before using a
240+ language or standard-library feature newer than that version.
241+
242+ SKILLS
243+ Any request to DO something Go-specific — verify, fix a failing build or
244+ test, write tests, start a project, manage dependencies, review code — has
245+ a skill. Call `read_skill` FIRST, before any other tool, then follow it.
246+
247+ EDITING
248+ - Read before you write: `read_file` (numbered=true when you need lines).
249+ - Change an existing file with `edit_file`; `old` is copied character for
250+ character and appears exactly once. `write_file` only creates a file or
251+ rewrites it entirely on purpose. If `edit_file` refuses, read again and
252+ fix `old` — never fall back to `write_file` to force it.
253+ - After every edit to Go code: `gofmt -l` on the file, then the narrowest
254+ `go build` / `go test` that covers it. A change is done when it compiles
255+ and its tests pass, not before.
256+
257+ GO STYLE
258+ - Errors are values: check every one, wrap with `fmt.Errorf("doing x: %w", err)`,
259+ compare with errors.Is / errors.As. No panic for ordinary failures.
260+ - context.Context is the first parameter of anything that blocks or does I/O.
261+ - Every goroutine has a clear owner and a way to stop; no leaks.
262+ - Accept interfaces, return concrete types; small interfaces defined where
263+ they are used. No getters named GetX. MixedCaps, short receiver names.
264+ - Standard library first; a new dependency needs a reason you can state.
265+ - Tests are table-driven with t.Run subtests, and use t.Helper in helpers.
266+
267+ RULES
268+ - Touch only what the request is about. Keep existing behaviour unless asked.
269+ - Never run git commands that change state (commit, push, reset, checkout)
270+ unless the user says so. git status / git diff are fine.
271+ - Never delete, move or rename files unless asked.
272+ - Nothing is interactive: no stdin. Servers and watchers go to the
273+ background — read the `bg-jobs` skill first — and are stopped before you
274+ finish.
275+ - Answer in the user's language, briefly: what changed, what you ran, the
276+ result. Show code only when it helps.
added mini-mes/gopher/skills/bg-jobs/SKILL.md +82 -0
new file mode 100644
@@ -0,0 +1,82 @@
1+---
2+name: bg-jobs
3+description: Start, wait on, inspect and stop a long-running background job — a server, a watcher, a build that does not end — without blocking the turn.
4+keywords: background, job, server, serve, start, daemon, nohup, watch, tail, log, pid, kill, stop, port, running
5+---
6+
7+# Background jobs
8+
9+## When to use it
10+
11+Any command that **serves, watches, or runs until stopped**: an HTTP server, `npm run dev`, `go run` on a web app, a file watcher, a queue worker. Read this before you start one, and before you wait on, inspect or stop one.
12+
13+A command that never returns will hold the turn for its whole budget and then be killed. The answer the user asked for never arrives.
14+
15+## Start it
16+
17+Both streams redirected, the pid kept:
18+
19+```bash
20+nohup <command> > /tmp/<job>.log 2>&1 & echo $! > /tmp/<job>.pid
21+```
22+
23+Three parts, and all three matter:
24+
25+- **`> /tmp/<job>.log 2>&1`** — both streams. Redirecting only stdout is the classic mistake: the job keeps the tool's own error pipe open, and the call cannot finish until the job does. You get the 30-second budget spent on nothing.
26+- **`&`** — the shell returns at once.
27+- **`echo $! > /tmp/<job>.pid`** — without the pid you cannot stop it later except by guessing at `pkill` patterns, which also kills things you did not start.
28+
29+Use one name per job, and reuse it for the log and the pid file.
30+
31+## Wait for it to be ready
32+
33+**Do not `sleep` and hope.** Poll for the thing you actually need, with a bound:
34+
35+```bash
36+for i in $(seq 1 30); do
37+ curl -fsS localhost:8080/ >/dev/null 2>&1 && echo ready && break
38+ sleep 0.5
39+done
40+```
41+
42+For something that is not an HTTP server, poll the log for the line it prints when it is up:
43+
44+```bash
45+for i in $(seq 1 30); do
46+ grep -q "listening on" /tmp/<job>.log && echo ready && break
47+ sleep 0.5
48+done
49+```
50+
51+If the loop ends without `ready`, the job did not start — go read the log.
52+
53+## Inspect it
54+
55+```bash
56+tail -n 40 /tmp/<job>.log # what it said
57+kill -0 "$(cat /tmp/<job>.pid)" 2>/dev/null && echo alive || echo dead
58+```
59+
60+`kill -0` sends no signal; it only asks whether the process is there. A job that is `dead` right after starting almost always says why in the last lines of its log — read them before changing anything.
61+
62+## Stop it
63+
64+```bash
65+kill "$(cat /tmp/<job>.pid)" 2>/dev/null
66+sleep 0.5
67+kill -0 "$(cat /tmp/<job>.pid)" 2>/dev/null && kill -9 "$(cat /tmp/<job>.pid)"
68+rm -f /tmp/<job>.pid
69+```
70+
71+Ask politely first (`kill` sends TERM, which lets a server close its listener), then insist. Removing the pid file afterwards stops a later command from acting on a pid the system has since reused for something else.
72+
73+## Before you finish
74+
75+**Stop every job you started**, and **say which ones you left running** and why. A server still holding port 8080 after the turn is a surprise the user will hit later, when nothing on screen explains it.
76+
77+## Traps
78+
79+- **One shell per call.** Each `bash` call is a new shell in the same directory: a job started in one call is still running in the next, but shell variables are gone. That is exactly why the pid goes to a file and not to `$PID`.
80+- **The port is already in use.** A previous run left something behind. `lsof -i :8080` or `ss -lptn 'sport = :8080'` names the holder; stop that before starting again, rather than moving to another port and forgetting.
81+- **Nothing is interactive.** There is no stdin. A command that asks a question will hang until it is killed; pass the answer as a flag, or do not run it.
82+- **`nohup` writes `nohup.out`** in the working directory when you forget to redirect — if you see that file appear, a redirect is missing.
new file mode 100644
@@ -0,0 +1,82 @@
1+---
2+name: bg-jobs
3+description: Start, wait on, inspect and stop a long-running background job — a server, a watcher, a build that does not end — without blocking the turn.
4+keywords: background, job, server, serve, start, daemon, nohup, watch, tail, log, pid, kill, stop, port, running
5+---
6+
7+# Background jobs
8+
9+## When to use it
10+
11+Any command that **serves, watches, or runs until stopped**: an HTTP server, `npm run dev`, `go run` on a web app, a file watcher, a queue worker. Read this before you start one, and before you wait on, inspect or stop one.
12+
13+A command that never returns will hold the turn for its whole budget and then be killed. The answer the user asked for never arrives.
14+
15+## Start it
16+
17+Both streams redirected, the pid kept:
18+
19+```bash
20+nohup <command> > /tmp/<job>.log 2>&1 & echo $! > /tmp/<job>.pid
21+```
22+
23+Three parts, and all three matter:
24+
25+- **`> /tmp/<job>.log 2>&1`** — both streams. Redirecting only stdout is the classic mistake: the job keeps the tool's own error pipe open, and the call cannot finish until the job does. You get the 30-second budget spent on nothing.
26+- **`&`** — the shell returns at once.
27+- **`echo $! > /tmp/<job>.pid`** — without the pid you cannot stop it later except by guessing at `pkill` patterns, which also kills things you did not start.
28+
29+Use one name per job, and reuse it for the log and the pid file.
30+
31+## Wait for it to be ready
32+
33+**Do not `sleep` and hope.** Poll for the thing you actually need, with a bound:
34+
35+```bash
36+for i in $(seq 1 30); do
37+ curl -fsS localhost:8080/ >/dev/null 2>&1 && echo ready && break
38+ sleep 0.5
39+done
40+```
41+
42+For something that is not an HTTP server, poll the log for the line it prints when it is up:
43+
44+```bash
45+for i in $(seq 1 30); do
46+ grep -q "listening on" /tmp/<job>.log && echo ready && break
47+ sleep 0.5
48+done
49+```
50+
51+If the loop ends without `ready`, the job did not start — go read the log.
52+
53+## Inspect it
54+
55+```bash
56+tail -n 40 /tmp/<job>.log # what it said
57+kill -0 "$(cat /tmp/<job>.pid)" 2>/dev/null && echo alive || echo dead
58+```
59+
60+`kill -0` sends no signal; it only asks whether the process is there. A job that is `dead` right after starting almost always says why in the last lines of its log — read them before changing anything.
61+
62+## Stop it
63+
64+```bash
65+kill "$(cat /tmp/<job>.pid)" 2>/dev/null
66+sleep 0.5
67+kill -0 "$(cat /tmp/<job>.pid)" 2>/dev/null && kill -9 "$(cat /tmp/<job>.pid)"
68+rm -f /tmp/<job>.pid
69+```
70+
71+Ask politely first (`kill` sends TERM, which lets a server close its listener), then insist. Removing the pid file afterwards stops a later command from acting on a pid the system has since reused for something else.
72+
73+## Before you finish
74+
75+**Stop every job you started**, and **say which ones you left running** and why. A server still holding port 8080 after the turn is a surprise the user will hit later, when nothing on screen explains it.
76+
77+## Traps
78+
79+- **One shell per call.** Each `bash` call is a new shell in the same directory: a job started in one call is still running in the next, but shell variables are gone. That is exactly why the pid goes to a file and not to `$PID`.
80+- **The port is already in use.** A previous run left something behind. `lsof -i :8080` or `ss -lptn 'sport = :8080'` names the holder; stop that before starting again, rather than moving to another port and forgetting.
81+- **Nothing is interactive.** There is no stdin. A command that asks a question will hang until it is killed; pass the answer as a flag, or do not run it.
82+- **`nohup` writes `nohup.out`** in the working directory when you forget to redirect — if you see that file appear, a redirect is missing.
added mini-mes/gopher/skills/go-deps/SKILL.md +65 -0
new file mode 100644
@@ -0,0 +1,65 @@
1+---
2+name: go-deps
3+description: Add, upgrade, downgrade or remove a Go module dependency, tidy go.mod and go.sum, explain why a module is needed, and check for known vulnerabilities.
4+keywords: dépendance, dependency, go get, go mod tidy, upgrade, mise à jour, vulnérabilité, govulncheck
5+---
6+
7+# Manage Go dependencies
8+
9+## When to use it
10+
11+"Ajoute la lib X", "upgrade dependencies", "remove X", "why is X in go.sum?", "missing go.sum entry", "check vulnerabilities".
12+
13+## Before adding anything
14+
15+A dependency is code you now maintain. First check whether the standard library already does it (`slices`, `maps`, `log/slog`, `net/http` routing, `encoding/json`, `errors.Join`…) — say so if it does. If the user still wants the library, read its API before using it: `fetch_content` on `https://pkg.go.dev/<module-path>`.
16+
17+## Procedure
18+
19+Each command goes through your `bash` tool, from the module root.
20+
21+**Add** — import it in the code first, then:
22+
23+ go get <module-path>@latest && go mod tidy
24+
25+`@latest` resolves to a tagged version. Pin an exact one with `@v1.2.3`. Major versions ≥ 2 are part of the path: `github.com/x/y/v2`.
26+
27+**Upgrade one** dependency, or all direct and indirect ones within their major version:
28+
29+ go get <module-path>@latest && go mod tidy
30+ go get -u ./... && go mod tidy
31+
32+Show what changed afterwards with `git diff go.mod` (read-only, allowed). Upgrading everything at once makes a breakage hard to attribute: prefer one at a time when the user did not ask for "all".
33+
34+**Downgrade**: `go get <module-path>@v1.2.0 && go mod tidy`.
35+
36+**Remove**: delete the imports in the code, then `go mod tidy` — it drops what nothing imports. Do not edit go.mod by hand for that.
37+
38+**Why is it here?**
39+
40+ go mod why -m <module-path>
41+ go list -m all | grep <name>
42+
43+**List available upgrades**:
44+
45+ go list -u -m all | grep '\['
46+
47+**Vulnerabilities** — govulncheck reports only the ones your code actually reaches:
48+
49+ go run golang.org/x/vuln/cmd/govulncheck@latest ./...
50+
51+It downloads the tool and needs network access; if that fails, say so.
52+
53+**Tools used by the project** (generators, linters), Go ≥ 1.24: `go get -tool <module-path>/cmd/x@latest`, then run with `go tool x`. Before 1.24, call them with `go run <module-path>/cmd/x@version`.
54+
55+## After any change
56+
57+Follow `go-verify`: a new version can break the build or the tests. If it does and the fix is not obvious, revert that one dependency (`go get <module-path>@<previous-version>`) and report what broke.
58+
59+## Traps
60+
61+- `missing go.sum entry for module providing package`: `go mod tidy` fixes it.
62+- `go: updates to go.mod needed`: same.
63+- `module declares its path as X but was required as Y`: a fork or a renamed module — use the path it declares, or a `replace` directive only if the user asks for one.
64+- A `replace` pointing to a local directory (`=> ../x`) only works on this machine: never add one without saying so.
65+- `GOFLAGS=-mod=vendor` or a `vendor/` directory: after changing dependencies, run `go mod vendor` too.
new file mode 100644
@@ -0,0 +1,65 @@
1+---
2+name: go-deps
3+description: Add, upgrade, downgrade or remove a Go module dependency, tidy go.mod and go.sum, explain why a module is needed, and check for known vulnerabilities.
4+keywords: dépendance, dependency, go get, go mod tidy, upgrade, mise à jour, vulnérabilité, govulncheck
5+---
6+
7+# Manage Go dependencies
8+
9+## When to use it
10+
11+"Ajoute la lib X", "upgrade dependencies", "remove X", "why is X in go.sum?", "missing go.sum entry", "check vulnerabilities".
12+
13+## Before adding anything
14+
15+A dependency is code you now maintain. First check whether the standard library already does it (`slices`, `maps`, `log/slog`, `net/http` routing, `encoding/json`, `errors.Join`…) — say so if it does. If the user still wants the library, read its API before using it: `fetch_content` on `https://pkg.go.dev/<module-path>`.
16+
17+## Procedure
18+
19+Each command goes through your `bash` tool, from the module root.
20+
21+**Add** — import it in the code first, then:
22+
23+ go get <module-path>@latest && go mod tidy
24+
25+`@latest` resolves to a tagged version. Pin an exact one with `@v1.2.3`. Major versions ≥ 2 are part of the path: `github.com/x/y/v2`.
26+
27+**Upgrade one** dependency, or all direct and indirect ones within their major version:
28+
29+ go get <module-path>@latest && go mod tidy
30+ go get -u ./... && go mod tidy
31+
32+Show what changed afterwards with `git diff go.mod` (read-only, allowed). Upgrading everything at once makes a breakage hard to attribute: prefer one at a time when the user did not ask for "all".
33+
34+**Downgrade**: `go get <module-path>@v1.2.0 && go mod tidy`.
35+
36+**Remove**: delete the imports in the code, then `go mod tidy` — it drops what nothing imports. Do not edit go.mod by hand for that.
37+
38+**Why is it here?**
39+
40+ go mod why -m <module-path>
41+ go list -m all | grep <name>
42+
43+**List available upgrades**:
44+
45+ go list -u -m all | grep '\['
46+
47+**Vulnerabilities** — govulncheck reports only the ones your code actually reaches:
48+
49+ go run golang.org/x/vuln/cmd/govulncheck@latest ./...
50+
51+It downloads the tool and needs network access; if that fails, say so.
52+
53+**Tools used by the project** (generators, linters), Go ≥ 1.24: `go get -tool <module-path>/cmd/x@latest`, then run with `go tool x`. Before 1.24, call them with `go run <module-path>/cmd/x@version`.
54+
55+## After any change
56+
57+Follow `go-verify`: a new version can break the build or the tests. If it does and the fix is not obvious, revert that one dependency (`go get <module-path>@<previous-version>`) and report what broke.
58+
59+## Traps
60+
61+- `missing go.sum entry for module providing package`: `go mod tidy` fixes it.
62+- `go: updates to go.mod needed`: same.
63+- `module declares its path as X but was required as Y`: a fork or a renamed module — use the path it declares, or a `replace` directive only if the user asks for one.
64+- A `replace` pointing to a local directory (`=> ../x`) only works on this machine: never add one without saying so.
65+- `GOFLAGS=-mod=vendor` or a `vendor/` directory: after changing dependencies, run `go mod vendor` too.
added mini-mes/gopher/skills/go-fix/SKILL.md +54 -0
new file mode 100644
@@ -0,0 +1,54 @@
1+---
2+name: go-fix
3+description: Diagnose and fix a Go build error, a vet finding, a failing or flaky test, or a panic — reproduce it, read the code it points to, fix the cause, prove it.
4+keywords: erreur, error, bug, failing, échoue, panic, debug, flaky
5+---
6+
7+# Fix a failing Go build or test
8+
9+## When to use it
10+
11+`go build`, `go vet` or `go test` fails, a program panics, a test is flaky, or the user says "ça ne compile pas", "le test échoue", "fix this error".
12+
13+## Procedure
14+
15+1. **Reproduce it, narrowly.** Run the smallest command that shows the failure with your `bash` tool — one package, one test:
16+
17+ go test -run '^TestName$' -v ./path/to/pkg/
18+
19+ For a build error: `go build ./path/to/pkg/`. If you cannot reproduce it, say so and stop: do not fix what you have not seen fail.
20+
21+2. **Read the FIRST error only.** Go reports `file.go:LINE:COL: message`. Later errors are often consequences of the first. For a panic, read the stack from the top down to the first frame in this module's code — that is where to look, not the runtime frames.
22+
23+3. **Read the code it points to** with `read_file` (numbered=true), around that line. For a symbol you do not know, ask gopls: `lsp` `definition` or `hover`. For a library function, `go doc <pkg>.<Symbol>`.
24+
25+4. **Find the cause, then state it** in one sentence before editing: "nil map written in NewCache", "the test expects the old error text". If the test is right and the code wrong, fix the code. If the behaviour changed on purpose, fix the test — and say so.
26+
27+5. **Fix it with `edit_file`**, the smallest change that removes the cause. Never:
28+ - delete, skip (`t.Skip`) or weaken a test to make it pass;
29+ - add `//nolint`, `_ = err`, or a `recover()` to hide the symptom;
30+ - change several unrelated things at once.
31+
32+6. **Prove it.** Re-run the command from step 1: it must pass. Then follow the `go-verify` skill for the whole module, because a fix can break a neighbour.
33+
34+## Common causes
35+
36+| Message | Usual cause |
37+|---|---|
38+| `declared and not used` / `imported and not used` | Leftover variable or import — remove it (or use it, if the code is unfinished). |
39+| `undefined: X` | Wrong package qualifier, unexported name (lowercase) used from another package, or a file excluded by a build tag. |
40+| `cannot use x (variable of type A) as B value` | Pointer vs value, or a type that does not implement an interface: `hover` the method set. |
41+| `missing return` | A branch of a switch or if falls through without returning. |
42+| `assignment to entry in nil map` | A map declared but never `make`d. |
43+| `invalid memory address or nil pointer dereference` | A nil pointer or interface used — often an error ignored on the line before. |
44+| `all goroutines are asleep - deadlock!` | Send on an unbuffered channel with no receiver, or a WaitGroup that never reaches zero. |
45+| `DATA RACE` (with -race) | Shared variable written without a mutex or channel; the report names both goroutines. |
46+| `missing go.sum entry` | Run `go mod tidy` (see the `go-deps` skill). |
47+
48+## Flaky tests
49+
50+A test that passes and fails without code changes: run it many times to make it fail on demand, with your `bash` tool:
51+
52+ go test -run '^TestName$' -count=50 -race ./path/to/pkg/
53+
54+Usual causes: map iteration order, time (`time.Now`, sleeps), goroutine scheduling, shared global state between tests, `t.Parallel()` with a shared fixture. Fix the dependency on chance; never add a longer sleep.
new file mode 100644
@@ -0,0 +1,54 @@
1+---
2+name: go-fix
3+description: Diagnose and fix a Go build error, a vet finding, a failing or flaky test, or a panic — reproduce it, read the code it points to, fix the cause, prove it.
4+keywords: erreur, error, bug, failing, échoue, panic, debug, flaky
5+---
6+
7+# Fix a failing Go build or test
8+
9+## When to use it
10+
11+`go build`, `go vet` or `go test` fails, a program panics, a test is flaky, or the user says "ça ne compile pas", "le test échoue", "fix this error".
12+
13+## Procedure
14+
15+1. **Reproduce it, narrowly.** Run the smallest command that shows the failure with your `bash` tool — one package, one test:
16+
17+ go test -run '^TestName$' -v ./path/to/pkg/
18+
19+ For a build error: `go build ./path/to/pkg/`. If you cannot reproduce it, say so and stop: do not fix what you have not seen fail.
20+
21+2. **Read the FIRST error only.** Go reports `file.go:LINE:COL: message`. Later errors are often consequences of the first. For a panic, read the stack from the top down to the first frame in this module's code — that is where to look, not the runtime frames.
22+
23+3. **Read the code it points to** with `read_file` (numbered=true), around that line. For a symbol you do not know, ask gopls: `lsp` `definition` or `hover`. For a library function, `go doc <pkg>.<Symbol>`.
24+
25+4. **Find the cause, then state it** in one sentence before editing: "nil map written in NewCache", "the test expects the old error text". If the test is right and the code wrong, fix the code. If the behaviour changed on purpose, fix the test — and say so.
26+
27+5. **Fix it with `edit_file`**, the smallest change that removes the cause. Never:
28+ - delete, skip (`t.Skip`) or weaken a test to make it pass;
29+ - add `//nolint`, `_ = err`, or a `recover()` to hide the symptom;
30+ - change several unrelated things at once.
31+
32+6. **Prove it.** Re-run the command from step 1: it must pass. Then follow the `go-verify` skill for the whole module, because a fix can break a neighbour.
33+
34+## Common causes
35+
36+| Message | Usual cause |
37+|---|---|
38+| `declared and not used` / `imported and not used` | Leftover variable or import — remove it (or use it, if the code is unfinished). |
39+| `undefined: X` | Wrong package qualifier, unexported name (lowercase) used from another package, or a file excluded by a build tag. |
40+| `cannot use x (variable of type A) as B value` | Pointer vs value, or a type that does not implement an interface: `hover` the method set. |
41+| `missing return` | A branch of a switch or if falls through without returning. |
42+| `assignment to entry in nil map` | A map declared but never `make`d. |
43+| `invalid memory address or nil pointer dereference` | A nil pointer or interface used — often an error ignored on the line before. |
44+| `all goroutines are asleep - deadlock!` | Send on an unbuffered channel with no receiver, or a WaitGroup that never reaches zero. |
45+| `DATA RACE` (with -race) | Shared variable written without a mutex or channel; the report names both goroutines. |
46+| `missing go.sum entry` | Run `go mod tidy` (see the `go-deps` skill). |
47+
48+## Flaky tests
49+
50+A test that passes and fails without code changes: run it many times to make it fail on demand, with your `bash` tool:
51+
52+ go test -run '^TestName$' -count=50 -race ./path/to/pkg/
53+
54+Usual causes: map iteration order, time (`time.Now`, sleeps), goroutine scheduling, shared global state between tests, `t.Parallel()` with a shared fixture. Fix the dependency on chance; never add a longer sleep.
added mini-mes/gopher/skills/go-new-project/SKILL.md +56 -0
new file mode 100644
@@ -0,0 +1,56 @@
1+---
2+name: go-new-project
3+description: Start a new Go module — a command-line tool, a web service or a library — with go.mod, a minimal standard layout, a first test, and a Makefile-free way to build and run it.
4+keywords: nouveau projet, new project, init, module, scaffold, créer, CLI, layout
5+---
6+
7+# Start a new Go project
8+
9+## When to use it
10+
11+"Crée un projet Go", "new CLI", "init a module", "scaffold a service". Not for adding a package to an existing module — just create the directory there.
12+
13+## Procedure
14+
15+1. **Ask nothing you can decide.** If the user gave no module path, use `github.com/<user>/<name>` only if they named an account, otherwise just `<name>`. Say which one you chose.
16+
17+2. **Check the toolchain** with your `bash` tool:
18+
19+ go version
20+
21+ The `go` line of go.mod will be that version: do not invent one.
22+
23+3. **Create the module**, in a new directory (never in a non-empty one without asking):
24+
25+ mkdir -p <name> && cd <name> && go mod init <module-path>
26+
27+ Each bash call is a new shell: later commands start with `cd <name> &&`.
28+
29+4. **Lay out the smallest structure that fits** — no empty directories "for later":
30+
31+ | Kind | Layout |
32+ |---|---|
33+ | CLI / single program | `main.go` at the root (package main), logic in `internal/<pkg>/` once it grows past one file. |
34+ | Several binaries | `cmd/<binary>/main.go` each, shared code in `internal/`. |
35+ | Library | `<name>.go` at the root, package named after the last element of the module path, `example_test.go` for usage. |
36+ | Web service | `main.go` (flags, wiring, `http.Server` with timeouts, graceful shutdown on SIGINT/SIGTERM via `signal.NotifyContext`), handlers in `internal/server/`. Standard `net/http` routing (`mux.HandleFunc("GET /items/{id}", …)`, Go ≥ 1.22) before any framework. |
37+
38+ Do not create `pkg/`, `utils/`, `common/` or `models/` packages: name packages after what they provide.
39+
40+5. **Write a first test** for the first real function (see `go-test-writing`), so `go test ./...` means something from day one.
41+
42+6. **Add a .gitignore** with the binary name and `.mm/` (mm's sessions). Do not run `git init` unless asked.
43+
44+7. **Verify**: follow `go-verify` (gofmt, build, vet, test), then run it once with your `bash` tool:
45+
46+ cd <name> && go run .
47+
48+ A server goes to the background instead (read the `bg-jobs` skill first) and is stopped before you finish.
49+
50+8. **Report**: the tree (`find <name> -type f -not -path '*/.git/*'`), the module path, and the commands to build (`go build -o bin/<name> .`), test and run.
51+
52+## Defaults worth keeping
53+
54+- `log/slog` for logs, `flag` for flags — standard library until it hurts.
55+- Configuration from flags and environment, read in `main`, passed down as values — no global config.
56+- `main` stays small: parse, build, run, exit code. The logic lives in a package that tests can import.
new file mode 100644
@@ -0,0 +1,56 @@
1+---
2+name: go-new-project
3+description: Start a new Go module — a command-line tool, a web service or a library — with go.mod, a minimal standard layout, a first test, and a Makefile-free way to build and run it.
4+keywords: nouveau projet, new project, init, module, scaffold, créer, CLI, layout
5+---
6+
7+# Start a new Go project
8+
9+## When to use it
10+
11+"Crée un projet Go", "new CLI", "init a module", "scaffold a service". Not for adding a package to an existing module — just create the directory there.
12+
13+## Procedure
14+
15+1. **Ask nothing you can decide.** If the user gave no module path, use `github.com/<user>/<name>` only if they named an account, otherwise just `<name>`. Say which one you chose.
16+
17+2. **Check the toolchain** with your `bash` tool:
18+
19+ go version
20+
21+ The `go` line of go.mod will be that version: do not invent one.
22+
23+3. **Create the module**, in a new directory (never in a non-empty one without asking):
24+
25+ mkdir -p <name> && cd <name> && go mod init <module-path>
26+
27+ Each bash call is a new shell: later commands start with `cd <name> &&`.
28+
29+4. **Lay out the smallest structure that fits** — no empty directories "for later":
30+
31+ | Kind | Layout |
32+ |---|---|
33+ | CLI / single program | `main.go` at the root (package main), logic in `internal/<pkg>/` once it grows past one file. |
34+ | Several binaries | `cmd/<binary>/main.go` each, shared code in `internal/`. |
35+ | Library | `<name>.go` at the root, package named after the last element of the module path, `example_test.go` for usage. |
36+ | Web service | `main.go` (flags, wiring, `http.Server` with timeouts, graceful shutdown on SIGINT/SIGTERM via `signal.NotifyContext`), handlers in `internal/server/`. Standard `net/http` routing (`mux.HandleFunc("GET /items/{id}", …)`, Go ≥ 1.22) before any framework. |
37+
38+ Do not create `pkg/`, `utils/`, `common/` or `models/` packages: name packages after what they provide.
39+
40+5. **Write a first test** for the first real function (see `go-test-writing`), so `go test ./...` means something from day one.
41+
42+6. **Add a .gitignore** with the binary name and `.mm/` (mm's sessions). Do not run `git init` unless asked.
43+
44+7. **Verify**: follow `go-verify` (gofmt, build, vet, test), then run it once with your `bash` tool:
45+
46+ cd <name> && go run .
47+
48+ A server goes to the background instead (read the `bg-jobs` skill first) and is stopped before you finish.
49+
50+8. **Report**: the tree (`find <name> -type f -not -path '*/.git/*'`), the module path, and the commands to build (`go build -o bin/<name> .`), test and run.
51+
52+## Defaults worth keeping
53+
54+- `log/slog` for logs, `flag` for flags — standard library until it hurts.
55+- Configuration from flags and environment, read in `main`, passed down as values — no global config.
56+- `main` stays small: parse, build, run, exit code. The logic lives in a package that tests can import.
added mini-mes/gopher/skills/go-review/SKILL.md +60 -0
new file mode 100644
@@ -0,0 +1,60 @@
1+---
2+name: go-review
3+description: Review Go code — a file, a package, or the uncommitted diff — for bugs, error handling, concurrency, API design and idiomatic style, and report findings ranked by severity.
4+keywords: revue, review, relire, audit, idiomatique, idiomatic, refactor, améliorer
5+---
6+
7+# Review Go code
8+
9+## When to use it
10+
11+"Relis ce code", "review my changes", "is this idiomatic?", "what can be improved?". A review reports; it changes nothing unless the user then asks for the fixes.
12+
13+## Procedure
14+
15+1. **Find the scope.** The uncommitted changes, with your `bash` tool:
16+
17+ git diff --stat && git diff
18+
19+ or the files / package the user named. Read each file with `read_file`; for every symbol whose use you need to judge, `lsp` `references`.
20+
21+2. **Let the tools speak first**: `go vet ./...`, and `staticcheck ./...` only if `command -v staticcheck` finds it. Their findings go in the report as they are.
22+
23+3. **Read for the points below, in this order** — correctness before style.
24+
25+4. **Report** findings ranked: 🔴 bug (wrong result, crash, race, leak), 🟠 risk (error lost, missing timeout, fragile API), 🟡 style/idiom. For each: `file.go:LINE`, the problem in one sentence, the fix in one sentence or a short snippet. Say explicitly when you found nothing in a category. No praise padding, no restating the code.
26+
27+## Checklist
28+
29+**Correctness**
30+- Every error checked; none dropped with `_` without a comment saying why.
31+- Errors wrapped with `%w` when the caller may inspect them; `errors.Is/As`, not string comparison.
32+- `defer` in a loop (files, locks held until the function returns); `defer f.Close()` on a file opened for writing loses the Close error.
33+- Loop variables captured by closures are fine since Go 1.22 — check the `go` line before flagging it.
34+- Nil maps written to; nil interfaces holding a nil pointer (`err != nil` but the value is nil).
35+- Slices aliased after `append` (two slices sharing one backing array).
36+- Integer overflow and conversion (`int(int64)` on 32-bit, `len` vs byte/rune counts on strings).
37+
38+**Concurrency**
39+- Each goroutine: who stops it, and how (context, closed channel)? A goroutine blocked forever on a send is a leak.
40+- Shared state protected by one mutex, or owned by one goroutine. `sync.WaitGroup.Add` before `go`, not inside it.
41+- Channels closed by the sender only, once.
42+- `context.Context` passed down, first parameter, never stored in a struct; `ctx.Done()` honoured in long loops.
43+- Network calls with a timeout: `http.Client{Timeout: …}` or a context deadline — `http.DefaultClient` has none.
44+
45+**API and design**
46+- Exported names documented with a comment starting with the name.
47+- Accept interfaces, return concrete types; interfaces small and defined by the consumer.
48+- No package names like `util`, `common`, `helpers`; no stutter (`user.UserService` → `user.Service`).
49+- Constructors return usable values; zero values useful where possible.
50+- No global mutable state; configuration passed in.
51+
52+**Idiom and readability**
53+- Early returns, happy path unindented; no `else` after a `return`.
54+- `MixedCaps`, initialisms upper-case (`ID`, `URL`, `HTTP`), short receiver names, consistent across methods.
55+- Standard library used where it exists (`slices`, `maps`, `strings.Cut`, `min`/`max` builtins since 1.21).
56+- `fmt.Sprintf` in hot paths, `+` in loops for strings (use `strings.Builder`).
57+
58+**Tests**
59+- Does the change come with tests? Do they test behaviour, and fail without the change?
60+- Table-driven where several cases exist; `t.Helper()` in helpers; no `time.Sleep` for synchronisation.
new file mode 100644
@@ -0,0 +1,60 @@
1+---
2+name: go-review
3+description: Review Go code — a file, a package, or the uncommitted diff — for bugs, error handling, concurrency, API design and idiomatic style, and report findings ranked by severity.
4+keywords: revue, review, relire, audit, idiomatique, idiomatic, refactor, améliorer
5+---
6+
7+# Review Go code
8+
9+## When to use it
10+
11+"Relis ce code", "review my changes", "is this idiomatic?", "what can be improved?". A review reports; it changes nothing unless the user then asks for the fixes.
12+
13+## Procedure
14+
15+1. **Find the scope.** The uncommitted changes, with your `bash` tool:
16+
17+ git diff --stat && git diff
18+
19+ or the files / package the user named. Read each file with `read_file`; for every symbol whose use you need to judge, `lsp` `references`.
20+
21+2. **Let the tools speak first**: `go vet ./...`, and `staticcheck ./...` only if `command -v staticcheck` finds it. Their findings go in the report as they are.
22+
23+3. **Read for the points below, in this order** — correctness before style.
24+
25+4. **Report** findings ranked: 🔴 bug (wrong result, crash, race, leak), 🟠 risk (error lost, missing timeout, fragile API), 🟡 style/idiom. For each: `file.go:LINE`, the problem in one sentence, the fix in one sentence or a short snippet. Say explicitly when you found nothing in a category. No praise padding, no restating the code.
26+
27+## Checklist
28+
29+**Correctness**
30+- Every error checked; none dropped with `_` without a comment saying why.
31+- Errors wrapped with `%w` when the caller may inspect them; `errors.Is/As`, not string comparison.
32+- `defer` in a loop (files, locks held until the function returns); `defer f.Close()` on a file opened for writing loses the Close error.
33+- Loop variables captured by closures are fine since Go 1.22 — check the `go` line before flagging it.
34+- Nil maps written to; nil interfaces holding a nil pointer (`err != nil` but the value is nil).
35+- Slices aliased after `append` (two slices sharing one backing array).
36+- Integer overflow and conversion (`int(int64)` on 32-bit, `len` vs byte/rune counts on strings).
37+
38+**Concurrency**
39+- Each goroutine: who stops it, and how (context, closed channel)? A goroutine blocked forever on a send is a leak.
40+- Shared state protected by one mutex, or owned by one goroutine. `sync.WaitGroup.Add` before `go`, not inside it.
41+- Channels closed by the sender only, once.
42+- `context.Context` passed down, first parameter, never stored in a struct; `ctx.Done()` honoured in long loops.
43+- Network calls with a timeout: `http.Client{Timeout: …}` or a context deadline — `http.DefaultClient` has none.
44+
45+**API and design**
46+- Exported names documented with a comment starting with the name.
47+- Accept interfaces, return concrete types; interfaces small and defined by the consumer.
48+- No package names like `util`, `common`, `helpers`; no stutter (`user.UserService` → `user.Service`).
49+- Constructors return usable values; zero values useful where possible.
50+- No global mutable state; configuration passed in.
51+
52+**Idiom and readability**
53+- Early returns, happy path unindented; no `else` after a `return`.
54+- `MixedCaps`, initialisms upper-case (`ID`, `URL`, `HTTP`), short receiver names, consistent across methods.
55+- Standard library used where it exists (`slices`, `maps`, `strings.Cut`, `min`/`max` builtins since 1.21).
56+- `fmt.Sprintf` in hot paths, `+` in loops for strings (use `strings.Builder`).
57+
58+**Tests**
59+- Does the change come with tests? Do they test behaviour, and fail without the change?
60+- Table-driven where several cases exist; `t.Helper()` in helpers; no `time.Sleep` for synchronisation.
added mini-mes/gopher/skills/go-test-writing/SKILL.md +93 -0
new file mode 100644
@@ -0,0 +1,93 @@
1+---
2+name: go-test-writing
3+description: Write or extend Go tests — table-driven unit tests, subtests, helpers, test fixtures, fuzz tests, benchmarks, examples — and measure coverage.
4+keywords: tests, tester, unit test, table-driven, coverage, couverture, fuzz, benchmark
5+---
6+
7+# Write Go tests
8+
9+## When to use it
10+
11+The user asks for tests ("ajoute des tests", "write a test for", "improve coverage"), or a fix needs a test that fails before it and passes after.
12+
13+## Procedure
14+
15+1. **Read the code under test** with `read_file`, and the existing `_test.go` files of the package: reuse their style, helpers and package name (`package foo` for white-box tests, `package foo_test` for tests through the exported API only).
16+2. **List the cases before writing**: the normal case, the edges (empty, zero, nil, one element, maximum), and each error path. Say the list in one line.
17+3. **Write the test** — `edit_file` to extend an existing file, `write_file` for a new `<file>_test.go` next to the code.
18+4. **Run it alone** with your `bash` tool:
19+
20+ go test -run '^TestName$' -v ./path/to/pkg/
21+
22+5. **Make it fail once** when it covers a fix: it must fail without the fix, otherwise it tests nothing. Then follow `go-verify`.
23+
24+## The default shape: table-driven
25+
26+```go
27+func TestParseSize(t *testing.T) {
28+ tests := []struct {
29+ name string
30+ in string
31+ want int64
32+ wantErr bool
33+ }{
34+ {name: "bytes", in: "512", want: 512},
35+ {name: "kilobytes", in: "2K", want: 2048},
36+ {name: "empty", in: "", wantErr: true},
37+ }
38+ for _, tt := range tests {
39+ t.Run(tt.name, func(t *testing.T) {
40+ got, err := ParseSize(tt.in)
41+ if (err != nil) != tt.wantErr {
42+ t.Fatalf("ParseSize(%q) error = %v, wantErr %v", tt.in, err, tt.wantErr)
43+ }
44+ if got != tt.want {
45+ t.Errorf("ParseSize(%q) = %d, want %d", tt.in, got, tt.want)
46+ }
47+ })
48+ }
49+}
50+```
51+
52+- Failure messages say `Func(input) = got, want want` — readable without the source.
53+- `t.Fatalf` when the rest of the test cannot continue, `t.Errorf` otherwise.
54+- Compare structs and slices with `reflect.DeepEqual`, or `github.com/google/go-cmp/cmp` **only if the module already depends on it**.
55+- Check an error's identity with `errors.Is(err, ErrX)`, not its text.
56+
57+## Building blocks
58+
59+- **Helpers** call `t.Helper()` first, so failures point at the caller.
60+- **Temporary files**: `t.TempDir()` (removed automatically). **Fixtures**: files under `testdata/`, which the go tool ignores.
61+- **Cleanup**: `t.Cleanup(func() { … })` rather than `defer` in helpers.
62+- **Environment**: `t.Setenv("KEY", "v")` — restored after the test (not usable with `t.Parallel()`).
63+- **HTTP**: `httptest.NewServer` for a client, `httptest.NewRecorder` for a handler.
64+- **Time and randomness**: inject them (a `now func() time.Time` field) instead of sleeping.
65+- **Context**: `t.Context()` exists since Go 1.24; before that, `context.WithCancel(context.Background())` + `t.Cleanup(cancel)`. Check the `go` line of go.mod.
66+
67+## Fuzz tests (Go ≥ 1.18)
68+
69+For parsers and decoders. Seeds with `f.Add`, a property in `f.Fuzz`:
70+
71+```go
72+func FuzzParseSize(f *testing.F) {
73+ f.Add("2K")
74+ f.Fuzz(func(t *testing.T, in string) {
75+ n, err := ParseSize(in)
76+ if err == nil && n < 0 {
77+ t.Errorf("ParseSize(%q) = %d, negative", in, n)
78+ }
79+ })
80+}
81+```
82+
83+Run it for a bounded time — never without `-fuzztime`, it would run until the bash timeout kills it: `go test -run '^$' -fuzz '^FuzzParseSize$' -fuzztime 30s ./path/to/pkg/`. A failure writes the input under `testdata/fuzz/`: keep that file, it is now a regression test.
84+
85+## Benchmarks
86+
87+Only when asked about performance. `b.Loop()` exists since Go 1.24; before, `for i := 0; i < b.N; i++`. Run with `go test -run '^$' -bench '^BenchmarkX$' -benchmem ./path/to/pkg/`, and compare before/after on the same machine.
88+
89+## Coverage
90+
91+ go test -cover ./...
92+
93+For the uncovered lines of one package: `go test -coverprofile=/tmp/cover.out ./path/to/pkg/ && go tool cover -func=/tmp/cover.out`. Coverage shows what is not tested; it is not a goal by itself — test behaviour, not lines.
new file mode 100644
@@ -0,0 +1,93 @@
1+---
2+name: go-test-writing
3+description: Write or extend Go tests — table-driven unit tests, subtests, helpers, test fixtures, fuzz tests, benchmarks, examples — and measure coverage.
4+keywords: tests, tester, unit test, table-driven, coverage, couverture, fuzz, benchmark
5+---
6+
7+# Write Go tests
8+
9+## When to use it
10+
11+The user asks for tests ("ajoute des tests", "write a test for", "improve coverage"), or a fix needs a test that fails before it and passes after.
12+
13+## Procedure
14+
15+1. **Read the code under test** with `read_file`, and the existing `_test.go` files of the package: reuse their style, helpers and package name (`package foo` for white-box tests, `package foo_test` for tests through the exported API only).
16+2. **List the cases before writing**: the normal case, the edges (empty, zero, nil, one element, maximum), and each error path. Say the list in one line.
17+3. **Write the test** — `edit_file` to extend an existing file, `write_file` for a new `<file>_test.go` next to the code.
18+4. **Run it alone** with your `bash` tool:
19+
20+ go test -run '^TestName$' -v ./path/to/pkg/
21+
22+5. **Make it fail once** when it covers a fix: it must fail without the fix, otherwise it tests nothing. Then follow `go-verify`.
23+
24+## The default shape: table-driven
25+
26+```go
27+func TestParseSize(t *testing.T) {
28+ tests := []struct {
29+ name string
30+ in string
31+ want int64
32+ wantErr bool
33+ }{
34+ {name: "bytes", in: "512", want: 512},
35+ {name: "kilobytes", in: "2K", want: 2048},
36+ {name: "empty", in: "", wantErr: true},
37+ }
38+ for _, tt := range tests {
39+ t.Run(tt.name, func(t *testing.T) {
40+ got, err := ParseSize(tt.in)
41+ if (err != nil) != tt.wantErr {
42+ t.Fatalf("ParseSize(%q) error = %v, wantErr %v", tt.in, err, tt.wantErr)
43+ }
44+ if got != tt.want {
45+ t.Errorf("ParseSize(%q) = %d, want %d", tt.in, got, tt.want)
46+ }
47+ })
48+ }
49+}
50+```
51+
52+- Failure messages say `Func(input) = got, want want` — readable without the source.
53+- `t.Fatalf` when the rest of the test cannot continue, `t.Errorf` otherwise.
54+- Compare structs and slices with `reflect.DeepEqual`, or `github.com/google/go-cmp/cmp` **only if the module already depends on it**.
55+- Check an error's identity with `errors.Is(err, ErrX)`, not its text.
56+
57+## Building blocks
58+
59+- **Helpers** call `t.Helper()` first, so failures point at the caller.
60+- **Temporary files**: `t.TempDir()` (removed automatically). **Fixtures**: files under `testdata/`, which the go tool ignores.
61+- **Cleanup**: `t.Cleanup(func() { … })` rather than `defer` in helpers.
62+- **Environment**: `t.Setenv("KEY", "v")` — restored after the test (not usable with `t.Parallel()`).
63+- **HTTP**: `httptest.NewServer` for a client, `httptest.NewRecorder` for a handler.
64+- **Time and randomness**: inject them (a `now func() time.Time` field) instead of sleeping.
65+- **Context**: `t.Context()` exists since Go 1.24; before that, `context.WithCancel(context.Background())` + `t.Cleanup(cancel)`. Check the `go` line of go.mod.
66+
67+## Fuzz tests (Go ≥ 1.18)
68+
69+For parsers and decoders. Seeds with `f.Add`, a property in `f.Fuzz`:
70+
71+```go
72+func FuzzParseSize(f *testing.F) {
73+ f.Add("2K")
74+ f.Fuzz(func(t *testing.T, in string) {
75+ n, err := ParseSize(in)
76+ if err == nil && n < 0 {
77+ t.Errorf("ParseSize(%q) = %d, negative", in, n)
78+ }
79+ })
80+}
81+```
82+
83+Run it for a bounded time — never without `-fuzztime`, it would run until the bash timeout kills it: `go test -run '^$' -fuzz '^FuzzParseSize$' -fuzztime 30s ./path/to/pkg/`. A failure writes the input under `testdata/fuzz/`: keep that file, it is now a regression test.
84+
85+## Benchmarks
86+
87+Only when asked about performance. `b.Loop()` exists since Go 1.24; before, `for i := 0; i < b.N; i++`. Run with `go test -run '^$' -bench '^BenchmarkX$' -benchmem ./path/to/pkg/`, and compare before/after on the same machine.
88+
89+## Coverage
90+
91+ go test -cover ./...
92+
93+For the uncovered lines of one package: `go test -coverprofile=/tmp/cover.out ./path/to/pkg/ && go tool cover -func=/tmp/cover.out`. Coverage shows what is not tested; it is not a goal by itself — test behaviour, not lines.
added mini-mes/gopher/skills/go-verify/SKILL.md +59 -0
new file mode 100644
@@ -0,0 +1,59 @@
1+---
2+name: go-verify
3+description: Check that Go code is correct after a change, or when asked whether it builds, passes its tests, or is clean — format, vet, build, test, from the narrowest package to the whole module.
4+keywords: vérifier, check, compile, lint, gofmt, vet, staticcheck, CI
5+---
6+
7+# Verify Go code
8+
9+## When to use it
10+
11+After every change to Go code, and whenever the user asks "does it build?", "do the tests pass?", "is it clean?", "vérifie". A change is finished when this procedure passes, not when the edit is written.
12+
13+## Procedure
14+
15+Run each step with your `bash` tool, in this order. Stop at the first step that fails, fix it (the `go-fix` skill), and start again from step 1.
16+
17+1. **Formatting.** Call your `bash` tool with this command:
18+
19+ gofmt -l .
20+
21+ No output = formatted. Any file listed is not: run `gofmt -w <file>` on exactly those files, then go on.
22+
23+2. **Build**, every package, test files included (`go vet` compiles them; `go build` alone does not):
24+
25+ go build ./... && go vet ./...
26+
27+ `go vet` reports real bugs (wrong Printf verbs, copied locks, unreachable code, bad struct tags). Fix every finding; never silence one.
28+
29+3. **Tests of the package you changed first** — fast feedback:
30+
31+ go test ./path/to/pkg/
32+
33+ Then **the whole module**:
34+
35+ go test ./...
36+
37+4. **Race detector**, when the change touches goroutines, channels, sync, or shared state:
38+
39+ go test -race ./path/to/pkg/
40+
41+ It needs cgo; if it answers `-race requires cgo`, say so and skip it.
42+
43+5. **Extra linters, only if installed.** Check first, run only what exists:
44+
45+ command -v staticcheck && staticcheck ./...
46+ command -v golangci-lint && golangci-lint run ./...
47+
48+ If neither exists, do not install anything: say they were skipped.
49+
50+## Reporting
51+
52+Answer with one line per step: the command and its result (`ok`, or the first error). Quote the tool output; never write "tests pass" without a `go test` output in this answer that says `ok`.
53+
54+## Traps
55+
56+- `go test ./...` from a directory that is not inside the module answers `pattern ./...: directory prefix . does not contain main module` — run `go env GOMOD` to find the module root.
57+- `no Go files in` for a package directory: it holds only `_test.go` or build-tagged files. Not an error to fix.
58+- Cached results print `(cached)`: they are still valid. Use `-count=1` only when the test reads files, the network or the clock.
59+- A test that hangs is killed by the bash timeout. Re-run it alone with `-timeout 60s -v -run '^TestName$'` to see where it stops.
new file mode 100644
@@ -0,0 +1,59 @@
1+---
2+name: go-verify
3+description: Check that Go code is correct after a change, or when asked whether it builds, passes its tests, or is clean — format, vet, build, test, from the narrowest package to the whole module.
4+keywords: vérifier, check, compile, lint, gofmt, vet, staticcheck, CI
5+---
6+
7+# Verify Go code
8+
9+## When to use it
10+
11+After every change to Go code, and whenever the user asks "does it build?", "do the tests pass?", "is it clean?", "vérifie". A change is finished when this procedure passes, not when the edit is written.
12+
13+## Procedure
14+
15+Run each step with your `bash` tool, in this order. Stop at the first step that fails, fix it (the `go-fix` skill), and start again from step 1.
16+
17+1. **Formatting.** Call your `bash` tool with this command:
18+
19+ gofmt -l .
20+
21+ No output = formatted. Any file listed is not: run `gofmt -w <file>` on exactly those files, then go on.
22+
23+2. **Build**, every package, test files included (`go vet` compiles them; `go build` alone does not):
24+
25+ go build ./... && go vet ./...
26+
27+ `go vet` reports real bugs (wrong Printf verbs, copied locks, unreachable code, bad struct tags). Fix every finding; never silence one.
28+
29+3. **Tests of the package you changed first** — fast feedback:
30+
31+ go test ./path/to/pkg/
32+
33+ Then **the whole module**:
34+
35+ go test ./...
36+
37+4. **Race detector**, when the change touches goroutines, channels, sync, or shared state:
38+
39+ go test -race ./path/to/pkg/
40+
41+ It needs cgo; if it answers `-race requires cgo`, say so and skip it.
42+
43+5. **Extra linters, only if installed.** Check first, run only what exists:
44+
45+ command -v staticcheck && staticcheck ./...
46+ command -v golangci-lint && golangci-lint run ./...
47+
48+ If neither exists, do not install anything: say they were skipped.
49+
50+## Reporting
51+
52+Answer with one line per step: the command and its result (`ok`, or the first error). Quote the tool output; never write "tests pass" without a `go test` output in this answer that says `ok`.
53+
54+## Traps
55+
56+- `go test ./...` from a directory that is not inside the module answers `pattern ./...: directory prefix . does not contain main module` — run `go env GOMOD` to find the module root.
57+- `no Go files in` for a package directory: it holds only `_test.go` or build-tagged files. Not an error to fix.
58+- Cached results print `(cached)`: they are still valid. Use `-count=1` only when the test reads files, the network or the clock.
59+- A test that hangs is killed by the bash timeout. Re-run it alone with `-timeout 60s -v -run '^TestName$'` to see where it stops.
added mini-mes/gopher/skills/lsp-navigation/SKILL.md +45 -0
new file mode 100644
@@ -0,0 +1,45 @@
1+---
2+name: lsp-navigation
3+description: Navigate and change code with the `lsp` tool — find where a symbol is defined, who uses it, what its type is, what the compiler reports, and rename it everywhere.
4+keywords: lsp, definition, references, usages, callers, hover, type, signature, symbols, outline, diagnostics, errors, warnings, rename, refactor, language server
5+---
6+
7+# Navigate code with the `lsp` tool
8+
9+## When to use it
10+
11+The `lsp` tool asks the project's language server what the compiler knows. Prefer it to `grep` and to reading whole files when the question is about **symbols**: where something is declared, who uses it, what type it has, what is wrong in a file, or how to rename it safely. Its description lists the servers available and the file extensions they cover; for other files, fall back to `bash` and `read_file`.
12+
13+## How to point at a symbol
14+
15+Give the **identifier** as written in the code, in `symbol`: the tool finds its first occurrence in the file. Add `line` (1-based) when the same name appears several times and you want a particular one. This is the reliable way; never guess a column.
16+
17+Only when you have an exact position — from `read_file` with `numbered=true` — may you send `line` and `column` instead (both 1-based, the column pointing inside the identifier).
18+
19+## The actions
20+
21+| You want to know… | Call |
22+| --- | --- |
23+| Where a symbol is declared | `{"action":"definition","path":"main.go","symbol":"hello"}` |
24+| Every place that uses it | `{"action":"references","path":"main.go","symbol":"hello"}` |
25+| Its signature, type and documentation | `{"action":"hover","path":"main.go","symbol":"hello"}` |
26+| What a file contains (outline) | `{"action":"symbols","path":"main.go"}` |
27+| What the compiler reports in a file | `{"action":"diagnostics","path":"main.go"}` |
28+| Rename it everywhere, files rewritten | `{"action":"rename","path":"main.go","symbol":"hello","new_name":"greet"}` |
29+| The occurrence on one line only | add `"line": 9` to any of the calls above |
30+
31+Answers come as `path:line:column <source line>`, one per location. You rarely need to open the file afterwards.
32+
33+## Procedure for a change
34+
35+1. `symbols` on the file to find the symbol, or `read_file numbered=true` if you already know roughly where it is.
36+2. `references` on the symbol to see every file the change touches. Say how many there are.
37+3. Edit with `edit_file` (or `rename` when the change is a rename — it rewrites all the files at once).
38+4. `diagnostics` on each edited file to see what the compiler reports, then fix what it says.
39+5. Only then run the tests with `bash`.
40+
41+## Rules
42+
43+- A `[lsp: …]` answer is information, not a crash: read it. "no language server for" means the extension is not covered — use `bash`. "not found in" means the identifier is not spelled as in the code — read the file and copy it. "past the end of line" means you miscounted — use `symbol` instead.
44+- `diagnostics` right after an edit may say "as last published" or "no diagnostics received": the server is still indexing. Ask again once.
45+- `rename` writes files. It NEEDS `new_name`, the new identifier; without it the tool answers with the exact call to make — make it, do not fall back to `edit_file`. Say what it changed, and never rename to a name the file already uses for something else.
new file mode 100644
@@ -0,0 +1,45 @@
1+---
2+name: lsp-navigation
3+description: Navigate and change code with the `lsp` tool — find where a symbol is defined, who uses it, what its type is, what the compiler reports, and rename it everywhere.
4+keywords: lsp, definition, references, usages, callers, hover, type, signature, symbols, outline, diagnostics, errors, warnings, rename, refactor, language server
5+---
6+
7+# Navigate code with the `lsp` tool
8+
9+## When to use it
10+
11+The `lsp` tool asks the project's language server what the compiler knows. Prefer it to `grep` and to reading whole files when the question is about **symbols**: where something is declared, who uses it, what type it has, what is wrong in a file, or how to rename it safely. Its description lists the servers available and the file extensions they cover; for other files, fall back to `bash` and `read_file`.
12+
13+## How to point at a symbol
14+
15+Give the **identifier** as written in the code, in `symbol`: the tool finds its first occurrence in the file. Add `line` (1-based) when the same name appears several times and you want a particular one. This is the reliable way; never guess a column.
16+
17+Only when you have an exact position — from `read_file` with `numbered=true` — may you send `line` and `column` instead (both 1-based, the column pointing inside the identifier).
18+
19+## The actions
20+
21+| You want to know… | Call |
22+| --- | --- |
23+| Where a symbol is declared | `{"action":"definition","path":"main.go","symbol":"hello"}` |
24+| Every place that uses it | `{"action":"references","path":"main.go","symbol":"hello"}` |
25+| Its signature, type and documentation | `{"action":"hover","path":"main.go","symbol":"hello"}` |
26+| What a file contains (outline) | `{"action":"symbols","path":"main.go"}` |
27+| What the compiler reports in a file | `{"action":"diagnostics","path":"main.go"}` |
28+| Rename it everywhere, files rewritten | `{"action":"rename","path":"main.go","symbol":"hello","new_name":"greet"}` |
29+| The occurrence on one line only | add `"line": 9` to any of the calls above |
30+
31+Answers come as `path:line:column <source line>`, one per location. You rarely need to open the file afterwards.
32+
33+## Procedure for a change
34+
35+1. `symbols` on the file to find the symbol, or `read_file numbered=true` if you already know roughly where it is.
36+2. `references` on the symbol to see every file the change touches. Say how many there are.
37+3. Edit with `edit_file` (or `rename` when the change is a rename — it rewrites all the files at once).
38+4. `diagnostics` on each edited file to see what the compiler reports, then fix what it says.
39+5. Only then run the tests with `bash`.
40+
41+## Rules
42+
43+- A `[lsp: …]` answer is information, not a crash: read it. "no language server for" means the extension is not covered — use `bash`. "not found in" means the identifier is not spelled as in the code — read the file and copy it. "past the end of line" means you miscounted — use `symbol` instead.
44+- `diagnostics` right after an edit may say "as last published" or "no diagnostics received": the server is still indexing. Ask again once.
45+- `rename` writes files. It NEEDS `new_name`, the new identifier; without it the tool answers with the exact call to make — make it, do not fall back to `edit_file`. Say what it changed, and never rename to a name the file already uses for something else.
added mini-mes/riker/README.en.md +69 -0
new file mode 100644
@@ -0,0 +1,69 @@
1+# Riker — one coordinator, two specialists
2+
3+Three `mm` agents working together through `mm --ask`, called from the coordinator's skills.
4+
5+| Agent | Role | Model (llmman) | Reasoning |
6+|---|---|---|---|
7+| **riker** | Coordinator: talks with you, picks the skill, hands the work over | `hf.co/unsloth/gemma-4-E4B-it-GGUF:Q4_K_M` | off (`enable_thinking: false`) |
8+| **milo** | Specifier: writes the spec, checks the code against it | `hf.co/unsloth/gemma-4-26B-A4B-it-GGUF:Q4_K_M` | on (`enable_thinking: true`) |
9+| **homer** | Coder: implements the spec, with tests | `hf.co/unsloth/Qwen3-Coder-Next-GGUF:Q4_K_M` | none (not a reasoning model) |
10+
11+## The flow
12+
13+Hand-offs go through **files**, in the project's `specs/` directory:
14+
15+```
16+you ──► riker ──write_file──► specs/<slug>.brief.md
17+ └─ mm --ask milo ──► specs/<slug>.spec.md (+ milo.log)
18+ └─ AGENT_YOLO=true mm --ask homer ──► code + specs/<slug>.report.md (+ homer.log)
19+ └─ mm --ask milo ──► specs/<slug>.check.md
20+```
21+
22+Nothing long travels on a command line (no quoting problems), and every step leaves a file you can read or fix before the next one.
23+
24+Each hand-off is a small script in `bin/` (`specify.sh`, `implement.sh`, `check.sh`, one argument: the slug) that the skills have riker run. On a first try, the 4B model miscopied the full `--ask` line: it dropped the quotes and `AGENT_YOLO=true`. It copies a short command correctly. The scripts also keep each agent's raw output (`.milo.out`, `.homer.out`) and extract only the document (the spec from its title on, the report from `# Report` on).
25+
26+## Riker's skills
27+
28+| Skill | What it does |
29+|---|---|
30+| `specify` | Writes the brief, asks milo for the spec, summarises it, **stops** for your approval. |
31+| `implement` | Asks homer to implement a spec, relays his report. |
32+| `check-against-spec` | Asks milo to check the code, criterion by criterion. |
33+| `build-feature` | The three in a row; stops after the spec unless you say to go all the way. |
34+
35+homer has his own skill, `skills-homer/implement-spec`: requirement by requirement, code and its tests, then a report in a fixed format.
36+
37+## Run
38+
39+From the project to work on:
40+
41+```bash
42+cd ~/src/my-project
43+mm -config /path/to/mini-me/mini-mes/riker/agent.riker.yaml
44+```
45+
46+Then, for instance: *"Create a Go CLI that converts temperatures"*, or *"specify a CSV export of the orders"*.
47+
48+You can also ask the agents directly: `/ask-milo …`, `/ask-homer …` in riker, or `mm -config agent.homer.yaml` from the project.
49+
50+## Permissions — read this
51+
52+- **riker has `yolo: false`**: every bash command and every write is submitted to you. Each hand-off to milo or homer is a bash command: you see it and approve it before it runs.
53+- **milo is read-only in practice**: an asked agent's tool calls follow the asker's `yolo`. `read_file` never asks; his writes are refused.
54+- **homer is started with `AGENT_YOLO=true`** by the `implement` skill: once you approve the command, he edits files and runs commands **without asking**. That is deliberate, since coding is his job, but work in a clean git repository so you can review and revert his changes.
55+- With `mm -p` nobody can answer: riker needs `AGENT_YOLO=true`, and then milo can write too.
56+
57+## Notable settings
58+
59+- **Riker's 30-minute timeouts** (`bashTimeout`, `watchdogTimeout`): one `--ask homer` command lasts the whole implementation. The price: a genuinely hung riker generation is only detected after 30 minutes.
60+- **Sampling**: each model starts from its own GGUF metadata (Gemma: 1.0 / 0.95 / top_k 64; Qwen3-Coder-Next: 1.0 / 0.95 / top_k 40). Riker's temperature is lowered to 0.3 (to copy exact commands), milo's to 0.7 (spec precision). Homer's is left as is.
61+- **Gemma 4**: its template reads `enable_thinking`, off by default, with no effort levels.
62+- **Absolute `skillsDir`** for riker and homer: in the terminal, a relative path would be resolved from your project.
63+- **Memory**: up to three models loaded at once in llmman (~5 + ~16 + ~48 GB at Q4). llmman unloads a model after five idle minutes.
64+
65+## See also
66+
67+- [Ask another agent from a skill](../../docs/en/how-to/ask-another-agent-from-a-skill.md)
68+- [CLI reference — ask mode](../../docs/en/reference/cli.md)
69+- [Turn reasoning off or tune it](../../docs/en/how-to/turn-reasoning-off.md)
new file mode 100644
@@ -0,0 +1,69 @@
1+# Riker — one coordinator, two specialists
2+
3+Three `mm` agents working together through `mm --ask`, called from the coordinator's skills.
4+
5+| Agent | Role | Model (llmman) | Reasoning |
6+|---|---|---|---|
7+| **riker** | Coordinator: talks with you, picks the skill, hands the work over | `hf.co/unsloth/gemma-4-E4B-it-GGUF:Q4_K_M` | off (`enable_thinking: false`) |
8+| **milo** | Specifier: writes the spec, checks the code against it | `hf.co/unsloth/gemma-4-26B-A4B-it-GGUF:Q4_K_M` | on (`enable_thinking: true`) |
9+| **homer** | Coder: implements the spec, with tests | `hf.co/unsloth/Qwen3-Coder-Next-GGUF:Q4_K_M` | none (not a reasoning model) |
10+
11+## The flow
12+
13+Hand-offs go through **files**, in the project's `specs/` directory:
14+
15+```
16+you ──► riker ──write_file──► specs/<slug>.brief.md
17+ └─ mm --ask milo ──► specs/<slug>.spec.md (+ milo.log)
18+ └─ AGENT_YOLO=true mm --ask homer ──► code + specs/<slug>.report.md (+ homer.log)
19+ └─ mm --ask milo ──► specs/<slug>.check.md
20+```
21+
22+Nothing long travels on a command line (no quoting problems), and every step leaves a file you can read or fix before the next one.
23+
24+Each hand-off is a small script in `bin/` (`specify.sh`, `implement.sh`, `check.sh`, one argument: the slug) that the skills have riker run. On a first try, the 4B model miscopied the full `--ask` line: it dropped the quotes and `AGENT_YOLO=true`. It copies a short command correctly. The scripts also keep each agent's raw output (`.milo.out`, `.homer.out`) and extract only the document (the spec from its title on, the report from `# Report` on).
25+
26+## Riker's skills
27+
28+| Skill | What it does |
29+|---|---|
30+| `specify` | Writes the brief, asks milo for the spec, summarises it, **stops** for your approval. |
31+| `implement` | Asks homer to implement a spec, relays his report. |
32+| `check-against-spec` | Asks milo to check the code, criterion by criterion. |
33+| `build-feature` | The three in a row; stops after the spec unless you say to go all the way. |
34+
35+homer has his own skill, `skills-homer/implement-spec`: requirement by requirement, code and its tests, then a report in a fixed format.
36+
37+## Run
38+
39+From the project to work on:
40+
41+```bash
42+cd ~/src/my-project
43+mm -config /path/to/mini-me/mini-mes/riker/agent.riker.yaml
44+```
45+
46+Then, for instance: *"Create a Go CLI that converts temperatures"*, or *"specify a CSV export of the orders"*.
47+
48+You can also ask the agents directly: `/ask-milo …`, `/ask-homer …` in riker, or `mm -config agent.homer.yaml` from the project.
49+
50+## Permissions — read this
51+
52+- **riker has `yolo: false`**: every bash command and every write is submitted to you. Each hand-off to milo or homer is a bash command: you see it and approve it before it runs.
53+- **milo is read-only in practice**: an asked agent's tool calls follow the asker's `yolo`. `read_file` never asks; his writes are refused.
54+- **homer is started with `AGENT_YOLO=true`** by the `implement` skill: once you approve the command, he edits files and runs commands **without asking**. That is deliberate, since coding is his job, but work in a clean git repository so you can review and revert his changes.
55+- With `mm -p` nobody can answer: riker needs `AGENT_YOLO=true`, and then milo can write too.
56+
57+## Notable settings
58+
59+- **Riker's 30-minute timeouts** (`bashTimeout`, `watchdogTimeout`): one `--ask homer` command lasts the whole implementation. The price: a genuinely hung riker generation is only detected after 30 minutes.
60+- **Sampling**: each model starts from its own GGUF metadata (Gemma: 1.0 / 0.95 / top_k 64; Qwen3-Coder-Next: 1.0 / 0.95 / top_k 40). Riker's temperature is lowered to 0.3 (to copy exact commands), milo's to 0.7 (spec precision). Homer's is left as is.
61+- **Gemma 4**: its template reads `enable_thinking`, off by default, with no effort levels.
62+- **Absolute `skillsDir`** for riker and homer: in the terminal, a relative path would be resolved from your project.
63+- **Memory**: up to three models loaded at once in llmman (~5 + ~16 + ~48 GB at Q4). llmman unloads a model after five idle minutes.
64+
65+## See also
66+
67+- [Ask another agent from a skill](../../docs/en/how-to/ask-another-agent-from-a-skill.md)
68+- [CLI reference — ask mode](../../docs/en/reference/cli.md)
69+- [Turn reasoning off or tune it](../../docs/en/how-to/turn-reasoning-off.md)
added mini-mes/riker/README.md +69 -0
new file mode 100644
@@ -0,0 +1,69 @@
1+# Riker — un coordinateur et deux spécialistes
2+
3+Trois agents `mm` qui travaillent ensemble par `mm --ask`, appelé depuis les skills du coordinateur.
4+
5+| Agent | Rôle | Modèle (llmman) | Raisonnement |
6+|---|---|---|---|
7+| **riker** | Coordinateur : parle avec vous, choisit la skill, passe la main | `hf.co/unsloth/gemma-4-E4B-it-GGUF:Q4_K_M` | coupé (`enable_thinking: false`) |
8+| **milo** | Spécificateur : écrit la spec, vérifie le code contre elle | `hf.co/unsloth/gemma-4-26B-A4B-it-GGUF:Q4_K_M` | actif (`enable_thinking: true`) |
9+| **homer** | Codeur : implémente la spec, avec tests | `hf.co/unsloth/Qwen3-Coder-Next-GGUF:Q4_K_M` | aucun (modèle sans raisonnement) |
10+
11+## Le circuit
12+
13+Les échanges passent par des **fichiers**, dans le dossier `specs/` du projet :
14+
15+```
16+vous ──► riker ──write_file──► specs/<slug>.brief.md
17+ └─ mm --ask milo ──► specs/<slug>.spec.md (+ milo.log)
18+ └─ AGENT_YOLO=true mm --ask homer ──► code + specs/<slug>.report.md (+ homer.log)
19+ └─ mm --ask milo ──► specs/<slug>.check.md
20+```
21+
22+Rien de long ne transite par une ligne de commande (pas de problème de guillemets), et chaque étape laisse un fichier que vous pouvez lire ou corriger avant la suivante.
23+
24+Chaque passage de main est un petit script de `bin/` (`specify.sh`, `implement.sh`, `check.sh`, un argument : le slug) que les skills font lancer à riker. Lors d'un premier essai, le modèle 4B recopiait mal la ligne `--ask` complète : il oubliait les guillemets et `AGENT_YOLO=true`. Une commande courte, il la recopie juste. Les scripts gardent aussi la sortie brute de chaque agent (`.milo.out`, `.homer.out`) et n'extraient que le document (la spec à partir de son titre, le rapport à partir de `# Report`).
25+
26+## Skills de riker
27+
28+| Skill | Ce qu'elle fait |
29+|---|---|
30+| `specify` | Écrit le brief, demande la spec à milo, la résume, **s'arrête** pour votre accord. |
31+| `implement` | Demande à homer d'implémenter une spec, rapporte son compte rendu. |
32+| `check-against-spec` | Demande à milo de vérifier le code critère par critère. |
33+| `build-feature` | Les trois à la suite ; s'arrête après la spec, sauf si vous dites d'aller jusqu'au bout. |
34+
35+homer a sa propre skill, `skills-homer/implement-spec` : exigence par exigence, du code et ses tests, puis un rapport au format fixe.
36+
37+## Lancer
38+
39+Depuis le projet sur lequel travailler :
40+
41+```bash
42+cd ~/src/mon-projet
43+mm -config /chemin/vers/mini-me/mini-mes/riker/agent.riker.yaml
44+```
45+
46+Puis, par exemple : *« Crée un CLI Go qui convertit des températures »*, ou *« spécifie un export CSV des commandes »*.
47+
48+Vous pouvez aussi interroger les agents directement : `/ask-milo …`, `/ask-homer …` dans riker, ou `mm -config agent.homer.yaml` depuis le projet.
49+
50+## Permissions — à lire
51+
52+- **riker a `yolo: false`** : chaque commande bash et chaque écriture vous est soumise. Chaque passage de main à milo ou homer est une commande bash : vous la voyez et l'approuvez avant qu'elle parte.
53+- **milo est en lecture seule de fait** : les appels d'outils d'un agent interrogé suivent le `yolo` de celui qui pose la question. `read_file` ne demande jamais ; ses écritures sont refusées.
54+- **homer est lancé avec `AGENT_YOLO=true`** par la skill `implement` : une fois la commande approuvée, il modifie des fichiers et lance des commandes **sans rien demander**. C'est voulu, puisque coder est son travail, mais travaillez dans un dépôt git propre pour pouvoir relire et annuler ses changements.
55+- Avec `mm -p`, personne ne peut répondre : il faut `AGENT_YOLO=true` pour riker, et alors milo peut écrire lui aussi.
56+
57+## Réglages notables
58+
59+- **Délais de riker à 30 min** (`bashTimeout`, `watchdogTimeout`) : une commande `--ask homer` dure tout le temps de l'implémentation. En contrepartie, une génération de riker réellement bloquée n'est détectée qu'au bout de 30 minutes.
60+- **Échantillonnage** : chaque modèle part des valeurs de ses propres métadonnées GGUF (Gemma : 1.0 / 0.95 / top_k 64 ; Qwen3-Coder-Next : 1.0 / 0.95 / top_k 40). La température de riker est baissée à 0.3 (copier des commandes exactes), celle de milo à 0.7 (précision d'une spec). Celle de homer est laissée telle quelle.
61+- **Gemma 4** : le template lit `enable_thinking`, désactivé par défaut, sans niveaux d'effort.
62+- **`skillsDir` absolu** pour riker et homer : en mode terminal, un chemin relatif serait résolu depuis votre projet.
63+- **Mémoire** : jusqu'à trois modèles chargés en même temps dans llmman (~5 + ~16 + ~48 Go en Q4). llmman décharge un modèle après cinq minutes d'inactivité.
64+
65+## Voir aussi
66+
67+- [Interroger un autre agent depuis une skill](../../docs/fr/how-to/ask-another-agent-from-a-skill.md)
68+- [Référence de la ligne de commande — mode ask](../../docs/fr/reference/cli.md)
69+- [Couper ou régler le raisonnement](../../docs/fr/how-to/turn-reasoning-off.md)
new file mode 100644
@@ -0,0 +1,69 @@
1+# Riker — un coordinateur et deux spécialistes
2+
3+Trois agents `mm` qui travaillent ensemble par `mm --ask`, appelé depuis les skills du coordinateur.
4+
5+| Agent | Rôle | Modèle (llmman) | Raisonnement |
6+|---|---|---|---|
7+| **riker** | Coordinateur : parle avec vous, choisit la skill, passe la main | `hf.co/unsloth/gemma-4-E4B-it-GGUF:Q4_K_M` | coupé (`enable_thinking: false`) |
8+| **milo** | Spécificateur : écrit la spec, vérifie le code contre elle | `hf.co/unsloth/gemma-4-26B-A4B-it-GGUF:Q4_K_M` | actif (`enable_thinking: true`) |
9+| **homer** | Codeur : implémente la spec, avec tests | `hf.co/unsloth/Qwen3-Coder-Next-GGUF:Q4_K_M` | aucun (modèle sans raisonnement) |
10+
11+## Le circuit
12+
13+Les échanges passent par des **fichiers**, dans le dossier `specs/` du projet :
14+
15+```
16+vous ──► riker ──write_file──► specs/<slug>.brief.md
17+ └─ mm --ask milo ──► specs/<slug>.spec.md (+ milo.log)
18+ └─ AGENT_YOLO=true mm --ask homer ──► code + specs/<slug>.report.md (+ homer.log)
19+ └─ mm --ask milo ──► specs/<slug>.check.md
20+```
21+
22+Rien de long ne transite par une ligne de commande (pas de problème de guillemets), et chaque étape laisse un fichier que vous pouvez lire ou corriger avant la suivante.
23+
24+Chaque passage de main est un petit script de `bin/` (`specify.sh`, `implement.sh`, `check.sh`, un argument : le slug) que les skills font lancer à riker. Lors d'un premier essai, le modèle 4B recopiait mal la ligne `--ask` complète : il oubliait les guillemets et `AGENT_YOLO=true`. Une commande courte, il la recopie juste. Les scripts gardent aussi la sortie brute de chaque agent (`.milo.out`, `.homer.out`) et n'extraient que le document (la spec à partir de son titre, le rapport à partir de `# Report`).
25+
26+## Skills de riker
27+
28+| Skill | Ce qu'elle fait |
29+|---|---|
30+| `specify` | Écrit le brief, demande la spec à milo, la résume, **s'arrête** pour votre accord. |
31+| `implement` | Demande à homer d'implémenter une spec, rapporte son compte rendu. |
32+| `check-against-spec` | Demande à milo de vérifier le code critère par critère. |
33+| `build-feature` | Les trois à la suite ; s'arrête après la spec, sauf si vous dites d'aller jusqu'au bout. |
34+
35+homer a sa propre skill, `skills-homer/implement-spec` : exigence par exigence, du code et ses tests, puis un rapport au format fixe.
36+
37+## Lancer
38+
39+Depuis le projet sur lequel travailler :
40+
41+```bash
42+cd ~/src/mon-projet
43+mm -config /chemin/vers/mini-me/mini-mes/riker/agent.riker.yaml
44+```
45+
46+Puis, par exemple : *« Crée un CLI Go qui convertit des températures »*, ou *« spécifie un export CSV des commandes »*.
47+
48+Vous pouvez aussi interroger les agents directement : `/ask-milo …`, `/ask-homer …` dans riker, ou `mm -config agent.homer.yaml` depuis le projet.
49+
50+## Permissions — à lire
51+
52+- **riker a `yolo: false`** : chaque commande bash et chaque écriture vous est soumise. Chaque passage de main à milo ou homer est une commande bash : vous la voyez et l'approuvez avant qu'elle parte.
53+- **milo est en lecture seule de fait** : les appels d'outils d'un agent interrogé suivent le `yolo` de celui qui pose la question. `read_file` ne demande jamais ; ses écritures sont refusées.
54+- **homer est lancé avec `AGENT_YOLO=true`** par la skill `implement` : une fois la commande approuvée, il modifie des fichiers et lance des commandes **sans rien demander**. C'est voulu, puisque coder est son travail, mais travaillez dans un dépôt git propre pour pouvoir relire et annuler ses changements.
55+- Avec `mm -p`, personne ne peut répondre : il faut `AGENT_YOLO=true` pour riker, et alors milo peut écrire lui aussi.
56+
57+## Réglages notables
58+
59+- **Délais de riker à 30 min** (`bashTimeout`, `watchdogTimeout`) : une commande `--ask homer` dure tout le temps de l'implémentation. En contrepartie, une génération de riker réellement bloquée n'est détectée qu'au bout de 30 minutes.
60+- **Échantillonnage** : chaque modèle part des valeurs de ses propres métadonnées GGUF (Gemma : 1.0 / 0.95 / top_k 64 ; Qwen3-Coder-Next : 1.0 / 0.95 / top_k 40). La température de riker est baissée à 0.3 (copier des commandes exactes), celle de milo à 0.7 (précision d'une spec). Celle de homer est laissée telle quelle.
61+- **Gemma 4** : le template lit `enable_thinking`, désactivé par défaut, sans niveaux d'effort.
62+- **`skillsDir` absolu** pour riker et homer : en mode terminal, un chemin relatif serait résolu depuis votre projet.
63+- **Mémoire** : jusqu'à trois modèles chargés en même temps dans llmman (~5 + ~16 + ~48 Go en Q4). llmman décharge un modèle après cinq minutes d'inactivité.
64+
65+## Voir aussi
66+
67+- [Interroger un autre agent depuis une skill](../../docs/fr/how-to/ask-another-agent-from-a-skill.md)
68+- [Référence de la ligne de commande — mode ask](../../docs/fr/reference/cli.md)
69+- [Couper ou régler le raisonnement](../../docs/fr/how-to/turn-reasoning-off.md)
added mini-mes/riker/agent.homer.yaml +148 -0
new file mode 100644
@@ -0,0 +1,148 @@
1+# Homer — the coder. Asked by riker (`AGENT_YOLO=true mm --ask homer`) to
2+# implement a specification written by milo. You can also run him directly:
3+# `mm -config agent.homer.yaml`, from the project.
4+#
5+# Started by riker as a child process (`mm -acp -config agent.homer.yaml`)
6+# in riker's working directory — the project.
7+
8+# ─── Model and server ────────────────────────────────────────────────────────
9+
10+provider: llmman
11+
12+# Qwen3-Coder-Next: an 80B mixture of experts (512 experts, 10 active, ~3B
13+# active parameters per token), trained for agentic coding — tool calls,
14+# long edit/test loops. ~48 GB at Q4_K_M.
15+#model: hf.co/unsloth/Qwen3-Coder-Next-GGUF:Q4_K_M
16+model: hf.co/unsloth/Qwen3.8-27B-GGUF:Q4_K_M
17+
18+baseUrl: http://127.0.0.1:17434/v1
19+fallback: http://host.docker.internal:17434/v1
20+
21+# Served window, asked from llmman (up to 262,144 for this model).
22+contextWindow: 0
23+
24+# ─── Generation ──────────────────────────────────────────────────────────────
25+
26+sampling:
27+ # The GGUF's own metadata: temp 1.0 / top_p 0.95 / top_k 40, the values
28+ # this model was tuned with. Kept as they are.
29+ temperature: 1.0
30+ top_p: 0.95
31+ top_k: 40
32+
33+ # A whole file in one write_file call needs room. No reasoning to pay for:
34+ # the budget is all code and tool calls.
35+ max_tokens: 16384
36+
37+ # Sequential work: edit, then build, then test.
38+ parallel_tool_calls: false
39+
40+ # No chat_template_kwargs: this model does not reason (its template has no
41+ # thinking block and reads neither enable_thinking nor reasoning_effort —
42+ # verified on the GGUF served by llmman). Anything set here would be inert.
43+ chat_template_kwargs:
44+ enable_thinking: true
45+ reasoning_effort: low
46+
47+showThinking: true
48+
49+# ─── Timeouts ────────────────────────────────────────────────────────────────
50+
51+# Loading ~48 GB on the first question, then long prompts.
52+firstTokenTimeout: 5m
53+
54+# One build or test command may take minutes (module downloads, cold cache).
55+bashTimeout: 5m
56+
57+# Counts during bash commands: at least bashTimeout.
58+watchdogTimeout: 5m
59+
60+# ─── Agent loop ──────────────────────────────────────────────────────────────
61+
62+# Implementing a spec is many round trips: read, edit, build, test, fix —
63+# per requirement.
64+maxTurns: 80
65+
66+# Build and test output can be long; 20000 keeps the whole failure report.
67+maxOutput: 20000
68+
69+previewLines: 20
70+displayCommands: true
71+
72+# ─── Tools ───────────────────────────────────────────────────────────────────
73+
74+# When riker asks, riker's yolo decides homer's calls — and riker's skill
75+# starts the ask with AGENT_YOLO=true, so homer works without interruption
76+# once you approved the hand-off. When you run homer directly, this applies:
77+# every change waits for you.
78+yolo: false
79+
80+bashTool: true
81+editTools: true
82+
83+# No plan tool: the spec's numbered requirements ARE the todo list, and the
84+# report says what is done. Measured on a first run: 14 of homer's 32 tool
85+# calls were plan bookkeeping.
86+planTool: false
87+
88+# Reading a library's documentation on the web.
89+fetchContentTool: true
90+
91+# Uncomment the servers you have, for definition / references / diagnostics.
92+# lsp:
93+# servers:
94+# - name: gopls
95+# command: gopls
96+# extensions: [".go"]
97+# - name: typescript
98+# command: typescript-language-server
99+# args: ["--stdio"]
100+# extensions: [".ts", ".tsx", ".js", ".jsx"]
101+
102+# One skill: implement-spec. Absolute: a relative path would follow this
103+# file when riker asks (ACP mode) but the current directory when you run
104+# homer directly in a terminal. Adjust it if you move the repository.
105+skillsDir: /Users/k33g/kDrive/Rickub/bots-garden/mini-me/mini-mes/riker/skills-homer
106+
107+# Asked agents never write sessions; this matters only for a direct start.
108+sessions:
109+ enabled: false
110+
111+context:
112+ enabled: true
113+ # 30 % of 262k ≈ 79k tokens before compressing a long implementation.
114+ threshold: 30
115+ maxMessages: 120
116+ keepLastTurns: 3
117+ summaryMaxTokens: 2000
118+ showStats: true
119+
120+acp:
121+ name: homer
122+ title: Homer (coder)
123+
124+system: |
125+ Your name is Homer. You are a senior software engineer working in a
126+ terminal, in the project in the current directory. You are usually asked by
127+ a coordinator to implement a specification file written by Milo.
128+
129+ For any request to implement a specification, call `read_skill` with
130+ `implement-spec` FIRST, then follow it.
131+
132+ TOOLS
133+ - `bash` runs commands: build, test, list files, search.
134+ - `read_file`, `edit_file`, `write_file` read and change files. Read before
135+ you write. Change existing files with `edit_file` (`old` copied exactly,
136+ unique); `write_file` only for new files or a deliberate full rewrite.
137+ - `fetch_content` reads documentation pages.
138+
139+ RULES
140+ - Facts come from tools: never claim code builds or tests pass without the
141+ command output in this answer.
142+ - Follow the specification. Where it is silent, choose the simplest option
143+ and report it.
144+ - Match the project's existing style, language and tools.
145+ - Write tests for every requirement you implement.
146+ - Never run git commands that change state; never delete files you did
147+ not create; nothing interactive (no stdin).
148+ - Your final answer is a REPORT, in English, read by another agent.
new file mode 100644
@@ -0,0 +1,148 @@
1+# Homer — the coder. Asked by riker (`AGENT_YOLO=true mm --ask homer`) to
2+# implement a specification written by milo. You can also run him directly:
3+# `mm -config agent.homer.yaml`, from the project.
4+#
5+# Started by riker as a child process (`mm -acp -config agent.homer.yaml`)
6+# in riker's working directory — the project.
7+
8+# ─── Model and server ────────────────────────────────────────────────────────
9+
10+provider: llmman
11+
12+# Qwen3-Coder-Next: an 80B mixture of experts (512 experts, 10 active, ~3B
13+# active parameters per token), trained for agentic coding — tool calls,
14+# long edit/test loops. ~48 GB at Q4_K_M.
15+#model: hf.co/unsloth/Qwen3-Coder-Next-GGUF:Q4_K_M
16+model: hf.co/unsloth/Qwen3.8-27B-GGUF:Q4_K_M
17+
18+baseUrl: http://127.0.0.1:17434/v1
19+fallback: http://host.docker.internal:17434/v1
20+
21+# Served window, asked from llmman (up to 262,144 for this model).
22+contextWindow: 0
23+
24+# ─── Generation ──────────────────────────────────────────────────────────────
25+
26+sampling:
27+ # The GGUF's own metadata: temp 1.0 / top_p 0.95 / top_k 40, the values
28+ # this model was tuned with. Kept as they are.
29+ temperature: 1.0
30+ top_p: 0.95
31+ top_k: 40
32+
33+ # A whole file in one write_file call needs room. No reasoning to pay for:
34+ # the budget is all code and tool calls.
35+ max_tokens: 16384
36+
37+ # Sequential work: edit, then build, then test.
38+ parallel_tool_calls: false
39+
40+ # No chat_template_kwargs: this model does not reason (its template has no
41+ # thinking block and reads neither enable_thinking nor reasoning_effort —
42+ # verified on the GGUF served by llmman). Anything set here would be inert.
43+ chat_template_kwargs:
44+ enable_thinking: true
45+ reasoning_effort: low
46+
47+showThinking: true
48+
49+# ─── Timeouts ────────────────────────────────────────────────────────────────
50+
51+# Loading ~48 GB on the first question, then long prompts.
52+firstTokenTimeout: 5m
53+
54+# One build or test command may take minutes (module downloads, cold cache).
55+bashTimeout: 5m
56+
57+# Counts during bash commands: at least bashTimeout.
58+watchdogTimeout: 5m
59+
60+# ─── Agent loop ──────────────────────────────────────────────────────────────
61+
62+# Implementing a spec is many round trips: read, edit, build, test, fix —
63+# per requirement.
64+maxTurns: 80
65+
66+# Build and test output can be long; 20000 keeps the whole failure report.
67+maxOutput: 20000
68+
69+previewLines: 20
70+displayCommands: true
71+
72+# ─── Tools ───────────────────────────────────────────────────────────────────
73+
74+# When riker asks, riker's yolo decides homer's calls — and riker's skill
75+# starts the ask with AGENT_YOLO=true, so homer works without interruption
76+# once you approved the hand-off. When you run homer directly, this applies:
77+# every change waits for you.
78+yolo: false
79+
80+bashTool: true
81+editTools: true
82+
83+# No plan tool: the spec's numbered requirements ARE the todo list, and the
84+# report says what is done. Measured on a first run: 14 of homer's 32 tool
85+# calls were plan bookkeeping.
86+planTool: false
87+
88+# Reading a library's documentation on the web.
89+fetchContentTool: true
90+
91+# Uncomment the servers you have, for definition / references / diagnostics.
92+# lsp:
93+# servers:
94+# - name: gopls
95+# command: gopls
96+# extensions: [".go"]
97+# - name: typescript
98+# command: typescript-language-server
99+# args: ["--stdio"]
100+# extensions: [".ts", ".tsx", ".js", ".jsx"]
101+
102+# One skill: implement-spec. Absolute: a relative path would follow this
103+# file when riker asks (ACP mode) but the current directory when you run
104+# homer directly in a terminal. Adjust it if you move the repository.
105+skillsDir: /Users/k33g/kDrive/Rickub/bots-garden/mini-me/mini-mes/riker/skills-homer
106+
107+# Asked agents never write sessions; this matters only for a direct start.
108+sessions:
109+ enabled: false
110+
111+context:
112+ enabled: true
113+ # 30 % of 262k ≈ 79k tokens before compressing a long implementation.
114+ threshold: 30
115+ maxMessages: 120
116+ keepLastTurns: 3
117+ summaryMaxTokens: 2000
118+ showStats: true
119+
120+acp:
121+ name: homer
122+ title: Homer (coder)
123+
124+system: |
125+ Your name is Homer. You are a senior software engineer working in a
126+ terminal, in the project in the current directory. You are usually asked by
127+ a coordinator to implement a specification file written by Milo.
128+
129+ For any request to implement a specification, call `read_skill` with
130+ `implement-spec` FIRST, then follow it.
131+
132+ TOOLS
133+ - `bash` runs commands: build, test, list files, search.
134+ - `read_file`, `edit_file`, `write_file` read and change files. Read before
135+ you write. Change existing files with `edit_file` (`old` copied exactly,
136+ unique); `write_file` only for new files or a deliberate full rewrite.
137+ - `fetch_content` reads documentation pages.
138+
139+ RULES
140+ - Facts come from tools: never claim code builds or tests pass without the
141+ command output in this answer.
142+ - Follow the specification. Where it is silent, choose the simplest option
143+ and report it.
144+ - Match the project's existing style, language and tools.
145+ - Write tests for every requirement you implement.
146+ - Never run git commands that change state; never delete files you did
147+ not create; nothing interactive (no stdin).
148+ - Your final answer is a REPORT, in English, read by another agent.
added mini-mes/riker/agent.milo.yaml +159 -0
new file mode 100644
@@ -0,0 +1,159 @@
1+# Milo — the specifier. Asked by riker (`mm --ask milo`), never used directly
2+# in normal work (you can: `mm -config agent.milo.yaml`).
3+#
4+# Two jobs: turn a brief into a specification, and check an implementation
5+# against a specification. His answer is redirected to a file by riker's
6+# skill, so he answers with the document and nothing else.
7+#
8+# Started by riker as a child process (`mm -acp -config agent.milo.yaml`) in
9+# riker's working directory — the project.
10+
11+# ─── Model and server ────────────────────────────────────────────────────────
12+
13+provider: llmman
14+
15+# Gemma 4 26B-A4B: a mixture of experts, 25B parameters, ~4B active per
16+# token — the reasoning depth of a mid-size model at the speed of a small one.
17+model: hf.co/unsloth/gemma-4-26B-A4B-it-GGUF:Q4_K_M
18+
19+baseUrl: http://127.0.0.1:17434/v1
20+fallback: http://host.docker.internal:17434/v1
21+
22+# Served window, asked from llmman (up to 262,144 for this model).
23+contextWindow: 0
24+
25+# ─── Generation ──────────────────────────────────────────────────────────────
26+
27+sampling:
28+ # Gemma's own metadata: temp 1.0 / top_p 0.95 / top_k 64. A specification
29+ # must be precise more than inventive: temperature lowered to 0.7.
30+ temperature: 0.7
31+ top_p: 0.95
32+ top_k: 64
33+
34+ # Reasoning + a complete specification in ONE reply.
35+ max_tokens: 16384
36+
37+ parallel_tool_calls: false
38+
39+ # Gemma 4's template: `enable_thinking`, false by default. ON here: a
40+ # specification is where thinking pays — requirements, edge cases,
41+ # acceptance criteria. (Gemma 4 has no effort levels: on or off.)
42+ chat_template_kwargs:
43+ enable_thinking: true
44+
45+# Milo's reasoning never reaches riker (an asked agent's thoughts are not
46+# part of its answer); shown when you run milo directly.
47+showThinking: true
48+
49+# ─── Timeouts ────────────────────────────────────────────────────────────────
50+
51+# Loading ~16 GB and reading the project's files before the first token.
52+firstTokenTimeout: 5m
53+
54+# Between two tokens. Milo runs no commands, so this only has to cover a
55+# pause of the server.
56+watchdogTimeout: 2m
57+
58+# ─── Agent loop ──────────────────────────────────────────────────────────────
59+
60+# Reading a handful of files, then writing.
61+maxTurns: 20
62+
63+# A source file returned by read_file; 20000 characters is a long Go/TS file.
64+maxOutput: 20000
65+
66+previewLines: 20
67+displayCommands: true
68+
69+# ─── Tools ───────────────────────────────────────────────────────────────────
70+
71+# Riker's yolo decides milo's calls. read_file never asks, so it always
72+# works; write_file / edit_file are refused (riker runs with yolo false and
73+# does not override it for milo): milo is read-only in practice, and his
74+# prompt says so too.
75+yolo: false
76+
77+# No bash: a specifier reads, he does not run things.
78+bashTool: false
79+
80+# read_file — to read the brief and the code it mentions. (write_file and
81+# edit_file come with it; see yolo above.)
82+editTools: true
83+
84+planTool: false
85+fetchContentTool: false
86+
87+# No skills: his prompt is his whole procedure. A name that does not exist =
88+# no read_skill tool (and a warning on a direct start).
89+skillsDir: no-skills-for-milo
90+
91+# An asked agent never writes sessions (mm turns them off); this only matters
92+# when you run milo directly.
93+sessions:
94+ enabled: false
95+
96+context:
97+ enabled: true
98+ threshold: 50
99+ maxMessages: 80
100+ keepLastTurns: 3
101+ summaryMaxTokens: 1200
102+ showStats: true
103+
104+acp:
105+ name: milo
106+ title: Milo (specifier)
107+
108+system: |
109+ Your name is Milo. You are a software specifier. You are asked by a
110+ coordinator, not by a person: your answer is saved to a file as it is.
111+
112+ YOUR TOOLS
113+ `read_file` only. Read the files you are told to read, and the files they
114+ mention. Never call `write_file` or `edit_file`: they are refused. Your
115+ answer IS the document.
116+
117+ JOB 1 — WRITE A SPECIFICATION
118+ When asked to specify from a brief: read the brief, read the existing code
119+ it names, then answer with the specification in Markdown. Start with a
120+ line `# <Title>`, then these eight `##` headings, written exactly as
121+ shown here — the heading text only, nothing after it:
122+
123+ ## Goal
124+ ## Context
125+ ## Requirements
126+ ## Interfaces
127+ ## Edge cases and errors
128+ ## Acceptance criteria
129+ ## Out of scope
130+ ## Open questions
131+
132+ What goes under each:
133+ - Goal: two or three sentences, what and why.
134+ - Context: what exists today (files, functions) that this builds on.
135+ - Requirements: numbered R1, R2…; each testable, one behaviour each.
136+ - Interfaces: functions, types, CLI flags, HTTP routes, file formats,
137+ with exact names and signatures.
138+ - Edge cases and errors: inputs and failures, and the expected behaviour.
139+ - Acceptance criteria: numbered A1, A2…, Given / When / Then, each
140+ traceable to a requirement, with exact commands and outputs when the
141+ brief gives examples.
142+ - Out of scope: what NOT to do.
143+ - Open questions: only what the brief truly leaves undecided, each with
144+ the default you chose so the coder is never blocked.
145+
146+ Write for a coder who will read nothing else: concrete, no filler, no
147+ code beyond signatures and short examples. Language and stack: those of
148+ the project, or of the brief.
149+
150+ JOB 2 — CHECK AN IMPLEMENTATION
151+ When asked to check code against a specification: read the spec, then the
152+ files you are given. Answer with one line per acceptance criterion:
153+ `A1 — met | not met | cannot tell — <file:line or reason>`, then a short
154+ list of anything the code does that the spec does not ask for. Judge only
155+ from what you read.
156+
157+ RULES
158+ - No greeting, no preamble, no closing remark: the document only.
159+ - Answer in English.
new file mode 100644
@@ -0,0 +1,159 @@
1+# Milo — the specifier. Asked by riker (`mm --ask milo`), never used directly
2+# in normal work (you can: `mm -config agent.milo.yaml`).
3+#
4+# Two jobs: turn a brief into a specification, and check an implementation
5+# against a specification. His answer is redirected to a file by riker's
6+# skill, so he answers with the document and nothing else.
7+#
8+# Started by riker as a child process (`mm -acp -config agent.milo.yaml`) in
9+# riker's working directory — the project.
10+
11+# ─── Model and server ────────────────────────────────────────────────────────
12+
13+provider: llmman
14+
15+# Gemma 4 26B-A4B: a mixture of experts, 25B parameters, ~4B active per
16+# token — the reasoning depth of a mid-size model at the speed of a small one.
17+model: hf.co/unsloth/gemma-4-26B-A4B-it-GGUF:Q4_K_M
18+
19+baseUrl: http://127.0.0.1:17434/v1
20+fallback: http://host.docker.internal:17434/v1
21+
22+# Served window, asked from llmman (up to 262,144 for this model).
23+contextWindow: 0
24+
25+# ─── Generation ──────────────────────────────────────────────────────────────
26+
27+sampling:
28+ # Gemma's own metadata: temp 1.0 / top_p 0.95 / top_k 64. A specification
29+ # must be precise more than inventive: temperature lowered to 0.7.
30+ temperature: 0.7
31+ top_p: 0.95
32+ top_k: 64
33+
34+ # Reasoning + a complete specification in ONE reply.
35+ max_tokens: 16384
36+
37+ parallel_tool_calls: false
38+
39+ # Gemma 4's template: `enable_thinking`, false by default. ON here: a
40+ # specification is where thinking pays — requirements, edge cases,
41+ # acceptance criteria. (Gemma 4 has no effort levels: on or off.)
42+ chat_template_kwargs:
43+ enable_thinking: true
44+
45+# Milo's reasoning never reaches riker (an asked agent's thoughts are not
46+# part of its answer); shown when you run milo directly.
47+showThinking: true
48+
49+# ─── Timeouts ────────────────────────────────────────────────────────────────
50+
51+# Loading ~16 GB and reading the project's files before the first token.
52+firstTokenTimeout: 5m
53+
54+# Between two tokens. Milo runs no commands, so this only has to cover a
55+# pause of the server.
56+watchdogTimeout: 2m
57+
58+# ─── Agent loop ──────────────────────────────────────────────────────────────
59+
60+# Reading a handful of files, then writing.
61+maxTurns: 20
62+
63+# A source file returned by read_file; 20000 characters is a long Go/TS file.
64+maxOutput: 20000
65+
66+previewLines: 20
67+displayCommands: true
68+
69+# ─── Tools ───────────────────────────────────────────────────────────────────
70+
71+# Riker's yolo decides milo's calls. read_file never asks, so it always
72+# works; write_file / edit_file are refused (riker runs with yolo false and
73+# does not override it for milo): milo is read-only in practice, and his
74+# prompt says so too.
75+yolo: false
76+
77+# No bash: a specifier reads, he does not run things.
78+bashTool: false
79+
80+# read_file — to read the brief and the code it mentions. (write_file and
81+# edit_file come with it; see yolo above.)
82+editTools: true
83+
84+planTool: false
85+fetchContentTool: false
86+
87+# No skills: his prompt is his whole procedure. A name that does not exist =
88+# no read_skill tool (and a warning on a direct start).
89+skillsDir: no-skills-for-milo
90+
91+# An asked agent never writes sessions (mm turns them off); this only matters
92+# when you run milo directly.
93+sessions:
94+ enabled: false
95+
96+context:
97+ enabled: true
98+ threshold: 50
99+ maxMessages: 80
100+ keepLastTurns: 3
101+ summaryMaxTokens: 1200
102+ showStats: true
103+
104+acp:
105+ name: milo
106+ title: Milo (specifier)
107+
108+system: |
109+ Your name is Milo. You are a software specifier. You are asked by a
110+ coordinator, not by a person: your answer is saved to a file as it is.
111+
112+ YOUR TOOLS
113+ `read_file` only. Read the files you are told to read, and the files they
114+ mention. Never call `write_file` or `edit_file`: they are refused. Your
115+ answer IS the document.
116+
117+ JOB 1 — WRITE A SPECIFICATION
118+ When asked to specify from a brief: read the brief, read the existing code
119+ it names, then answer with the specification in Markdown. Start with a
120+ line `# <Title>`, then these eight `##` headings, written exactly as
121+ shown here — the heading text only, nothing after it:
122+
123+ ## Goal
124+ ## Context
125+ ## Requirements
126+ ## Interfaces
127+ ## Edge cases and errors
128+ ## Acceptance criteria
129+ ## Out of scope
130+ ## Open questions
131+
132+ What goes under each:
133+ - Goal: two or three sentences, what and why.
134+ - Context: what exists today (files, functions) that this builds on.
135+ - Requirements: numbered R1, R2…; each testable, one behaviour each.
136+ - Interfaces: functions, types, CLI flags, HTTP routes, file formats,
137+ with exact names and signatures.
138+ - Edge cases and errors: inputs and failures, and the expected behaviour.
139+ - Acceptance criteria: numbered A1, A2…, Given / When / Then, each
140+ traceable to a requirement, with exact commands and outputs when the
141+ brief gives examples.
142+ - Out of scope: what NOT to do.
143+ - Open questions: only what the brief truly leaves undecided, each with
144+ the default you chose so the coder is never blocked.
145+
146+ Write for a coder who will read nothing else: concrete, no filler, no
147+ code beyond signatures and short examples. Language and stack: those of
148+ the project, or of the brief.
149+
150+ JOB 2 — CHECK AN IMPLEMENTATION
151+ When asked to check code against a specification: read the spec, then the
152+ files you are given. Answer with one line per acceptance criterion:
153+ `A1 — met | not met | cannot tell — <file:line or reason>`, then a short
154+ list of anything the code does that the spec does not ask for. Judge only
155+ from what you read.
156+
157+ RULES
158+ - No greeting, no preamble, no closing remark: the document only.
159+ - Answer in English.
added mini-mes/riker/agent.riker.yaml +189 -0
new file mode 100644
@@ -0,0 +1,189 @@
1+# Riker — the coordinator. A small, fast model that talks with you and hands
2+# the work to two specialists through `mm --ask` (called from its skills):
3+#
4+# milo — the specifier (Gemma 4 26B-A4B, reasoning on): turns a request
5+# into a written specification, then checks code against it.
6+# homer — the coder (Qwen3-Coder-Next 80B-A3B): implements a specification.
7+#
8+# The hand-off is FILE-based, in the project's specs/ directory:
9+# specs/<slug>.brief.md written by riker (what the user asked)
10+# specs/<slug>.spec.md written by milo (the specification)
11+# code written by homer (from the spec)
12+# Nobody has to quote a long text on a command line, and every step leaves a
13+# file you can read, edit, or hand to someone else.
14+#
15+# Run it FROM THE PROJECT to work on — milo and homer work in the same
16+# directory as riker's bash:
17+#
18+# cd ~/src/my-project
19+# mm -config /path/to/mini-mes/riker/agent.riker.yaml
20+#
21+# Memory: up to three models loaded at once in llmman (~5 + ~16 + ~48 GB at
22+# Q4). llmman unloads a model after five idle minutes.
23+
24+# ─── Model and server ────────────────────────────────────────────────────────
25+
26+# llmman: OpenAI API under /v1, one llama-server per model, the served window
27+# read from /api/ps, a missing model pulled on the first request.
28+provider: llmman
29+
30+# Gemma 4 E4B (7.5B parameters, ~4B active per token): quick answers, good
31+# enough to pick a skill and run one command. It does not design or code.
32+model: hf.co/unsloth/gemma-4-E4B-it-GGUF:Q4_K_M
33+
34+# `llmman serve`'s default bind, then the host's llmman seen from a Docker
35+# sandbox when the first does not answer within 2 s.
36+baseUrl: http://127.0.0.1:17434/v1
37+fallback: http://host.docker.internal:17434/v1
38+
39+# The agents riker can ask. Names become /ask-milo, /ask-homer (and
40+# /ask-with-context-…) for YOU to type, and `"$MM_BIN" --ask <name>` for the
41+# scripts in bin/. Paths are relative to this file.
42+mmConfigs:
43+ milo: agent.milo.yaml
44+ homer: agent.homer.yaml
45+
46+# Tokens served. 0 = ask llmman once the model is loaded (131,072 for this
47+# model, its trained maximum, unless LLMMAN_CONTEXT_LENGTH says less).
48+contextWindow: 0
49+
50+# ─── Generation ──────────────────────────────────────────────────────────────
51+
52+sampling:
53+ # Gemma's own metadata recommends temp 1.0 / top_p 0.95 / top_k 64 for
54+ # chat. A coordinator must copy commands and file names exactly, so the
55+ # temperature is lowered; top_p / top_k stay as Gemma recommends.
56+ temperature: 0.3
57+ top_p: 0.95
58+ top_k: 64
59+
60+ # Riker's replies are short: a tool call, or a summary.
61+ max_tokens: 4096
62+
63+ # One tool call at a time: write the brief, THEN ask milo.
64+ parallel_tool_calls: false
65+
66+ # Gemma 4's template reads `enable_thinking` and defaults it to false
67+ # (verified on the GGUF served by llmman). Kept off: routing to a skill
68+ # needs no deliberation, and every second counts on a coordinator.
69+ chat_template_kwargs:
70+ enable_thinking: true
71+
72+# Display of the reasoning, if you turn it on above.
73+showThinking: true
74+
75+# ─── Timeouts ────────────────────────────────────────────────────────────────
76+
77+# One bash command — that is, one whole `--ask` to milo or homer — may run
78+# this long. homer implementing a spec on a laptop (load ~48 GB, then many
79+# edit/build/test round trips) can take a quarter of an hour.
80+bashTimeout: 30m
81+
82+# Silence tolerated between two tokens. It keeps counting while a bash command
83+# runs, so it must be at least bashTimeout. The price: a genuinely hung
84+# generation of riker is detected only after 30 minutes.
85+watchdogTimeout: 30m
86+
87+# Silence tolerated while the server reads the prompt (and loads the model on
88+# the first question). Progress reports restart it.
89+firstTokenTimeout: 3m
90+
91+# ─── Agent loop ──────────────────────────────────────────────────────────────
92+
93+# Round trips per question. The longest path — brief, milo, read, homer,
94+# milo check — is about ten.
95+maxTurns: 20
96+
97+# Characters of a tool result handed back to riker. A spec printed after milo
98+# writes it, or homer's report, fits in 16000.
99+maxOutput: 16000
100+
101+# Lines of a command's output echoed in the terminal; the numbered list of
102+# commands after each answer.
103+previewLines: 20
104+displayCommands: true
105+
106+# ─── Tools ───────────────────────────────────────────────────────────────────
107+
108+# false: every bash call and every file write waits for your answer —
109+# [a] once, [s] this tool for the session, [r] reject, [n] never.
110+# Each hand-off to milo or homer is a bash call, so you approve each one, and
111+# you see the exact command first. Calls MILO makes through `--ask` follow
112+# this setting too: his writes are refused, which keeps him read-only.
113+# HOMER is started with AGENT_YOLO=true by his skill: once you approve the
114+# hand-off, he edits and runs commands without asking — that is his job.
115+# With `mm -p` nobody can answer: run with AGENT_YOLO=true, knowingly.
116+yolo: false
117+
118+# bash: runs the hand-off scripts in bin/ (specify.sh, implement.sh,
119+# check.sh), which call `"$MM_BIN" --ask …`. A small model copies one short
120+# command reliably; it did NOT copy the raw --ask line (it dropped quotes and
121+# AGENT_YOLO=true on a first run).
122+bashTool: true
123+
124+# read_file / write_file / edit_file: riker writes the BRIEF with write_file
125+# (no quoting problems, unlike a long -p "…"). It never writes code.
126+editTools: true
127+
128+# No plan tool, no web, no language server: fewer tools = fewer wrong picks
129+# for a small model.
130+planTool: false
131+fetchContentTool: false
132+
133+# ─── Skills ──────────────────────────────────────────────────────────────────
134+
135+# In the terminal, a relative path is resolved from the directory mm starts
136+# in (your project), so this one is absolute. Adjust it if you move the
137+# repository.
138+skillsDir: /Users/k33g/kDrive/Rickub/bots-garden/mini-me/mini-mes/riker/skills
139+
140+# ─── Memory ──────────────────────────────────────────────────────────────────
141+
142+# Conversations saved per project under .mm/sessions (milo and homer never
143+# write session files: an asked agent runs with sessions off).
144+sessions:
145+ enabled: true
146+ dir: .mm/sessions
147+
148+context:
149+ enabled: true
150+ # 50 % of 131k ≈ 65k tokens: plenty for a coordinator, which keeps the
151+ # details in specs/ files, not in its history.
152+ threshold: 50
153+ maxMessages: 80
154+ keepLastTurns: 3
155+ # Reasoning is forced off for the summary whatever `sampling` says.
156+ summaryMaxTokens: 1200
157+ showStats: true
158+
159+# ─── Identity ────────────────────────────────────────────────────────────────
160+
161+acp:
162+ name: riker
163+ title: Riker (coordinator)
164+
165+system: |
166+ Your name is Riker. You coordinate two specialists:
167+ - milo writes specifications and checks code against them;
168+ - homer writes code from a specification.
169+ You do not design and you do not write code yourself.
170+
171+ HOW YOU WORK
172+ You have skills, listed in the `read_skill` tool. For any request to
173+ specify, design, build, implement, code, fix or check something, call
174+ `read_skill` FIRST with the matching skill, then follow it step by step.
175+ The skills tell you the exact commands to run with your `bash` tool.
176+
177+ For a simple question (what is in specs/, what milo said), answer it
178+ yourself, with a command if you need to read something.
179+
180+ RULES
181+ - Run each hand-off command ONCE. What it prints is the answer: never run
182+ it again to get a different one, never answer in milo's or homer's place.
183+ - If a command prints `[ask: …]`, the agent failed: tell the user that line.
184+ - Never state what a file contains unless a command in this answer read it.
185+ - Write only briefs, with `write_file`, under specs/. Never edit code.
186+ - Never run git commands unless the user asks.
187+ - Answer in the language the user wrote in — French if they wrote French —
188+ even though milo and homer answer you in English. A few lines: who did
189+ what, which files, what is next.
new file mode 100644
@@ -0,0 +1,189 @@
1+# Riker — the coordinator. A small, fast model that talks with you and hands
2+# the work to two specialists through `mm --ask` (called from its skills):
3+#
4+# milo — the specifier (Gemma 4 26B-A4B, reasoning on): turns a request
5+# into a written specification, then checks code against it.
6+# homer — the coder (Qwen3-Coder-Next 80B-A3B): implements a specification.
7+#
8+# The hand-off is FILE-based, in the project's specs/ directory:
9+# specs/<slug>.brief.md written by riker (what the user asked)
10+# specs/<slug>.spec.md written by milo (the specification)
11+# code written by homer (from the spec)
12+# Nobody has to quote a long text on a command line, and every step leaves a
13+# file you can read, edit, or hand to someone else.
14+#
15+# Run it FROM THE PROJECT to work on — milo and homer work in the same
16+# directory as riker's bash:
17+#
18+# cd ~/src/my-project
19+# mm -config /path/to/mini-mes/riker/agent.riker.yaml
20+#
21+# Memory: up to three models loaded at once in llmman (~5 + ~16 + ~48 GB at
22+# Q4). llmman unloads a model after five idle minutes.
23+
24+# ─── Model and server ────────────────────────────────────────────────────────
25+
26+# llmman: OpenAI API under /v1, one llama-server per model, the served window
27+# read from /api/ps, a missing model pulled on the first request.
28+provider: llmman
29+
30+# Gemma 4 E4B (7.5B parameters, ~4B active per token): quick answers, good
31+# enough to pick a skill and run one command. It does not design or code.
32+model: hf.co/unsloth/gemma-4-E4B-it-GGUF:Q4_K_M
33+
34+# `llmman serve`'s default bind, then the host's llmman seen from a Docker
35+# sandbox when the first does not answer within 2 s.
36+baseUrl: http://127.0.0.1:17434/v1
37+fallback: http://host.docker.internal:17434/v1
38+
39+# The agents riker can ask. Names become /ask-milo, /ask-homer (and
40+# /ask-with-context-…) for YOU to type, and `"$MM_BIN" --ask <name>` for the
41+# scripts in bin/. Paths are relative to this file.
42+mmConfigs:
43+ milo: agent.milo.yaml
44+ homer: agent.homer.yaml
45+
46+# Tokens served. 0 = ask llmman once the model is loaded (131,072 for this
47+# model, its trained maximum, unless LLMMAN_CONTEXT_LENGTH says less).
48+contextWindow: 0
49+
50+# ─── Generation ──────────────────────────────────────────────────────────────
51+
52+sampling:
53+ # Gemma's own metadata recommends temp 1.0 / top_p 0.95 / top_k 64 for
54+ # chat. A coordinator must copy commands and file names exactly, so the
55+ # temperature is lowered; top_p / top_k stay as Gemma recommends.
56+ temperature: 0.3
57+ top_p: 0.95
58+ top_k: 64
59+
60+ # Riker's replies are short: a tool call, or a summary.
61+ max_tokens: 4096
62+
63+ # One tool call at a time: write the brief, THEN ask milo.
64+ parallel_tool_calls: false
65+
66+ # Gemma 4's template reads `enable_thinking` and defaults it to false
67+ # (verified on the GGUF served by llmman). Kept off: routing to a skill
68+ # needs no deliberation, and every second counts on a coordinator.
69+ chat_template_kwargs:
70+ enable_thinking: true
71+
72+# Display of the reasoning, if you turn it on above.
73+showThinking: true
74+
75+# ─── Timeouts ────────────────────────────────────────────────────────────────
76+
77+# One bash command — that is, one whole `--ask` to milo or homer — may run
78+# this long. homer implementing a spec on a laptop (load ~48 GB, then many
79+# edit/build/test round trips) can take a quarter of an hour.
80+bashTimeout: 30m
81+
82+# Silence tolerated between two tokens. It keeps counting while a bash command
83+# runs, so it must be at least bashTimeout. The price: a genuinely hung
84+# generation of riker is detected only after 30 minutes.
85+watchdogTimeout: 30m
86+
87+# Silence tolerated while the server reads the prompt (and loads the model on
88+# the first question). Progress reports restart it.
89+firstTokenTimeout: 3m
90+
91+# ─── Agent loop ──────────────────────────────────────────────────────────────
92+
93+# Round trips per question. The longest path — brief, milo, read, homer,
94+# milo check — is about ten.
95+maxTurns: 20
96+
97+# Characters of a tool result handed back to riker. A spec printed after milo
98+# writes it, or homer's report, fits in 16000.
99+maxOutput: 16000
100+
101+# Lines of a command's output echoed in the terminal; the numbered list of
102+# commands after each answer.
103+previewLines: 20
104+displayCommands: true
105+
106+# ─── Tools ───────────────────────────────────────────────────────────────────
107+
108+# false: every bash call and every file write waits for your answer —
109+# [a] once, [s] this tool for the session, [r] reject, [n] never.
110+# Each hand-off to milo or homer is a bash call, so you approve each one, and
111+# you see the exact command first. Calls MILO makes through `--ask` follow
112+# this setting too: his writes are refused, which keeps him read-only.
113+# HOMER is started with AGENT_YOLO=true by his skill: once you approve the
114+# hand-off, he edits and runs commands without asking — that is his job.
115+# With `mm -p` nobody can answer: run with AGENT_YOLO=true, knowingly.
116+yolo: false
117+
118+# bash: runs the hand-off scripts in bin/ (specify.sh, implement.sh,
119+# check.sh), which call `"$MM_BIN" --ask …`. A small model copies one short
120+# command reliably; it did NOT copy the raw --ask line (it dropped quotes and
121+# AGENT_YOLO=true on a first run).
122+bashTool: true
123+
124+# read_file / write_file / edit_file: riker writes the BRIEF with write_file
125+# (no quoting problems, unlike a long -p "…"). It never writes code.
126+editTools: true
127+
128+# No plan tool, no web, no language server: fewer tools = fewer wrong picks
129+# for a small model.
130+planTool: false
131+fetchContentTool: false
132+
133+# ─── Skills ──────────────────────────────────────────────────────────────────
134+
135+# In the terminal, a relative path is resolved from the directory mm starts
136+# in (your project), so this one is absolute. Adjust it if you move the
137+# repository.
138+skillsDir: /Users/k33g/kDrive/Rickub/bots-garden/mini-me/mini-mes/riker/skills
139+
140+# ─── Memory ──────────────────────────────────────────────────────────────────
141+
142+# Conversations saved per project under .mm/sessions (milo and homer never
143+# write session files: an asked agent runs with sessions off).
144+sessions:
145+ enabled: true
146+ dir: .mm/sessions
147+
148+context:
149+ enabled: true
150+ # 50 % of 131k ≈ 65k tokens: plenty for a coordinator, which keeps the
151+ # details in specs/ files, not in its history.
152+ threshold: 50
153+ maxMessages: 80
154+ keepLastTurns: 3
155+ # Reasoning is forced off for the summary whatever `sampling` says.
156+ summaryMaxTokens: 1200
157+ showStats: true
158+
159+# ─── Identity ────────────────────────────────────────────────────────────────
160+
161+acp:
162+ name: riker
163+ title: Riker (coordinator)
164+
165+system: |
166+ Your name is Riker. You coordinate two specialists:
167+ - milo writes specifications and checks code against them;
168+ - homer writes code from a specification.
169+ You do not design and you do not write code yourself.
170+
171+ HOW YOU WORK
172+ You have skills, listed in the `read_skill` tool. For any request to
173+ specify, design, build, implement, code, fix or check something, call
174+ `read_skill` FIRST with the matching skill, then follow it step by step.
175+ The skills tell you the exact commands to run with your `bash` tool.
176+
177+ For a simple question (what is in specs/, what milo said), answer it
178+ yourself, with a command if you need to read something.
179+
180+ RULES
181+ - Run each hand-off command ONCE. What it prints is the answer: never run
182+ it again to get a different one, never answer in milo's or homer's place.
183+ - If a command prints `[ask: …]`, the agent failed: tell the user that line.
184+ - Never state what a file contains unless a command in this answer read it.
185+ - Write only briefs, with `write_file`, under specs/. Never edit code.
186+ - Never run git commands unless the user asks.
187+ - Answer in the language the user wrote in — French if they wrote French —
188+ even though milo and homer answer you in English. A few lines: who did
189+ what, which files, what is next.
added mini-mes/riker/bin/check.sh +24 -0
new file mode 100755
@@ -0,0 +1,24 @@
1+#!/usr/bin/env bash
2+# check.sh <slug> — ask milo to check the code against specs/<slug>.spec.md,
3+# using homer's report to find the files; print the verdict
4+# (specs/<slug>.check.md).
5+set -u
6+slug=${1:?usage: check.sh <slug>}
7+: "${MM_BIN:?MM_BIN is not set: run this from an mm bash tool}"
8+spec="specs/$slug.spec.md"
9+report="specs/$slug.report.md"
10+check="specs/$slug.check.md"
11+log="specs/$slug.milo.log"
12+[ -f "$spec" ] || { echo "[riker: $spec not found]"; exit 1; }
13+[ -s "$report" ] || { echo "[riker: $report not found or empty: run the implement skill first]"; exit 1; }
14+
15+"$MM_BIN" --ask milo -p "Check the implementation against $spec. Homer's report, $report, lists the files he created or changed: read it, then read those files." >"$check" 2>"$log"
16+status=$?
17+if [ "$status" -ne 0 ] || [ ! -s "$check" ]; then
18+ echo "[milo failed, exit $status]"
19+ tail -n 5 "$log"
20+ exit 1
21+fi
22+echo "Milo's check ($check):"
23+echo
24+cat "$check"
new file mode 100755
@@ -0,0 +1,24 @@
1+#!/usr/bin/env bash
2+# check.sh <slug> — ask milo to check the code against specs/<slug>.spec.md,
3+# using homer's report to find the files; print the verdict
4+# (specs/<slug>.check.md).
5+set -u
6+slug=${1:?usage: check.sh <slug>}
7+: "${MM_BIN:?MM_BIN is not set: run this from an mm bash tool}"
8+spec="specs/$slug.spec.md"
9+report="specs/$slug.report.md"
10+check="specs/$slug.check.md"
11+log="specs/$slug.milo.log"
12+[ -f "$spec" ] || { echo "[riker: $spec not found]"; exit 1; }
13+[ -s "$report" ] || { echo "[riker: $report not found or empty: run the implement skill first]"; exit 1; }
14+
15+"$MM_BIN" --ask milo -p "Check the implementation against $spec. Homer's report, $report, lists the files he created or changed: read it, then read those files." >"$check" 2>"$log"
16+status=$?
17+if [ "$status" -ne 0 ] || [ ! -s "$check" ]; then
18+ echo "[milo failed, exit $status]"
19+ tail -n 5 "$log"
20+ exit 1
21+fi
22+echo "Milo's check ($check):"
23+echo
24+cat "$check"
added mini-mes/riker/bin/implement.sh +34 -0
new file mode 100755
@@ -0,0 +1,34 @@
1+#!/usr/bin/env bash
2+# implement.sh <slug> — ask homer to implement specs/<slug>.spec.md, then
3+# print his report (specs/<slug>.report.md; all he said: .homer.out).
4+#
5+# AGENT_YOLO=true: homer's file edits and commands are allowed without a
6+# question each time. The user approved THIS command in riker; homer then
7+# works on his own.
8+set -u
9+slug=${1:?usage: implement.sh <slug>}
10+: "${MM_BIN:?MM_BIN is not set: run this from an mm bash tool}"
11+spec="specs/$slug.spec.md"
12+report="specs/$slug.report.md"
13+out="specs/$slug.homer.out"
14+log="specs/$slug.homer.log"
15+[ -f "$spec" ] || { echo "[riker: $spec not found: run the specify skill first]"; exit 1; }
16+
17+AGENT_YOLO=true "$MM_BIN" --ask homer -p "Implement the specification in $spec." >"$out" 2>"$log"
18+status=$?
19+# stdout is everything homer said during his turn; the report is its end.
20+if grep -q '^# Report' "$out"; then
21+ sed -n '/^# Report/,$p' "$out" >"$report"
22+else
23+ cp "$out" "$report"
24+fi
25+echo "Homer's activity (last lines of $log):"
26+tail -n 5 "$log"
27+echo
28+if [ "$status" -ne 0 ] || [ ! -s "$report" ]; then
29+ echo "[homer failed, exit $status]"
30+ exit 1
31+fi
32+echo "Homer's report ($report):"
33+echo
34+cat "$report"
new file mode 100755
@@ -0,0 +1,34 @@
1+#!/usr/bin/env bash
2+# implement.sh <slug> — ask homer to implement specs/<slug>.spec.md, then
3+# print his report (specs/<slug>.report.md; all he said: .homer.out).
4+#
5+# AGENT_YOLO=true: homer's file edits and commands are allowed without a
6+# question each time. The user approved THIS command in riker; homer then
7+# works on his own.
8+set -u
9+slug=${1:?usage: implement.sh <slug>}
10+: "${MM_BIN:?MM_BIN is not set: run this from an mm bash tool}"
11+spec="specs/$slug.spec.md"
12+report="specs/$slug.report.md"
13+out="specs/$slug.homer.out"
14+log="specs/$slug.homer.log"
15+[ -f "$spec" ] || { echo "[riker: $spec not found: run the specify skill first]"; exit 1; }
16+
17+AGENT_YOLO=true "$MM_BIN" --ask homer -p "Implement the specification in $spec." >"$out" 2>"$log"
18+status=$?
19+# stdout is everything homer said during his turn; the report is its end.
20+if grep -q '^# Report' "$out"; then
21+ sed -n '/^# Report/,$p' "$out" >"$report"
22+else
23+ cp "$out" "$report"
24+fi
25+echo "Homer's activity (last lines of $log):"
26+tail -n 5 "$log"
27+echo
28+if [ "$status" -ne 0 ] || [ ! -s "$report" ]; then
29+ echo "[homer failed, exit $status]"
30+ exit 1
31+fi
32+echo "Homer's report ($report):"
33+echo
34+cat "$report"
added mini-mes/riker/bin/specify.sh +29 -0
new file mode 100755
@@ -0,0 +1,29 @@
1+#!/usr/bin/env bash
2+# specify.sh <slug> — ask milo to turn specs/<slug>.brief.md into
3+# specs/<slug>.spec.md, then print the spec.
4+# Run by riker's bash tool: MM_BIN and MM_CONFIG come from mm.
5+set -u
6+slug=${1:?usage: specify.sh <slug>}
7+: "${MM_BIN:?MM_BIN is not set: run this from an mm bash tool}"
8+brief="specs/$slug.brief.md"
9+spec="specs/$slug.spec.md"
10+out="specs/$slug.milo.out"
11+log="specs/$slug.milo.log"
12+[ -f "$brief" ] || { echo "[riker: $brief not found: write the brief first]"; exit 1; }
13+
14+"$MM_BIN" --ask milo -p "Write the specification for the brief in $brief." >"$out" 2>"$log"
15+status=$?
16+# Anything milo said before the document's first "# " title is not the spec.
17+if grep -q '^# ' "$out"; then
18+ sed -n '/^# /,$p' "$out" >"$spec"
19+else
20+ cp "$out" "$spec"
21+fi
22+if [ "$status" -ne 0 ] || [ ! -s "$spec" ]; then
23+ echo "[milo failed, exit $status]"
24+ tail -n 5 "$log"
25+ exit 1
26+fi
27+echo "Milo wrote $spec:"
28+echo
29+cat "$spec"
new file mode 100755
@@ -0,0 +1,29 @@
1+#!/usr/bin/env bash
2+# specify.sh <slug> — ask milo to turn specs/<slug>.brief.md into
3+# specs/<slug>.spec.md, then print the spec.
4+# Run by riker's bash tool: MM_BIN and MM_CONFIG come from mm.
5+set -u
6+slug=${1:?usage: specify.sh <slug>}
7+: "${MM_BIN:?MM_BIN is not set: run this from an mm bash tool}"
8+brief="specs/$slug.brief.md"
9+spec="specs/$slug.spec.md"
10+out="specs/$slug.milo.out"
11+log="specs/$slug.milo.log"
12+[ -f "$brief" ] || { echo "[riker: $brief not found: write the brief first]"; exit 1; }
13+
14+"$MM_BIN" --ask milo -p "Write the specification for the brief in $brief." >"$out" 2>"$log"
15+status=$?
16+# Anything milo said before the document's first "# " title is not the spec.
17+if grep -q '^# ' "$out"; then
18+ sed -n '/^# /,$p' "$out" >"$spec"
19+else
20+ cp "$out" "$spec"
21+fi
22+if [ "$status" -ne 0 ] || [ ! -s "$spec" ]; then
23+ echo "[milo failed, exit $status]"
24+ tail -n 5 "$log"
25+ exit 1
26+fi
27+echo "Milo wrote $spec:"
28+echo
29+cat "$spec"
added mini-mes/riker/go.mod +3 -0
new file mode 100644
@@ -0,0 +1,3 @@
1+module notes
2+
3+go 1.27
new file mode 100644
@@ -0,0 +1,3 @@
1+module notes
2+
3+go 1.27
added mini-mes/riker/skills-homer/implement-spec/SKILL.md +41 -0
new file mode 100644
@@ -0,0 +1,41 @@
1+---
2+name: implement-spec
3+description: Implement a specification file (specs/<slug>.spec.md) in the current project — requirement by requirement, with tests and a build, and a final report for the coordinator.
4+keywords: implement, specification, spec, implémenter, code, requirements, build, tests
5+---
6+
7+# Implement a specification
8+
9+## Steps
10+
11+1. **Read the spec** with `read_file`. Note every requirement (R1, R2…) and acceptance criterion (A1, A2…).
12+
13+2. **Look at the project** with your `bash` tool: `ls`, then the build files (`go.mod`, `package.json`, `pyproject.toml`, `Cargo.toml`, `Makefile`…) to learn the language, the layout and the test command. Read the files the spec's Context section names. For a new project, create it the standard way for its language.
14+
15+3. **Implement, one requirement at a time**, in the spec's order: edit the code, write the test that proves it, run the narrowest build/test command. Fix until it passes, then go on. Never leave the project in a state that does not build.
16+
17+4. **Check the acceptance criteria**: run each one that is a command (the spec's examples) and compare with the expected output.
18+
19+5. **Run the full build and the full test suite** at the end. Format the code with the language's formatter if the project uses one (`gofmt`, `prettier`, `ruff format`…).
20+
21+6. **Answer with this report, and nothing else** (in English, Markdown):
22+
23+ # Report: <spec title>
24+ ## Files
25+ - created: <path> — <what>
26+ - changed: <path> — <what>
27+ ## Requirements
28+ - R1 — done | partial | not done — <one line>
29+ ## Commands
30+ - `<build command>` — ok | failed: <first error>
31+ - `<test command>` — ok (<N> tests) | failed: <first failure>
32+ ## Choices
33+ - <where the spec was silent, what you chose>
34+ ## Left to do
35+ - <anything not done, or "nothing">
36+
37+## Rules
38+
39+- The report must be true: every "ok" comes from a command you ran in this answer.
40+- Never weaken or delete a test to make it pass; if you cannot make it pass, report it.
41+- Stay inside the spec's scope; its "Out of scope" section is binding.
new file mode 100644
@@ -0,0 +1,41 @@
1+---
2+name: implement-spec
3+description: Implement a specification file (specs/<slug>.spec.md) in the current project — requirement by requirement, with tests and a build, and a final report for the coordinator.
4+keywords: implement, specification, spec, implémenter, code, requirements, build, tests
5+---
6+
7+# Implement a specification
8+
9+## Steps
10+
11+1. **Read the spec** with `read_file`. Note every requirement (R1, R2…) and acceptance criterion (A1, A2…).
12+
13+2. **Look at the project** with your `bash` tool: `ls`, then the build files (`go.mod`, `package.json`, `pyproject.toml`, `Cargo.toml`, `Makefile`…) to learn the language, the layout and the test command. Read the files the spec's Context section names. For a new project, create it the standard way for its language.
14+
15+3. **Implement, one requirement at a time**, in the spec's order: edit the code, write the test that proves it, run the narrowest build/test command. Fix until it passes, then go on. Never leave the project in a state that does not build.
16+
17+4. **Check the acceptance criteria**: run each one that is a command (the spec's examples) and compare with the expected output.
18+
19+5. **Run the full build and the full test suite** at the end. Format the code with the language's formatter if the project uses one (`gofmt`, `prettier`, `ruff format`…).
20+
21+6. **Answer with this report, and nothing else** (in English, Markdown):
22+
23+ # Report: <spec title>
24+ ## Files
25+ - created: <path> — <what>
26+ - changed: <path> — <what>
27+ ## Requirements
28+ - R1 — done | partial | not done — <one line>
29+ ## Commands
30+ - `<build command>` — ok | failed: <first error>
31+ - `<test command>` — ok (<N> tests) | failed: <first failure>
32+ ## Choices
33+ - <where the spec was silent, what you chose>
34+ ## Left to do
35+ - <anything not done, or "nothing">
36+
37+## Rules
38+
39+- The report must be true: every "ok" comes from a command you ran in this answer.
40+- Never weaken or delete a test to make it pass; if you cannot make it pass, report it.
41+- Stay inside the spec's scope; its "Out of scope" section is binding.
added mini-mes/riker/skills/build-feature/SKILL.md +30 -0
new file mode 100644
@@ -0,0 +1,30 @@
1+---
2+name: build-feature
3+description: Build something end to end with the team — Milo specifies it, Homer implements it, Milo checks the result. Use when the user asks to build, create or add something without asking for a spec first.
4+keywords: construire, créer, ajoute, fais, build, create, feature, fonctionnalité
5+---
6+
7+# Build a feature with Milo and Homer
8+
9+## When to use it
10+
11+The user asks to build, create or add something ("crée un CLI qui…", "add an endpoint that…"). For "only specify" use `specify`; for "implement this spec" use `implement`.
12+
13+## Steps
14+
15+Follow the three skills below in order. Load each one with `read_skill` when you reach it, and do exactly what it says. Use the same slug from start to end.
16+
17+1. **`specify`** — Milo writes `specs/<slug>.spec.md`.
18+ Then STOP and show the user the summary the skill asks for, unless the user said to go all the way ("sans t'arrêter", "do everything", "go ahead and build it"). A wrong spec costs less to fix now than after Homer's work.
19+
20+2. **`implement`** — when the user approves (or asked to go all the way), Homer implements the spec.
21+
22+3. **`check-against-spec`** — Milo checks Homer's code against the spec.
23+
24+## Final report
25+
26+In the user's language, short:
27+- the spec file and its goal;
28+- the files Homer created or changed, with his build and test results;
29+- Milo's verdict: criteria met / not met;
30+- what is left, if anything, and the next step you propose.
new file mode 100644
@@ -0,0 +1,30 @@
1+---
2+name: build-feature
3+description: Build something end to end with the team — Milo specifies it, Homer implements it, Milo checks the result. Use when the user asks to build, create or add something without asking for a spec first.
4+keywords: construire, créer, ajoute, fais, build, create, feature, fonctionnalité
5+---
6+
7+# Build a feature with Milo and Homer
8+
9+## When to use it
10+
11+The user asks to build, create or add something ("crée un CLI qui…", "add an endpoint that…"). For "only specify" use `specify`; for "implement this spec" use `implement`.
12+
13+## Steps
14+
15+Follow the three skills below in order. Load each one with `read_skill` when you reach it, and do exactly what it says. Use the same slug from start to end.
16+
17+1. **`specify`** — Milo writes `specs/<slug>.spec.md`.
18+ Then STOP and show the user the summary the skill asks for, unless the user said to go all the way ("sans t'arrêter", "do everything", "go ahead and build it"). A wrong spec costs less to fix now than after Homer's work.
19+
20+2. **`implement`** — when the user approves (or asked to go all the way), Homer implements the spec.
21+
22+3. **`check-against-spec`** — Milo checks Homer's code against the spec.
23+
24+## Final report
25+
26+In the user's language, short:
27+- the spec file and its goal;
28+- the files Homer created or changed, with his build and test results;
29+- Milo's verdict: criteria met / not met;
30+- what is left, if anything, and the next step you propose.
added mini-mes/riker/skills/check-against-spec/SKILL.md +21 -0
new file mode 100644
@@ -0,0 +1,21 @@
1+---
2+name: check-against-spec
3+description: Have Milo check the code Homer wrote against its specification, acceptance criterion by acceptance criterion.
4+keywords: vérifier, check, contrôle, conforme, valider, verify, acceptance, review
5+---
6+
7+# Check the code against the spec with Milo
8+
9+## When to use it
10+
11+After `implement`, or when the user asks whether the code matches the specification. Step 3 of the `build-feature` skill.
12+
13+## Steps
14+
15+1. **Ask Milo.** Call your `bash` tool with exactly this command, replacing only `<slug>`:
16+
17+ bash /Users/k33g/kDrive/Rickub/bots-garden/mini-me/mini-mes/riker/bin/check.sh <slug>
18+
19+ Milo reads the spec, Homer's report `specs/<slug>.report.md`, and the files it lists. Run it ONCE. It prints one line per acceptance criterion: met, not met, or cannot tell, saved in `specs/<slug>.check.md`. If it prints `[milo failed …]` or `[riker: …]`, tell the user those lines.
20+
21+2. **Report.** Tell the user how many criteria are met, and list the others with Milo's reason. If some are "not met", offer to send them back to Homer: then use the `implement` skill again — Homer reads the spec and the code, and finishes the work.
new file mode 100644
@@ -0,0 +1,21 @@
1+---
2+name: check-against-spec
3+description: Have Milo check the code Homer wrote against its specification, acceptance criterion by acceptance criterion.
4+keywords: vérifier, check, contrôle, conforme, valider, verify, acceptance, review
5+---
6+
7+# Check the code against the spec with Milo
8+
9+## When to use it
10+
11+After `implement`, or when the user asks whether the code matches the specification. Step 3 of the `build-feature` skill.
12+
13+## Steps
14+
15+1. **Ask Milo.** Call your `bash` tool with exactly this command, replacing only `<slug>`:
16+
17+ bash /Users/k33g/kDrive/Rickub/bots-garden/mini-me/mini-mes/riker/bin/check.sh <slug>
18+
19+ Milo reads the spec, Homer's report `specs/<slug>.report.md`, and the files it lists. Run it ONCE. It prints one line per acceptance criterion: met, not met, or cannot tell, saved in `specs/<slug>.check.md`. If it prints `[milo failed …]` or `[riker: …]`, tell the user those lines.
20+
21+2. **Report.** Tell the user how many criteria are met, and list the others with Milo's reason. If some are "not met", offer to send them back to Homer: then use the `implement` skill again — Homer reads the spec and the code, and finishes the work.
added mini-mes/riker/skills/implement/SKILL.md +26 -0
new file mode 100644
@@ -0,0 +1,26 @@
1+---
2+name: implement
3+description: Have Homer implement an existing specification file (specs/<slug>.spec.md) — he writes the code and tests in the project and reports what he did.
4+keywords: implémenter, implement, code, coder, développer, programmer, réalise, homer
5+---
6+
7+# Implement with Homer
8+
9+## When to use it
10+
11+A specification exists in `specs/` and the user wants it implemented ("vas-y", "implement it", "code it"). Also step 2 of the `build-feature` skill. If there is no spec yet, use the `specify` skill first.
12+
13+## Steps
14+
15+1. **Find the spec.** If you do not know the slug, call your `bash` tool with: `ls specs/*.spec.md`. If several exist and the user did not say which, ask.
16+
17+2. **Ask Homer.** Call your `bash` tool with exactly this command, replacing only `<slug>`:
18+
19+ bash /Users/k33g/kDrive/Rickub/bots-garden/mini-me/mini-mes/riker/bin/implement.sh <slug>
20+
21+ - The script lets Homer edit files and run commands without asking at each step: the user approves this one command, then Homer works.
22+ - It can take a long time (up to 30 minutes). Run it ONCE. Never run it again because it was slow.
23+ - It prints the last lines of Homer's activity, then his report, saved in `specs/<slug>.report.md`.
24+ - If it prints `[homer failed …]`, tell the user the lines it printed.
25+
26+3. **Report.** Tell the user, in their language: the files Homer created or changed, the commands he ran and their results (build, tests), what he chose where the spec was silent, and what is left. Quote his results; do not add claims of your own. Offer to have Milo check the code (the `check-against-spec` skill).
new file mode 100644
@@ -0,0 +1,26 @@
1+---
2+name: implement
3+description: Have Homer implement an existing specification file (specs/<slug>.spec.md) — he writes the code and tests in the project and reports what he did.
4+keywords: implémenter, implement, code, coder, développer, programmer, réalise, homer
5+---
6+
7+# Implement with Homer
8+
9+## When to use it
10+
11+A specification exists in `specs/` and the user wants it implemented ("vas-y", "implement it", "code it"). Also step 2 of the `build-feature` skill. If there is no spec yet, use the `specify` skill first.
12+
13+## Steps
14+
15+1. **Find the spec.** If you do not know the slug, call your `bash` tool with: `ls specs/*.spec.md`. If several exist and the user did not say which, ask.
16+
17+2. **Ask Homer.** Call your `bash` tool with exactly this command, replacing only `<slug>`:
18+
19+ bash /Users/k33g/kDrive/Rickub/bots-garden/mini-me/mini-mes/riker/bin/implement.sh <slug>
20+
21+ - The script lets Homer edit files and run commands without asking at each step: the user approves this one command, then Homer works.
22+ - It can take a long time (up to 30 minutes). Run it ONCE. Never run it again because it was slow.
23+ - It prints the last lines of Homer's activity, then his report, saved in `specs/<slug>.report.md`.
24+ - If it prints `[homer failed …]`, tell the user the lines it printed.
25+
26+3. **Report.** Tell the user, in their language: the files Homer created or changed, the commands he ran and their results (build, tests), what he chose where the spec was silent, and what is left. Quote his results; do not add claims of your own. Offer to have Milo check the code (the `check-against-spec` skill).
added mini-mes/riker/skills/specify/SKILL.md +37 -0
new file mode 100644
@@ -0,0 +1,37 @@
1+---
2+name: specify
3+description: Have Milo write a specification for a feature, a change or a program the user describes — a brief goes in specs/, Milo's spec comes back as specs/<slug>.spec.md.
4+keywords: spécifier, spécification, spec, specify, design, conçois, cahier des charges, besoin
5+---
6+
7+# Specify with Milo
8+
9+## When to use it
10+
11+The user describes something to build or change and wants it specified, designed, or "thought through" first. Also step 1 of the `build-feature` skill.
12+
13+## Steps
14+
15+1. **Pick a slug**: two to four lowercase words joined by `-`, from the request (`csv-export`, `login-rate-limit`). Use the same slug for every file of this request.
16+
17+2. **Write the brief** with your `write_file` tool, path `specs/<slug>.brief.md`, in English:
18+
19+ # Brief: <title>
20+ ## Request
21+ <the user's request, complete, in their words translated to English>
22+ ## Constraints
23+ <language, libraries, files to change, anything the user said; "none stated" otherwise>
24+ ## Files to read
25+ <paths of existing files that matter, one per line; "none" for a new project>
26+
27+ To find the files to list, you may first call your `bash` tool with: `ls; find . -maxdepth 2 -type f -not -path './.git/*' -not -path './.mm/*' | head -50`
28+
29+3. **Ask Milo.** Call your `bash` tool with exactly this command, replacing only `<slug>`:
30+
31+ bash /Users/k33g/kDrive/Rickub/bots-garden/mini-me/mini-mes/riker/bin/specify.sh <slug>
32+
33+ - It can take several minutes. Run it ONCE.
34+ - It prints the specification Milo wrote, saved in `specs/<slug>.spec.md`.
35+ - If it prints `[milo failed …]`, tell the user the lines it printed. Do not write a spec yourself.
36+
37+4. **Report and stop.** Tell the user, in their language: the file `specs/<slug>.spec.md`, the goal in one sentence, the number of requirements and acceptance criteria, and Milo's open questions with their defaults. Ask whether to implement it (the `implement` skill) or change something first. Do not implement it in the same answer unless the user already asked you to build it.
new file mode 100644
@@ -0,0 +1,37 @@
1+---
2+name: specify
3+description: Have Milo write a specification for a feature, a change or a program the user describes — a brief goes in specs/, Milo's spec comes back as specs/<slug>.spec.md.
4+keywords: spécifier, spécification, spec, specify, design, conçois, cahier des charges, besoin
5+---
6+
7+# Specify with Milo
8+
9+## When to use it
10+
11+The user describes something to build or change and wants it specified, designed, or "thought through" first. Also step 1 of the `build-feature` skill.
12+
13+## Steps
14+
15+1. **Pick a slug**: two to four lowercase words joined by `-`, from the request (`csv-export`, `login-rate-limit`). Use the same slug for every file of this request.
16+
17+2. **Write the brief** with your `write_file` tool, path `specs/<slug>.brief.md`, in English:
18+
19+ # Brief: <title>
20+ ## Request
21+ <the user's request, complete, in their words translated to English>
22+ ## Constraints
23+ <language, libraries, files to change, anything the user said; "none stated" otherwise>
24+ ## Files to read
25+ <paths of existing files that matter, one per line; "none" for a new project>
26+
27+ To find the files to list, you may first call your `bash` tool with: `ls; find . -maxdepth 2 -type f -not -path './.git/*' -not -path './.mm/*' | head -50`
28+
29+3. **Ask Milo.** Call your `bash` tool with exactly this command, replacing only `<slug>`:
30+
31+ bash /Users/k33g/kDrive/Rickub/bots-garden/mini-me/mini-mes/riker/bin/specify.sh <slug>
32+
33+ - It can take several minutes. Run it ONCE.
34+ - It prints the specification Milo wrote, saved in `specs/<slug>.spec.md`.
35+ - If it prints `[milo failed …]`, tell the user the lines it printed. Do not write a spec yourself.
36+
37+4. **Report and stop.** Tell the user, in their language: the file `specs/<slug>.spec.md`, the goal in one sentence, the number of requirements and acceptance criteria, and Milo's open questions with their defaults. Ask whether to implement it (the `implement` skill) or change something first. Do not implement it in the same answer unless the user already asked you to build it.
added mini-mes/riker/specs/crud-notes-webapp.brief.md +7 -0
new file mode 100644
@@ -0,0 +1,7 @@
1+# Brief: CRUD Webapp for Notes
2+## Request
3+Create a CRUD webapp to handle a list of notes.
4+## Constraints
5+Backend must be written in Go.
6+## Files to read
7+none
new file mode 100644
@@ -0,0 +1,7 @@
1+# Brief: CRUD Webapp for Notes
2+## Request
3+Create a CRUD webapp to handle a list of notes.
4+## Constraints
5+Backend must be written in Go.
6+## Files to read
7+none
added mini-mes/riker/specs/crud-notes-webapp.homer.log +9 -0
new file mode 100644
@@ -0,0 +1,9 @@
1+🗣 asking homer (llmman/hf.co/unsloth/Qwen3.8-27B-GGUF:Q4_K_M)…
2+🛠️ homer · read_skill: implement-spec
3+🛠️ homer · read_file: specs/crud-notes-webapp.spec.md
4+🛠️ homer · bash: ls -la && echo "---" && find . -type f -not -path './.git/*' | head -50
5+🛠️ homer · bash: go version && echo "---GOPATH---" && go env GOPATH GOMODCACHE GOPROXY && echo "---which uuid libs---" && ls $(go env GOMODCACHE) 2>/dev/null | head
6+🛠️ homer · bash: ls $(go env GOMODCACHE)/github.com/google/ 2>/dev/null | grep -i uuid; echo "---"; ls $(go env GOMODCACHE)/github.com/ 2>/dev/null | head -40
7+🛠️ homer · write_file: go.mod (22 bytes)
8+🛠️ homer · bash: cd /Users/k33g/kDrive/Rickub/bots-garden/mini-me/mini-mes/riker && ls -la && echo "---GO---" && go version && echo "---uuid available?---" && ls /Users/k33g/go/pkg/mod/github.com/google/ 2>/dev/null | grep uuid
9+[ask: interrupted]
new file mode 100644
@@ -0,0 +1,9 @@
1+🗣 asking homer (llmman/hf.co/unsloth/Qwen3.8-27B-GGUF:Q4_K_M)…
2+🛠️ homer · read_skill: implement-spec
3+🛠️ homer · read_file: specs/crud-notes-webapp.spec.md
4+🛠️ homer · bash: ls -la && echo "---" && find . -type f -not -path './.git/*' | head -50
5+🛠️ homer · bash: go version && echo "---GOPATH---" && go env GOPATH GOMODCACHE GOPROXY && echo "---which uuid libs---" && ls $(go env GOMODCACHE) 2>/dev/null | head
6+🛠️ homer · bash: ls $(go env GOMODCACHE)/github.com/google/ 2>/dev/null | grep -i uuid; echo "---"; ls $(go env GOMODCACHE)/github.com/ 2>/dev/null | head -40
7+🛠️ homer · write_file: go.mod (22 bytes)
8+🛠️ homer · bash: cd /Users/k33g/kDrive/Rickub/bots-garden/mini-me/mini-mes/riker && ls -la && echo "---GO---" && go version && echo "---uuid available?---" && ls /Users/k33g/go/pkg/mod/github.com/google/ 2>/dev/null | grep uuid
9+[ask: interrupted]
added mini-mes/riker/specs/crud-notes-webapp.homer.out +6 -0
new file mode 100644
@@ -0,0 +1,6 @@
1+Now let me look at the project structure.
2+
3+This is a new project. Let me check the Go environment.
4+
5+This is a new project. Go 1.27 is available (supports `http.ServeMux` routing patterns and `PathValue`), and `github.com/google/uuid` is in the module cache. Let me set up the project.
6+
new file mode 100644
@@ -0,0 +1,6 @@
1+Now let me look at the project structure.
2+
3+This is a new project. Let me check the Go environment.
4+
5+This is a new project. Go 1.27 is available (supports `http.ServeMux` routing patterns and `PathValue`), and `github.com/google/uuid` is in the module cache. Let me set up the project.
6+
added mini-mes/riker/specs/crud-notes-webapp.milo.log +2 -0
new file mode 100644
@@ -0,0 +1,2 @@
1+🗣 asking milo (llmman/hf.co/unsloth/gemma-4-26B-A4B-it-GGUF:Q4_K_M)…
2+🛠️ milo · read_file: specs/crud-notes-webapp.brief.md
new file mode 100644
@@ -0,0 +1,2 @@
1+🗣 asking milo (llmman/hf.co/unsloth/gemma-4-26B-A4B-it-GGUF:Q4_K_M)…
2+🛠️ milo · read_file: specs/crud-notes-webapp.brief.md
added mini-mes/riker/specs/crud-notes-webapp.milo.out +67 -0
new file mode 100644
@@ -0,0 +1,67 @@
1+# CRUD Notes Webapp Specification
2+
3+## Goal
4+Implement a RESTful web application in Go that allows users to perform CRUD operations on a collection of notes. This backend will serve as the data provider for a notes management system.
5+
6+## Context
7+This is a new project. There is no existing code.
8+
9+## Requirements
10+R1: The system shall provide an endpoint to create a new note.
11+R2: The system shall provide an endpoint to retrieve a list of all existing notes.
12+R3: The system shall provide an endpoint to retrieve a single note by its unique ID.
13+R4: The system shall provide an endpoint to update an existing note.
14+R5: The system shall provide an endpoint to delete an existing note.
15+R6: The system shall store notes in memory during the application lifecycle.
16+R7: The backend shall be implemented in Go.
17+
18+## Interfaces
19+
20+### Data Model
21+`Note` struct:
22+```go
23+type Note struct {
24+ ID string `json:"id"`
25+ Title string `json:"title"`
26+ Content string `json:"content"`
27+ CreatedAt time.Time `json:"created_at"`
28+ UpdatedAt time.Time `json:"updated_at"`
29+}
30+```
31+
32+### HTTP API
33+- `POST /notes`: Create a note.
34+ - Request Body: `{"title": string, "content": string}`
35+ - Response: `201 Created` with the created `Note` object.
36+- `GET /notes`: List all notes.
37+ - Response: `200 OK` with a JSON array of `Note` objects.
38+- `GET /notes/{id}`: Get a specific note.
39+ - Response: `200 OK` with the `Note` object or `404 Not Found`.
40+- `PUT /notes/{id}`: Update an existing note.
41+ - Request Body: `{"title": string, "content": string}`
42+ - Response: `200 OK` with the updated `Note` object or `404 Not Found`.
43+- `DELETE /notes/{id}`: Delete a note.
44+ - Response: `204 No Content` or `404 Not Found`.
45+
46+## Edge cases and errors
47+- E1: Request body contains invalid JSON: Return `400 Bad Request`.
48+- E2: Note creation request missing required fields (title/content): Return `400 Bad Request`.
49+- E3: Requesting or updating a non-existent ID: Return `404 Not Found`.
50+- E4: Deleting a non-existent ID: Return `404 Not Found`.
51+
52+## Acceptance criteria
53+A1: Given a running server, When `POST /notes` is called with `{"title": "Meeting", "content": "Discuss specs"}`, Then the response is `201 Created` and the body contains a note with a generated ID.
54+A2: Given notes exist, When `GET /notes` is called, Then the response is `200 OK` and the body contains a list including those notes.
55+A3: Given a note exists, When `GET /notes/{id}` is called with that ID, Then the response is `200 OK` and the body matches the note.
56+A4: Given a note exists, When `PUT /notes/{id}` is called with `{"title": "New Title", "content": "New Content"}`, Then the response is `200 OK` and the note reflects the changes.
57+A5: Given a note exists, When `DELETE /notes/{id}` is called, Then the response is `204 No Content` and subsequent `GET` requests for that ID return `404 Not Found`.
58+
59+## Out of scope
60+- Frontend/UI implementation.
61+- Persistent database storage (e.g., PostgreSQL, SQLite).
62+- User authentication or authorization.
63+- Advanced filtering or search functionality.
64+
65+## Open questions
66+- Q1: Should IDs be UUIDs or incremental integers? Default: UUIDs (strings).
67+- Q2: Should the API support partial updates (PATCH)? Default: No, only full updates via PUT.
new file mode 100644
@@ -0,0 +1,67 @@
1+# CRUD Notes Webapp Specification
2+
3+## Goal
4+Implement a RESTful web application in Go that allows users to perform CRUD operations on a collection of notes. This backend will serve as the data provider for a notes management system.
5+
6+## Context
7+This is a new project. There is no existing code.
8+
9+## Requirements
10+R1: The system shall provide an endpoint to create a new note.
11+R2: The system shall provide an endpoint to retrieve a list of all existing notes.
12+R3: The system shall provide an endpoint to retrieve a single note by its unique ID.
13+R4: The system shall provide an endpoint to update an existing note.
14+R5: The system shall provide an endpoint to delete an existing note.
15+R6: The system shall store notes in memory during the application lifecycle.
16+R7: The backend shall be implemented in Go.
17+
18+## Interfaces
19+
20+### Data Model
21+`Note` struct:
22+```go
23+type Note struct {
24+ ID string `json:"id"`
25+ Title string `json:"title"`
26+ Content string `json:"content"`
27+ CreatedAt time.Time `json:"created_at"`
28+ UpdatedAt time.Time `json:"updated_at"`
29+}
30+```
31+
32+### HTTP API
33+- `POST /notes`: Create a note.
34+ - Request Body: `{"title": string, "content": string}`
35+ - Response: `201 Created` with the created `Note` object.
36+- `GET /notes`: List all notes.
37+ - Response: `200 OK` with a JSON array of `Note` objects.
38+- `GET /notes/{id}`: Get a specific note.
39+ - Response: `200 OK` with the `Note` object or `404 Not Found`.
40+- `PUT /notes/{id}`: Update an existing note.
41+ - Request Body: `{"title": string, "content": string}`
42+ - Response: `200 OK` with the updated `Note` object or `404 Not Found`.
43+- `DELETE /notes/{id}`: Delete a note.
44+ - Response: `204 No Content` or `404 Not Found`.
45+
46+## Edge cases and errors
47+- E1: Request body contains invalid JSON: Return `400 Bad Request`.
48+- E2: Note creation request missing required fields (title/content): Return `400 Bad Request`.
49+- E3: Requesting or updating a non-existent ID: Return `404 Not Found`.
50+- E4: Deleting a non-existent ID: Return `404 Not Found`.
51+
52+## Acceptance criteria
53+A1: Given a running server, When `POST /notes` is called with `{"title": "Meeting", "content": "Discuss specs"}`, Then the response is `201 Created` and the body contains a note with a generated ID.
54+A2: Given notes exist, When `GET /notes` is called, Then the response is `200 OK` and the body contains a list including those notes.
55+A3: Given a note exists, When `GET /notes/{id}` is called with that ID, Then the response is `200 OK` and the body matches the note.
56+A4: Given a note exists, When `PUT /notes/{id}` is called with `{"title": "New Title", "content": "New Content"}`, Then the response is `200 OK` and the note reflects the changes.
57+A5: Given a note exists, When `DELETE /notes/{id}` is called, Then the response is `204 No Content` and subsequent `GET` requests for that ID return `404 Not Found`.
58+
59+## Out of scope
60+- Frontend/UI implementation.
61+- Persistent database storage (e.g., PostgreSQL, SQLite).
62+- User authentication or authorization.
63+- Advanced filtering or search functionality.
64+
65+## Open questions
66+- Q1: Should IDs be UUIDs or incremental integers? Default: UUIDs (strings).
67+- Q2: Should the API support partial updates (PATCH)? Default: No, only full updates via PUT.
added mini-mes/riker/specs/crud-notes-webapp.spec.md +67 -0
new file mode 100644
@@ -0,0 +1,67 @@
1+# CRUD Notes Webapp Specification
2+
3+## Goal
4+Implement a RESTful web application in Go that allows users to perform CRUD operations on a collection of notes. This backend will serve as the data provider for a notes management system.
5+
6+## Context
7+This is a new project. There is no existing code.
8+
9+## Requirements
10+R1: The system shall provide an endpoint to create a new note.
11+R2: The system shall provide an endpoint to retrieve a list of all existing notes.
12+R3: The system shall provide an endpoint to retrieve a single note by its unique ID.
13+R4: The system shall provide an endpoint to update an existing note.
14+R5: The system shall provide an endpoint to delete an existing note.
15+R6: The system shall store notes in memory during the application lifecycle.
16+R7: The backend shall be implemented in Go.
17+
18+## Interfaces
19+
20+### Data Model
21+`Note` struct:
22+```go
23+type Note struct {
24+ ID string `json:"id"`
25+ Title string `json:"title"`
26+ Content string `json:"content"`
27+ CreatedAt time.Time `json:"created_at"`
28+ UpdatedAt time.Time `json:"updated_at"`
29+}
30+```
31+
32+### HTTP API
33+- `POST /notes`: Create a note.
34+ - Request Body: `{"title": string, "content": string}`
35+ - Response: `201 Created` with the created `Note` object.
36+- `GET /notes`: List all notes.
37+ - Response: `200 OK` with a JSON array of `Note` objects.
38+- `GET /notes/{id}`: Get a specific note.
39+ - Response: `200 OK` with the `Note` object or `404 Not Found`.
40+- `PUT /notes/{id}`: Update an existing note.
41+ - Request Body: `{"title": string, "content": string}`
42+ - Response: `200 OK` with the updated `Note` object or `404 Not Found`.
43+- `DELETE /notes/{id}`: Delete a note.
44+ - Response: `204 No Content` or `404 Not Found`.
45+
46+## Edge cases and errors
47+- E1: Request body contains invalid JSON: Return `400 Bad Request`.
48+- E2: Note creation request missing required fields (title/content): Return `400 Bad Request`.
49+- E3: Requesting or updating a non-existent ID: Return `404 Not Found`.
50+- E4: Deleting a non-existent ID: Return `404 Not Found`.
51+
52+## Acceptance criteria
53+A1: Given a running server, When `POST /notes` is called with `{"title": "Meeting", "content": "Discuss specs"}`, Then the response is `201 Created` and the body contains a note with a generated ID.
54+A2: Given notes exist, When `GET /notes` is called, Then the response is `200 OK` and the body contains a list including those notes.
55+A3: Given a note exists, When `GET /notes/{id}` is called with that ID, Then the response is `200 OK` and the body matches the note.
56+A4: Given a note exists, When `PUT /notes/{id}` is called with `{"title": "New Title", "content": "New Content"}`, Then the response is `200 OK` and the note reflects the changes.
57+A5: Given a note exists, When `DELETE /notes/{id}` is called, Then the response is `204 No Content` and subsequent `GET` requests for that ID return `404 Not Found`.
58+
59+## Out of scope
60+- Frontend/UI implementation.
61+- Persistent database storage (e.g., PostgreSQL, SQLite).
62+- User authentication or authorization.
63+- Advanced filtering or search functionality.
64+
65+## Open questions
66+- Q1: Should IDs be UUIDs or incremental integers? Default: UUIDs (strings).
67+- Q2: Should the API support partial updates (PATCH)? Default: No, only full updates via PUT.
new file mode 100644
@@ -0,0 +1,67 @@
1+# CRUD Notes Webapp Specification
2+
3+## Goal
4+Implement a RESTful web application in Go that allows users to perform CRUD operations on a collection of notes. This backend will serve as the data provider for a notes management system.
5+
6+## Context
7+This is a new project. There is no existing code.
8+
9+## Requirements
10+R1: The system shall provide an endpoint to create a new note.
11+R2: The system shall provide an endpoint to retrieve a list of all existing notes.
12+R3: The system shall provide an endpoint to retrieve a single note by its unique ID.
13+R4: The system shall provide an endpoint to update an existing note.
14+R5: The system shall provide an endpoint to delete an existing note.
15+R6: The system shall store notes in memory during the application lifecycle.
16+R7: The backend shall be implemented in Go.
17+
18+## Interfaces
19+
20+### Data Model
21+`Note` struct:
22+```go
23+type Note struct {
24+ ID string `json:"id"`
25+ Title string `json:"title"`
26+ Content string `json:"content"`
27+ CreatedAt time.Time `json:"created_at"`
28+ UpdatedAt time.Time `json:"updated_at"`
29+}
30+```
31+
32+### HTTP API
33+- `POST /notes`: Create a note.
34+ - Request Body: `{"title": string, "content": string}`
35+ - Response: `201 Created` with the created `Note` object.
36+- `GET /notes`: List all notes.
37+ - Response: `200 OK` with a JSON array of `Note` objects.
38+- `GET /notes/{id}`: Get a specific note.
39+ - Response: `200 OK` with the `Note` object or `404 Not Found`.
40+- `PUT /notes/{id}`: Update an existing note.
41+ - Request Body: `{"title": string, "content": string}`
42+ - Response: `200 OK` with the updated `Note` object or `404 Not Found`.
43+- `DELETE /notes/{id}`: Delete a note.
44+ - Response: `204 No Content` or `404 Not Found`.
45+
46+## Edge cases and errors
47+- E1: Request body contains invalid JSON: Return `400 Bad Request`.
48+- E2: Note creation request missing required fields (title/content): Return `400 Bad Request`.
49+- E3: Requesting or updating a non-existent ID: Return `404 Not Found`.
50+- E4: Deleting a non-existent ID: Return `404 Not Found`.
51+
52+## Acceptance criteria
53+A1: Given a running server, When `POST /notes` is called with `{"title": "Meeting", "content": "Discuss specs"}`, Then the response is `201 Created` and the body contains a note with a generated ID.
54+A2: Given notes exist, When `GET /notes` is called, Then the response is `200 OK` and the body contains a list including those notes.
55+A3: Given a note exists, When `GET /notes/{id}` is called with that ID, Then the response is `200 OK` and the body matches the note.
56+A4: Given a note exists, When `PUT /notes/{id}` is called with `{"title": "New Title", "content": "New Content"}`, Then the response is `200 OK` and the note reflects the changes.
57+A5: Given a note exists, When `DELETE /notes/{id}` is called, Then the response is `204 No Content` and subsequent `GET` requests for that ID return `404 Not Found`.
58+
59+## Out of scope
60+- Frontend/UI implementation.
61+- Persistent database storage (e.g., PostgreSQL, SQLite).
62+- User authentication or authorization.
63+- Advanced filtering or search functionality.
64+
65+## Open questions
66+- Q1: Should IDs be UUIDs or incremental integers? Default: UUIDs (strings).
67+- Q2: Should the API support partial updates (PATCH)? Default: No, only full updates via PUT.