🛟 Updated.Unverified
8941766 parent: 30a5de4 modified
.tickets/epics.yaml +27 -0 | @@ -18,3 +18,30 @@ epics: | ||
| 18 | 18 | - title: Providers (LLM Engine) |
| 19 | 19 | state: open |
| 20 | 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" | |
| @@ -18,3 +18,30 @@ epics: | |||
| 18 | - title: Providers (LLM Engine) | 18 | - title: Providers (LLM Engine) |
| 19 | state: open | 19 | 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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-15T23:04:05.027Z |
| 9 | -updatedAt: 2026-09-15T23:04:05.027Z | |
| 9 | +updatedAt: 2026-10-06T13:00:56.375Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: Improve TUI | |
| 11 | 12 | body: "" |
| 12 | 13 | tasks: [] |
| 13 | 14 | comments: [] |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-15T23:04:05.027Z | 8 | createdAt: 2026-09-15T23:04:05.027Z |
| 9 | -updatedAt: 2026-09-15T23:04:05.027Z | 9 | +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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-16T04:09:48.463Z |
| 9 | -updatedAt: 2026-09-16T06:00:00.000Z | |
| 9 | +updatedAt: 2026-10-06T13:03:01.126Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: Documentation | |
| 11 | 12 | body: | |
| 12 | 13 | ## Summary |
| 13 | 14 | |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-16T04:09:48.463Z | 8 | createdAt: 2026-09-16T04:09:48.463Z |
| 9 | -updatedAt: 2026-09-16T06:00:00.000Z | 9 | +updatedAt: 2026-10-06T13:03:01.126Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | +epic: Documentation | ||
| 11 | body: | | 12 | body: | |
| 12 | ## Summary | 13 | ## Summary |
| 13 | 14 | ||
modified
.tickets/issues/0014-check-all-the-shortcuts-in-the-tui.yaml +2 -1 | @@ -6,8 +6,9 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-16T05:51:16.287Z |
| 9 | -updatedAt: 2026-09-18T18:43:57.408Z | |
| 9 | +updatedAt: 2026-10-06T13:03:40.148Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: Improve TUI | |
| 11 | 12 | body: "" |
| 12 | 13 | tasks: |
| 13 | 14 | - id: 1 |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-16T05:51:16.287Z | 8 | createdAt: 2026-09-16T05:51:16.287Z |
| 9 | -updatedAt: 2026-09-18T18:43:57.408Z | 9 | +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: 1 | 14 | - id: 1 |
modified
.tickets/issues/0016-check-and-review-the-compress-mechanism.yaml +2 -1 | @@ -6,8 +6,9 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-17T06:17:29.481Z |
| 9 | -updatedAt: 2026-09-18T18:46:34.272Z | |
| 9 | +updatedAt: 2026-10-06T13:04:37.034Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: Documentation | |
| 11 | 12 | related: |
| 12 | 13 | - 10 |
| 13 | 14 | body: "" |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-17T06:17:29.481Z | 8 | createdAt: 2026-09-17T06:17:29.481Z |
| 9 | -updatedAt: 2026-09-18T18:46:34.272Z | 9 | +updatedAt: 2026-10-06T13:04:37.034Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | +epic: Documentation | ||
| 11 | related: | 12 | related: |
| 12 | - 10 | 13 | - 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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-17T13:22:40.786Z |
| 9 | -updatedAt: 2026-09-18T18:50:10.764Z | |
| 9 | +updatedAt: 2026-10-06T13:05:39.475Z | |
| 10 | 10 | labels: |
| 11 | 11 | - priority::low |
| 12 | 12 | - kind::chore |
| 13 | 13 | - enhancement |
| 14 | +epic: Debug | |
| 14 | 15 | body: | |
| 15 | 16 | - Use the sessions' logs |
| 16 | 17 | - Create a Claude Skill for this |
| @@ -6,11 +6,12 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-17T13:22:40.786Z | 8 | createdAt: 2026-09-17T13:22:40.786Z |
| 9 | -updatedAt: 2026-09-18T18:50:10.764Z | 9 | +updatedAt: 2026-10-06T13:05:39.475Z |
| 10 | labels: | 10 | labels: |
| 11 | - priority::low | 11 | - priority::low |
| 12 | - kind::chore | 12 | - kind::chore |
| 13 | - enhancement | 13 | - enhancement |
| 14 | +epic: Debug | ||
| 14 | body: | | 15 | body: | |
| 15 | - Use the sessions' logs | 16 | - Use the sessions' logs |
| 16 | - Create a Claude Skill for this | 17 | - Create a Claude Skill for this |
modified
.tickets/issues/0036-hooks.yaml +2 -1 | @@ -6,8 +6,9 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-21T06:32:48.566Z |
| 9 | -updatedAt: 2026-09-23T11:50:03.431Z | |
| 9 | +updatedAt: 2026-10-06T13:16:31.213Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: Loop | |
| 11 | 12 | body: | |
| 12 | 13 | ## Overview |
| 13 | 14 | Design a hook system for mini-me to allow extensibility at key points in the agent lifecycle |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-21T06:32:48.566Z | 8 | createdAt: 2026-09-21T06:32:48.566Z |
| 9 | -updatedAt: 2026-09-23T11:50:03.431Z | 9 | +updatedAt: 2026-10-06T13:16:31.213Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | +epic: Loop | ||
| 11 | body: | | 12 | body: | |
| 12 | ## Overview | 13 | ## Overview |
| 13 | Design a hook system for mini-me to allow extensibility at key points in the agent lifecycle | 14 | 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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-25T04:44:02.972Z |
| 9 | -updatedAt: 2026-09-25T04:44:12.561Z | |
| 9 | +updatedAt: 2026-10-06T13:06:04.590Z | |
| 10 | 10 | labels: |
| 11 | 11 | - question |
| 12 | 12 | - llama.cpp |
| 13 | +epic: Models | |
| 13 | 14 | body: "" |
| 14 | 15 | tasks: [] |
| 15 | 16 | comments: [] |
| @@ -6,10 +6,11 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-25T04:44:02.972Z | 8 | createdAt: 2026-09-25T04:44:02.972Z |
| 9 | -updatedAt: 2026-09-25T04:44:12.561Z | 9 | +updatedAt: 2026-10-06T13:06:04.590Z |
| 10 | labels: | 10 | labels: |
| 11 | - question | 11 | - question |
| 12 | - llama.cpp | 12 | - 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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-25T07:14:21.206Z |
| 9 | -updatedAt: 2026-09-25T07:14:51.120Z | |
| 9 | +updatedAt: 2026-10-06T13:06:21.857Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: Documentation | |
| 11 | 12 | body: | |
| 12 | 13 | Create a document to explain how to use the sampling parameters |
| 13 | 14 | tasks: [] |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-25T07:14:21.206Z | 8 | createdAt: 2026-09-25T07:14:21.206Z |
| 9 | -updatedAt: 2026-09-25T07:14:51.120Z | 9 | +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 parameters | 13 | 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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-27T02:30:34.975Z |
| 9 | -updatedAt: 2026-09-27T03:45:08.358Z | |
| 9 | +updatedAt: 2026-10-06T13:09:56.640Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: Builtin tools | |
| 11 | 12 | body: | |
| 12 | 13 | example: safe / unsafe with wasm -> LlamaGuard |
| 13 | 14 | |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-27T02:30:34.975Z | 8 | createdAt: 2026-09-27T02:30:34.975Z |
| 9 | -updatedAt: 2026-09-27T03:45:08.358Z | 9 | +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 -> LlamaGuard | 13 | example: safe / unsafe with wasm -> LlamaGuard |
| 13 | 14 | ||
modified
.tickets/issues/0049-recreate-the-readme.yaml +2 -1 | @@ -6,9 +6,10 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-28T18:44:44.821Z |
| 9 | -updatedAt: 2026-09-29T06:27:22.776Z | |
| 9 | +updatedAt: 2026-10-06T13:08:12.646Z | |
| 10 | 10 | labels: [] |
| 11 | 11 | milestone: v0.3.0 |
| 12 | +epic: ToDo | |
| 12 | 13 | body: "" |
| 13 | 14 | tasks: [] |
| 14 | 15 | comments: [] |
| @@ -6,9 +6,10 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-28T18:44:44.821Z | 8 | createdAt: 2026-09-28T18:44:44.821Z |
| 9 | -updatedAt: 2026-09-29T06:27:22.776Z | 9 | +updatedAt: 2026-10-06T13:08:12.646Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | milestone: v0.3.0 | 11 | 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 @@ | ||
| 1 | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | 2 | id: 51 |
| 3 | 3 | title: Query other models from the prompt |
| 4 | -state: open | |
| 4 | +state: closed | |
| 5 | 5 | author: |
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-29T04:49:19.839Z |
| 9 | -updatedAt: 2026-09-29T06:24:02.144Z | |
| 9 | +updatedAt: 2026-10-06T13:08:32.615Z | |
| 10 | 10 | labels: |
| 11 | 11 | - priority::high |
| 12 | 12 | - kind::feature |
| 13 | 13 | - enhancement |
| 14 | 14 | - builtin tool |
| 15 | 15 | milestone: v0.3.0 |
| 16 | +epic: Models | |
| 16 | 17 | body: | |
| 17 | 18 | - Add a list of model (and provider) to the agent config file (with an alias / nickname) |
| 18 | 19 | - 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: 51 | 2 | id: 51 |
| 3 | title: Query other models from the prompt | 3 | title: Query other models from the prompt |
| 4 | -state: open | 4 | +state: closed |
| 5 | author: | 5 | author: |
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-29T04:49:19.839Z | 8 | createdAt: 2026-09-29T04:49:19.839Z |
| 9 | -updatedAt: 2026-09-29T06:24:02.144Z | 9 | +updatedAt: 2026-10-06T13:08:32.615Z |
| 10 | labels: | 10 | labels: |
| 11 | - priority::high | 11 | - priority::high |
| 12 | - kind::feature | 12 | - kind::feature |
| 13 | - enhancement | 13 | - enhancement |
| 14 | - builtin tool | 14 | - builtin tool |
| 15 | milestone: v0.3.0 | 15 | 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 @@ | ||
| 1 | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | 2 | id: 53 |
| 3 | 3 | title: Tool order changes on every question (breaks the KV prefix cache) |
| 4 | -state: open | |
| 4 | +state: closed | |
| 5 | 5 | author: |
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-30T05:52:16.000Z |
| 9 | -updatedAt: 2026-09-30T06:11:23.000Z | |
| 9 | +updatedAt: 2026-10-06T13:09:01.955Z | |
| 10 | 10 | labels: |
| 11 | 11 | - kind::bug |
| 12 | 12 | - 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: 53 | 2 | 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: open | 4 | +state: closed |
| 5 | author: | 5 | author: |
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-30T05:52:16.000Z | 8 | createdAt: 2026-09-30T05:52:16.000Z |
| 9 | -updatedAt: 2026-09-30T06:11:23.000Z | 9 | +updatedAt: 2026-10-06T13:09:01.955Z |
| 10 | labels: | 10 | labels: |
| 11 | - kind::bug | 11 | - kind::bug |
| 12 | - priority::high | 12 | - priority::high |
modified
.tickets/issues/0054-how-to-force-the-json-output.yaml +2 -1 | @@ -6,8 +6,9 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-30T06:35:54.771Z |
| 9 | -updatedAt: 2026-09-30T06:35:54.771Z | |
| 9 | +updatedAt: 2026-10-06T13:11:09.040Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: Questions | |
| 11 | 12 | body: "" |
| 12 | 13 | tasks: [] |
| 13 | 14 | comments: [] |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-30T06:35:54.771Z | 8 | createdAt: 2026-09-30T06:35:54.771Z |
| 9 | -updatedAt: 2026-09-30T06:35:54.771Z | 9 | +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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-30T06:37:48.693Z |
| 9 | -updatedAt: 2026-09-30T06:38:40.601Z | |
| 9 | +updatedAt: 2026-10-06T13:14:33.928Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: Models | |
| 11 | 12 | related: |
| 12 | 13 | - 54 |
| 13 | 14 | - 52 |
| 14 | 15 | - 51 |
| 15 | -body: "" | |
| 16 | +body: | | |
| 17 | + Extranal yaml file with structured JSON | |
| 16 | 18 | tasks: [] |
| 17 | 19 | comments: [] |
| @@ -6,12 +6,14 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-30T06:37:48.693Z | 8 | createdAt: 2026-09-30T06:37:48.693Z |
| 9 | -updatedAt: 2026-09-30T06:38:40.601Z | 9 | +updatedAt: 2026-10-06T13:14:33.928Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | +epic: Models | ||
| 11 | related: | 12 | related: |
| 12 | - 54 | 13 | - 54 |
| 13 | - 52 | 14 | - 52 |
| 14 | - 51 | 15 | - 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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-30T06:50:30.091Z |
| 9 | -updatedAt: 2026-09-30T06:50:30.091Z | |
| 9 | +updatedAt: 2026-10-06T13:12:26.692Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: ToDo | |
| 11 | 12 | body: "" |
| 12 | 13 | tasks: [] |
| 13 | 14 | comments: [] |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-30T06:50:30.091Z | 8 | createdAt: 2026-09-30T06:50:30.091Z |
| 9 | -updatedAt: 2026-09-30T06:50:30.091Z | 9 | +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 @@ | ||
| 1 | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | 2 | id: 57 |
| 3 | 3 | title: Watchdog kills the turn while a tool runs or a permission is pending |
| 4 | -state: open | |
| 4 | +state: closed | |
| 5 | 5 | author: |
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-30T11:38:05.000Z |
| 9 | -updatedAt: 2026-09-30T11:38:05.000Z | |
| 9 | +updatedAt: 2026-10-06T13:13:01.356Z | |
| 10 | 10 | labels: |
| 11 | 11 | - kind::bug |
| 12 | 12 | - priority::medium |
| 13 | +epic: Models | |
| 13 | 14 | related: |
| 14 | 15 | - 53 |
| 15 | 16 | body: | |
| @@ -63,7 +64,7 @@ tasks: | ||
| 63 | 64 | createdAt: 2026-09-30T11:38:05.000Z |
| 64 | 65 | updatedAt: 2026-09-30T11:38:05.000Z |
| 65 | 66 | - 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 | 68 | state: open |
| 68 | 69 | priority: none |
| 69 | 70 | author: |
| @@ -81,7 +82,7 @@ tasks: | ||
| 81 | 82 | createdAt: 2026-09-30T11:38:05.000Z |
| 82 | 83 | updatedAt: 2026-09-30T11:38:05.000Z |
| 83 | 84 | - 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 | 86 | state: open |
| 86 | 87 | priority: none |
| 87 | 88 | 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: 57 | 2 | id: 57 |
| 3 | title: Watchdog kills the turn while a tool runs or a permission is pending | 3 | title: Watchdog kills the turn while a tool runs or a permission is pending |
| 4 | -state: open | 4 | +state: closed |
| 5 | author: | 5 | author: |
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-30T11:38:05.000Z | 8 | createdAt: 2026-09-30T11:38:05.000Z |
| 9 | -updatedAt: 2026-09-30T11:38:05.000Z | 9 | +updatedAt: 2026-10-06T13:13:01.356Z |
| 10 | labels: | 10 | labels: |
| 11 | - kind::bug | 11 | - kind::bug |
| 12 | - priority::medium | 12 | - priority::medium |
| 13 | +epic: Models | ||
| 13 | related: | 14 | related: |
| 14 | - 53 | 15 | - 53 |
| 15 | body: | | 16 | body: | |
| @@ -63,7 +64,7 @@ tasks: | |||
| 63 | createdAt: 2026-09-30T11:38:05.000Z | 64 | createdAt: 2026-09-30T11:38:05.000Z |
| 64 | updatedAt: 2026-09-30T11:38:05.000Z | 65 | updatedAt: 2026-09-30T11:38:05.000Z |
| 65 | - id: 2 | 66 | - 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: open | 68 | state: open |
| 68 | priority: none | 69 | priority: none |
| 69 | author: | 70 | author: |
| @@ -81,7 +82,7 @@ tasks: | |||
| 81 | createdAt: 2026-09-30T11:38:05.000Z | 82 | createdAt: 2026-09-30T11:38:05.000Z |
| 82 | updatedAt: 2026-09-30T11:38:05.000Z | 83 | updatedAt: 2026-09-30T11:38:05.000Z |
| 83 | - id: 4 | 84 | - 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: open | 86 | state: open |
| 86 | priority: none | 87 | 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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-01T04:39:22.452Z |
| 9 | -updatedAt: 2026-10-01T04:39:22.452Z | |
| 9 | +updatedAt: 2026-10-06T13:13:18.155Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: ToDo | |
| 11 | 12 | body: "" |
| 12 | 13 | tasks: [] |
| 13 | 14 | comments: [] |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-01T04:39:22.452Z | 8 | createdAt: 2026-10-01T04:39:22.452Z |
| 9 | -updatedAt: 2026-10-01T04:39:22.452Z | 9 | +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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-01T05:48:44.919Z |
| 9 | -updatedAt: 2026-10-01T05:48:44.919Z | |
| 9 | +updatedAt: 2026-10-06T13:07:28.156Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: Providers (LLM Engine) | |
| 11 | 12 | body: "" |
| 12 | 13 | tasks: [] |
| 13 | 14 | comments: [] |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-01T05:48:44.919Z | 8 | createdAt: 2026-10-01T05:48:44.919Z |
| 9 | -updatedAt: 2026-10-01T05:48:44.919Z | 9 | +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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-01T06:38:27.789Z |
| 9 | -updatedAt: 2026-10-01T06:38:27.789Z | |
| 9 | +updatedAt: 2026-10-06T13:02:37.363Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: Documentation | |
| 11 | 12 | body: "" |
| 12 | 13 | tasks: [] |
| 13 | 14 | comments: [] |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-01T06:38:27.789Z | 8 | createdAt: 2026-10-01T06:38:27.789Z |
| 9 | -updatedAt: 2026-10-01T06:38:27.789Z | 9 | +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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-01T06:39:02.823Z |
| 9 | -updatedAt: 2026-10-01T06:39:02.823Z | |
| 9 | +updatedAt: 2026-10-06T13:03:26.126Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: Demos | |
| 11 | 12 | body: "" |
| 12 | 13 | tasks: [] |
| 13 | 14 | comments: [] |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-01T06:39:02.823Z | 8 | createdAt: 2026-10-01T06:39:02.823Z |
| 9 | -updatedAt: 2026-10-01T06:39:02.823Z | 9 | +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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-01T06:39:46.034Z |
| 9 | -updatedAt: 2026-10-01T06:39:46.034Z | |
| 9 | +updatedAt: 2026-10-06T13:13:31.383Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: Questions | |
| 11 | 12 | body: "" |
| 12 | 13 | tasks: [] |
| 13 | 14 | comments: [] |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-01T06:39:46.034Z | 8 | createdAt: 2026-10-01T06:39:46.034Z |
| 9 | -updatedAt: 2026-10-01T06:39:46.034Z | 9 | +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 @@ | ||
| 1 | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | 2 | id: 67 |
| 3 | 3 | title: Enable / Disable reasoning mode |
| 4 | -state: open | |
| 4 | +state: closed | |
| 5 | 5 | author: |
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-02T06:09:42.599Z |
| 9 | -updatedAt: 2026-10-06T14:00:00.000Z | |
| 9 | +updatedAt: 2026-10-06T13:13:56.879Z | |
| 10 | 10 | labels: |
| 11 | 11 | - kind::feature |
| 12 | +epic: Models | |
| 12 | 13 | related: |
| 13 | 14 | - 62 |
| 14 | 15 | - 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: 67 | 2 | id: 67 |
| 3 | title: Enable / Disable reasoning mode | 3 | title: Enable / Disable reasoning mode |
| 4 | -state: open | 4 | +state: closed |
| 5 | author: | 5 | author: |
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-02T06:09:42.599Z | 8 | createdAt: 2026-10-02T06:09:42.599Z |
| 9 | -updatedAt: 2026-10-06T14:00:00.000Z | 9 | +updatedAt: 2026-10-06T13:13:56.879Z |
| 10 | labels: | 10 | labels: |
| 11 | - kind::feature | 11 | - kind::feature |
| 12 | +epic: Models | ||
| 12 | related: | 13 | related: |
| 13 | - 62 | 14 | - 62 |
| 14 | - 76 | 15 | - 76 |
modified
.tickets/issues/0068-recall-the-last-commands-last.yaml +2 -1 | @@ -6,8 +6,9 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-02T07:01:13.955Z |
| 9 | -updatedAt: 2026-10-02T07:01:13.955Z | |
| 9 | +updatedAt: 2026-10-06T13:14:55.214Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: Improve TUI | |
| 11 | 12 | body: "" |
| 12 | 13 | tasks: [] |
| 13 | 14 | comments: [] |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-02T07:01:13.955Z | 8 | createdAt: 2026-10-02T07:01:13.955Z |
| 9 | -updatedAt: 2026-10-02T07:01:13.955Z | 9 | +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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-02T09:26:19.729Z |
| 9 | -updatedAt: 2026-10-02T09:27:01.494Z | |
| 9 | +updatedAt: 2026-10-06T13:11:52.354Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: ToDo | |
| 11 | 12 | body: | |
| 12 | 13 | For example Genkit skill with the appropriate links to the documentation (for fetching) |
| 13 | 14 | tasks: [] |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-02T09:26:19.729Z | 8 | createdAt: 2026-10-02T09:26:19.729Z |
| 9 | -updatedAt: 2026-10-02T09:27:01.494Z | 9 | +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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-02T14:22:29.427Z |
| 9 | -updatedAt: 2026-10-02T14:22:29.427Z | |
| 9 | +updatedAt: 2026-10-06T13:11:38.195Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: Questions | |
| 11 | 12 | body: "" |
| 12 | 13 | tasks: [] |
| 13 | 14 | comments: [] |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-02T14:22:29.427Z | 8 | createdAt: 2026-10-02T14:22:29.427Z |
| 9 | -updatedAt: 2026-10-02T14:22:29.427Z | 9 | +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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-02T05:32:33.878Z |
| 9 | -updatedAt: 2026-10-02T21:15:00.000Z | |
| 9 | +updatedAt: 2026-10-06T13:15:18.350Z | |
| 10 | 10 | labels: [] |
| 11 | +epic: SDK | |
| 11 | 12 | body: "" |
| 12 | 13 | tasks: [] |
| 13 | 14 | comments: [] |
| @@ -6,8 +6,9 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-02T05:32:33.878Z | 8 | createdAt: 2026-10-02T05:32:33.878Z |
| 9 | -updatedAt: 2026-10-02T21:15:00.000Z | 9 | +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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-02T21:40:00.000Z |
| 9 | -updatedAt: 2026-10-02T21:40:00.000Z | |
| 9 | +updatedAt: 2026-10-06T13:10:38.836Z | |
| 10 | 10 | labels: |
| 11 | 11 | - kind::feature |
| 12 | +epic: Models | |
| 12 | 13 | related: |
| 13 | 14 | - 15 |
| 14 | 15 | - 59 |
| @@ -186,7 +187,7 @@ tasks: | ||
| 186 | 187 | createdAt: 2026-10-02T21:40:00.000Z |
| 187 | 188 | updatedAt: 2026-10-02T21:40:00.000Z |
| 188 | 189 | - 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 | 191 | state: open |
| 191 | 192 | priority: none |
| 192 | 193 | author: |
| @@ -231,7 +232,7 @@ tasks: | ||
| 231 | 232 | createdAt: 2026-10-02T21:40:00.000Z |
| 232 | 233 | updatedAt: 2026-10-02T21:40:00.000Z |
| 233 | 234 | - 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 | 236 | state: open |
| 236 | 237 | priority: none |
| 237 | 238 | 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: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-02T21:40:00.000Z | 8 | createdAt: 2026-10-02T21:40:00.000Z |
| 9 | -updatedAt: 2026-10-02T21:40:00.000Z | 9 | +updatedAt: 2026-10-06T13:10:38.836Z |
| 10 | labels: | 10 | labels: |
| 11 | - kind::feature | 11 | - kind::feature |
| 12 | +epic: Models | ||
| 12 | related: | 13 | related: |
| 13 | - 15 | 14 | - 15 |
| 14 | - 59 | 15 | - 59 |
| @@ -186,7 +187,7 @@ tasks: | |||
| 186 | createdAt: 2026-10-02T21:40:00.000Z | 187 | createdAt: 2026-10-02T21:40:00.000Z |
| 187 | updatedAt: 2026-10-02T21:40:00.000Z | 188 | updatedAt: 2026-10-02T21:40:00.000Z |
| 188 | - id: 3 | 189 | - 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: open | 191 | state: open |
| 191 | priority: none | 192 | priority: none |
| 192 | author: | 193 | author: |
| @@ -231,7 +232,7 @@ tasks: | |||
| 231 | createdAt: 2026-10-02T21:40:00.000Z | 232 | createdAt: 2026-10-02T21:40:00.000Z |
| 232 | updatedAt: 2026-10-02T21:40:00.000Z | 233 | updatedAt: 2026-10-02T21:40:00.000Z |
| 233 | - id: 8 | 234 | - 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: open | 236 | state: open |
| 236 | priority: none | 237 | 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: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-06T18:00:00.000Z |
| 9 | -updatedAt: 2026-10-06T18:00:00.000Z | |
| 9 | +updatedAt: 2026-10-06T13:02:08.728Z | |
| 10 | 10 | labels: |
| 11 | 11 | - documentation |
| 12 | 12 | - priority::low |
| 13 | +epic: Documentation | |
| 13 | 14 | body: | |
| 14 | 15 | The ebook (« Créer un agent de code pas à pas », `ebook/`, French |
| 15 | 16 | AsciiDoc, built with the ebook-builder skill) never covers the MCP client, |
| @@ -75,7 +76,7 @@ body: | | ||
| 75 | 76 | 7. What is not there (stdio) and why. |
| 76 | 77 | tasks: |
| 77 | 78 | - 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 | 80 | state: open |
| 80 | 81 | priority: none |
| 81 | 82 | author: |
| @@ -84,7 +85,7 @@ tasks: | ||
| 84 | 85 | createdAt: 2026-10-06T18:00:00.000Z |
| 85 | 86 | updatedAt: 2026-10-06T18:00:00.000Z |
| 86 | 87 | - 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 | 89 | state: open |
| 89 | 90 | priority: none |
| 90 | 91 | author: |
| @@ -102,7 +103,7 @@ tasks: | ||
| 102 | 103 | createdAt: 2026-10-06T18:00:00.000Z |
| 103 | 104 | updatedAt: 2026-10-06T18:00:00.000Z |
| 104 | 105 | - 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 | 107 | state: open |
| 107 | 108 | priority: none |
| 108 | 109 | author: |
| @@ -111,7 +112,7 @@ tasks: | ||
| 111 | 112 | createdAt: 2026-10-06T18:00:00.000Z |
| 112 | 113 | updatedAt: 2026-10-06T18:00:00.000Z |
| 113 | 114 | - 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 | 116 | state: open |
| 116 | 117 | priority: none |
| 117 | 118 | 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: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-06T18:00:00.000Z | 8 | createdAt: 2026-10-06T18:00:00.000Z |
| 9 | -updatedAt: 2026-10-06T18:00:00.000Z | 9 | +updatedAt: 2026-10-06T13:02:08.728Z |
| 10 | labels: | 10 | labels: |
| 11 | - documentation | 11 | - documentation |
| 12 | - priority::low | 12 | - priority::low |
| 13 | +epic: Documentation | ||
| 13 | body: | | 14 | body: | |
| 14 | The ebook (« Créer un agent de code pas à pas », `ebook/`, French | 15 | 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: 1 | 78 | - 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: open | 80 | state: open |
| 80 | priority: none | 81 | priority: none |
| 81 | author: | 82 | author: |
| @@ -84,7 +85,7 @@ tasks: | |||
| 84 | createdAt: 2026-10-06T18:00:00.000Z | 85 | createdAt: 2026-10-06T18:00:00.000Z |
| 85 | updatedAt: 2026-10-06T18:00:00.000Z | 86 | updatedAt: 2026-10-06T18:00:00.000Z |
| 86 | - id: 2 | 87 | - 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: open | 89 | state: open |
| 89 | priority: none | 90 | priority: none |
| 90 | author: | 91 | author: |
| @@ -102,7 +103,7 @@ tasks: | |||
| 102 | createdAt: 2026-10-06T18:00:00.000Z | 103 | createdAt: 2026-10-06T18:00:00.000Z |
| 103 | updatedAt: 2026-10-06T18:00:00.000Z | 104 | updatedAt: 2026-10-06T18:00:00.000Z |
| 104 | - id: 4 | 105 | - 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: open | 107 | state: open |
| 107 | priority: none | 108 | priority: none |
| 108 | author: | 109 | author: |
| @@ -111,7 +112,7 @@ tasks: | |||
| 111 | createdAt: 2026-10-06T18:00:00.000Z | 112 | createdAt: 2026-10-06T18:00:00.000Z |
| 112 | updatedAt: 2026-10-06T18:00:00.000Z | 113 | updatedAt: 2026-10-06T18:00:00.000Z |
| 113 | - id: 5 | 114 | - 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: open | 116 | state: open |
| 116 | priority: none | 117 | 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/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 | ||
| 98 | 98 | showThinking: true |
| 99 | 99 | |
| 100 | 100 | |
| 101 | +acp: | |
| 102 | + name: jan | |
| 103 | + title: Jan (coding agent) | |
| 104 | + | |
| 101 | 105 | # The system prompt: what the agent is, and what it is allowed to do. |
| 102 | 106 | # This is the knob to play with — it is the shortest path to changing behaviour. |
| 103 | 107 | system: | |
| @@ -98,6 +98,10 @@ displayCommands: true | |||
| 98 | showThinking: true | 98 | 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: | ||
| 30 | 30 | # skills) when it is only asked for an opinion. |
| 31 | 31 | reviewer: agent.lucy-reviewer.yaml |
| 32 | 32 | |
| 33 | +acp: | |
| 34 | + name: bob | |
| 35 | + title: Bob (coordinator) | |
| 36 | + | |
| 33 | 37 | # Only when the daemon was started with LLMMAN_API_KEYS (mandatory when it |
| 34 | 38 | # listens beyond loopback); unset otherwise. The key never goes in this file. |
| 35 | 39 | # 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.yaml | 31 | 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 it | 37 | # 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_KEY | 39 | # apiKeyEnv: LLMMAN_API_KEY |
modified
demo-llmman/agent.lucy-reviewer.yaml +3 -0 | @@ -98,6 +98,9 @@ displayCommands: true | ||
| 98 | 98 | # model thinks — this only says whether to show it. |
| 99 | 99 | showThinking: true |
| 100 | 100 | |
| 101 | +acp: | |
| 102 | + name: lucy_reviewer | |
| 103 | + title: Lucy (reviewer) | |
| 101 | 104 | |
| 102 | 105 | # The system prompt: what the agent is, and what it is allowed to do. |
| 103 | 106 | # 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: true | 99 | 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 | ||
| 97 | 97 | # model thinks — this only says whether to show it. |
| 98 | 98 | showThinking: true |
| 99 | 99 | |
| 100 | +acp: | |
| 101 | + name: lucy | |
| 102 | + title: Lucy (coding agent) | |
| 100 | 103 | |
| 101 | 104 | # The system prompt: what the agent is, and what it is allowed to do. |
| 102 | 105 | # 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: true | 98 | 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 | ||
| 56 | 56 | |
| 57 | 57 | Use it with care: |
| 58 | 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. | |
| 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. | |
| 61 | 61 | - On `ollama`, `reasoning_effort` goes at the top level of `sampling`, not under `chat_template_kwargs`; only `none` has been measured there. |
| 62 | 62 | - Compaction summaries do not follow it — see below. |
| 63 | 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). |
| @@ -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 @@ | ||
| 59 | 59 | | Key | Type | Default | Description | |
| 60 | 60 | |-----|------|---------|-------------| |
| 61 | 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 | 64 | The version is not configurable: `agentInfo.version` is always the binary's, as printed by `mm --version`. |
| 65 | 65 | |
| @@ -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 | ||
| 56 | 56 | |
| 57 | 57 | Précautions d'usage : |
| 58 | 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. | |
| 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`. | |
| 61 | 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 | 62 | - Les résumés de compaction ne le suivent pas — voir ci-dessous. |
| 63 | 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`). |
| @@ -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 @@ | ||
| 59 | 59 | | Clé | Type | Défaut | Description | |
| 60 | 60 | |-----|------|--------|-------------| |
| 61 | 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 | 64 | La version n'est pas paramétrable : `agentInfo.version` est toujours celle du binaire, telle qu'affichée par `mm --version`. |
| 65 | 65 | |
| @@ -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 | ||
| 3 | 3 | import ( |
| 4 | 4 | "fmt" |
| 5 | 5 | "os" |
| 6 | + "strings" | |
| 6 | 7 | |
| 7 | 8 | "github.com/firebase/genkit/go/ai" |
| 8 | 9 | "gopkg.in/yaml.v3" |
| @@ -45,19 +46,40 @@ func clipMiddle(s string, max int) string { | ||
| 45 | 46 | // |
| 46 | 47 | // ask.Describe("demo-ollama/agent.ollama.yaml") // "ollama/qwen3.5:2b" |
| 47 | 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 | 67 | data, err := os.ReadFile(path) |
| 49 | 68 | if err != nil { |
| 50 | - return "?" | |
| 69 | + return Identity{} | |
| 51 | 70 | } |
| 52 | 71 | var head struct { |
| 53 | 72 | Provider string `yaml:"provider"` |
| 54 | 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 == "" { | |
| 57 | - return "?" | |
| 78 | + if yaml.Unmarshal(data, &head) != nil { | |
| 79 | + return Identity{} | |
| 58 | 80 | } |
| 59 | 81 | if head.Provider == "" { |
| 60 | 82 | head.Provider = "dmr" // config.Cfg's default |
| 61 | 83 | } |
| 62 | - return head.Provider + "/" + head.Model | |
| 84 | + return Identity{Title: strings.TrimSpace(head.ACP.Title), Provider: head.Provider, Model: head.Model} | |
| 63 | 85 | } |
| @@ -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 default | 82 | head.Provider = "dmr" // config.Cfg's default |
| 61 | } | 83 | } |
| 62 | - return head.Provider + "/" + head.Model | 84 | + 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) { | ||
| 54 | 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 | +} | |
| @@ -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 { | ||
| 426 | 426 | // AGENT_CONFIG says otherwise. |
| 427 | 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 | 432 | // Cfg: the live settings, pre-filled with the built-in defaults. |
| 430 | 433 | // |
| 431 | 434 | // Defaults suited to a CODING AGENT — low temperature for precise and |
| @@ -484,7 +487,7 @@ which ones you left running.`, | ||
| 484 | 487 | }, |
| 485 | 488 | ACP: ACPConfig{ |
| 486 | 489 | Name: "bob", |
| 487 | - Title: "Bob (bash-first agent)", | |
| 490 | + Title: DefaultACPTitle, | |
| 488 | 491 | }, |
| 489 | 492 | Yolo: true, |
| 490 | 493 | 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 and | 434 | // 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 ( | ||
| 11 | 11 | |
| 12 | 12 | "mm/internal/ask" |
| 13 | 13 | "mm/internal/command" |
| 14 | + "mm/internal/config" | |
| 14 | 15 | "mm/internal/store" |
| 15 | 16 | |
| 16 | 17 | "github.com/firebase/genkit/go/ai" |
| @@ -20,6 +21,9 @@ import ( | ||
| 20 | 21 | func (r *runner) startAsk(p Prompt, req command.AskRequest) { |
| 21 | 22 | r.t.AddUser(p.Display()) |
| 22 | 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 | 27 | ctx, cancel := context.WithCancel(context.Background()) |
| 24 | 28 | r.cancel = cancel |
| 25 | 29 | r.cancelled.Store(false) |
| @@ -37,6 +41,8 @@ func (r *runner) startAsk(p Prompt, req command.AskRequest) { | ||
| 37 | 41 | // when the other agent answered. |
| 38 | 42 | func (r *runner) applyAsk(res outcome) { |
| 39 | 43 | r.t.Close() |
| 44 | + r.t.SetSpeaker("") | |
| 45 | + r.asking.Store(nil) | |
| 40 | 46 | switch { |
| 41 | 47 | case res.err != nil && res.cancelled: |
| 42 | 48 | 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 = cancel | 28 | 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 | ||
| 3 | 3 | import ( |
| 4 | 4 | "context" |
| 5 | 5 | "errors" |
| 6 | + "os" | |
| 7 | + "path/filepath" | |
| 6 | 8 | "strings" |
| 7 | 9 | "testing" |
| 8 | 10 | |
| 11 | + "mm/internal/ask" | |
| 9 | 12 | "mm/internal/command" |
| 10 | 13 | "mm/internal/config" |
| 11 | 14 | "mm/internal/ui" |
| @@ -19,6 +22,7 @@ type fakeAsker struct { | ||
| 19 | 22 | answer string |
| 20 | 23 | fail error |
| 21 | 24 | block bool |
| 25 | + during func() // called while the other agent is answering | |
| 22 | 26 | } |
| 23 | 27 | |
| 24 | 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 | 35 | if a.fail != nil { |
| 32 | 36 | return nil, a.fail |
| 33 | 37 | } |
| 38 | + if a.during != nil { | |
| 39 | + a.during() | |
| 40 | + } | |
| 34 | 41 | sink.Text(a.answer) |
| 35 | 42 | 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 | 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 | +} | |
| @@ -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 string | 22 | answer string |
| 20 | fail error | 23 | fail error |
| 21 | block bool | 24 | 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.fail | 36 | 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)}, nil | 42 | 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 { | ||
| 60 | 60 | case KindUser: |
| 61 | 61 | lines = append(label("you"), prose(e.Text, width, styleBody)...) |
| 62 | 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 | 68 | case KindTool: |
| 65 | 69 | lines = toolLines(e, width, previewLines) |
| 66 | 70 | 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 ( | ||
| 44 | 44 | type Entry struct { |
| 45 | 45 | Kind Kind |
| 46 | 46 | 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 | 50 | // Full is the question as the model read it when Text is its collapsed |
| 48 | 51 | // form — a long paste shown as `[Pasted #1 · …]`. Empty when they agree. |
| 49 | 52 | Full string |
| @@ -76,8 +79,9 @@ func (e Entry) Detail() string { | ||
| 76 | 79 | type Transcript struct { |
| 77 | 80 | mu sync.Mutex |
| 78 | 81 | 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 | |
| 81 | 85 | now func() time.Time |
| 82 | 86 | } |
| 83 | 87 | |
| @@ -131,14 +135,22 @@ func (t *Transcript) Chunk(text string) { | ||
| 131 | 135 | } |
| 132 | 136 | t.mu.Lock() |
| 133 | 137 | 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 | |
| 136 | 140 | 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 | 143 | 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 | 154 | // Thinking appends a chunk of reasoning, growing the open thought entry |
| 143 | 155 | // rather than starting one per fragment — the same rule as Chunk, with its |
| 144 | 156 | // 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 Kind | 45 | Kind Kind |
| 46 | Text string // the question, the answer, the notice; a tool's OUTPUT | 46 | 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 collapsed | 50 | // 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 string | 52 | Full string |
| @@ -76,8 +79,9 @@ func (e Entry) Detail() string { | |||
| 76 | type Transcript struct { | 79 | type Transcript struct { |
| 77 | mu sync.Mutex | 80 | mu sync.Mutex |
| 78 | entries []Entry | 81 | entries []Entry |
| 79 | - open bool // the last entry is an agent run still receiving chunks | 82 | + open bool // the last entry is an agent run still receiving chunks |
| 80 | - tools int // tool calls recorded, for the status bar | 83 | + speaker string // Who of the answers being streamed; "" = this agent |
| 84 | + tools int // tool calls recorded, for the status bar | ||
| 81 | now func() time.Time | 85 | 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 += text | 139 | + t.entries[last].Text += text |
| 136 | return | 140 | 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 = true | 143 | 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 entry | 154 | // Thinking appends a chunk of reasoning, growing the open thought entry |
| 143 | // rather than starting one per fragment — the same rule as Chunk, with its | 155 | // 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 { | ||
| 114 | 114 | ask *permission |
| 115 | 115 | 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 | 121 | // streamed says the sink saw at least one chunk this turn. An answer |
| 118 | 122 | // that did not stream (a test model, or a server answering in one block |
| 119 | 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 | 361 | // 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 | 364 | func (r *runner) header() string { |
| 360 | 365 | 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 | 373 | fmt.Fprintf(&b, "%s · %s @ %s", r.opts.AgentName, shortModel(r.opts.ModelName), r.opts.Provider) |
| 362 | 374 | used := max(r.opts.Model.LastInputTokens(), compact.Estimate(r.messages)) |
| 363 | 375 | if w := r.opts.Window(); w > 0 { |
| @@ -114,6 +114,10 @@ type runner struct { | |||
| 114 | ask *permission | 114 | ask *permission |
| 115 | policy consent.Policy // "for this session" and "never", per tool | 115 | 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 answer | 121 | // 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 block | 122 | // 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, which | 361 | // 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.Builder | 365 | 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 | ||
| 269 | 269 | Detector: d, |
| 270 | 270 | System: config.Cfg.System, |
| 271 | 271 | Cwd: cwd, |
| 272 | - AgentName: "mm", | |
| 272 | + AgentName: tui.AgentLabel(config.Cfg.ACP.Title), | |
| 273 | 273 | ModelName: config.Cfg.Model, |
| 274 | 274 | Provider: e.Backend.Provider, |
| 275 | 275 | 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/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. | ||