🛟 Updated.
ad83d0e parent: 9a5c4ec modified
.tickets/issues/0152-dev-team.yaml +304 -2 | @@ -6,7 +6,7 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-25T04:44:30.351Z |
| 9 | -updatedAt: 2026-10-25T05:15:11.308Z | |
| 9 | +updatedAt: 2026-10-25T12:30:00.000Z | |
| 10 | 10 | labels: [] |
| 11 | 11 | epic: Demos |
| 12 | 12 | body: |+ |
| @@ -53,7 +53,52 @@ body: |+ | ||
| 53 | 53 | |
| 54 | 54 | |
| 55 | 55 | |
| 56 | -tasks: [] | |
| 56 | +tasks: | |
| 57 | + - id: 1 | |
| 58 | + title: "Créer ./dev.team : 5 agents (coordinator, reformulator, tutor, coder, reviewer), hook de déchargement, projet d'essai" | |
| 59 | + state: closed | |
| 60 | + priority: none | |
| 61 | + author: | |
| 62 | + name: k33g | |
| 63 | + email: ph.charriere@gmail.com | |
| 64 | + createdAt: 2026-10-25T07:30:00.000Z | |
| 65 | + updatedAt: 2026-10-25T07:30:00.000Z | |
| 66 | + - id: 2 | |
| 67 | + title: "Mesurer chaque agent seul (mm -p) sur des exemples réels, ajuster prompts et réglages" | |
| 68 | + state: closed | |
| 69 | + priority: none | |
| 70 | + author: | |
| 71 | + name: k33g | |
| 72 | + email: ph.charriere@gmail.com | |
| 73 | + createdAt: 2026-10-25T07:30:00.000Z | |
| 74 | + updatedAt: 2026-10-25T07:30:00.000Z | |
| 75 | + - id: 3 | |
| 76 | + title: "Mesurer l'équipe de bout en bout via le coordinateur, vérifier le déchargement des modèles (/api/ps)" | |
| 77 | + state: closed | |
| 78 | + priority: none | |
| 79 | + author: | |
| 80 | + name: k33g | |
| 81 | + email: ph.charriere@gmail.com | |
| 82 | + createdAt: 2026-10-25T07:30:00.000Z | |
| 83 | + updatedAt: 2026-10-25T07:30:00.000Z | |
| 84 | + - id: 4 | |
| 85 | + title: "Répondre à la question du modèle de décision (mesure du routage du coordinateur)" | |
| 86 | + state: closed | |
| 87 | + priority: none | |
| 88 | + author: | |
| 89 | + name: k33g | |
| 90 | + email: ph.charriere@gmail.com | |
| 91 | + createdAt: 2026-10-25T07:30:00.000Z | |
| 92 | + updatedAt: 2026-10-25T07:30:00.000Z | |
| 93 | + - id: 5 | |
| 94 | + title: "README EN + FR avec diagrammes fancy et exemples d'utilisation ; ligne dans le README racine" | |
| 95 | + state: closed | |
| 96 | + priority: none | |
| 97 | + author: | |
| 98 | + name: k33g | |
| 99 | + email: ph.charriere@gmail.com | |
| 100 | + createdAt: 2026-10-25T07:30:00.000Z | |
| 101 | + updatedAt: 2026-10-25T07:30:00.000Z | |
| 57 | 102 | comments: |
| 58 | 103 | - id: 1 |
| 59 | 104 | author: |
| @@ -172,3 +217,260 @@ comments: | ||
| 172 | 217 | name. |
| 173 | 218 | |
| 174 | 219 | ``` |
| 220 | + - id: 2 | |
| 221 | + author: | |
| 222 | + name: k33g | |
| 223 | + email: ph.charriere@gmail.com | |
| 224 | + createdAt: 2026-10-25T07:30:00.000Z | |
| 225 | + body: | | |
| 226 | + Plan (2026-10-25), avant de coder. | |
| 227 | + | |
| 228 | + ## Ce qui existe déjà et que je réutilise | |
| 229 | + - demos/team : un coordinateur + 3 spécialistes via `ask_agent` (mmConfigs). | |
| 230 | + - demos/unload-models/hooks/unload.js : hooks `preAsk` (décharge le modèle | |
| 231 | + de l'agent qui demande, juste avant de lancer l'agent demandé) et | |
| 232 | + `postAsk` (décharge le modèle de l'agent demandé une fois sa réponse | |
| 233 | + reçue). C'est une garantie, pas une consigne au modèle : la doc | |
| 234 | + unload-a-model mesure qu'un petit modèle oublie d'appeler unload_model | |
| 235 | + (4 fois sur 5 avec MiniCPM5 2B). Deux modèles ne sont donc jamais | |
| 236 | + chargés ensemble. | |
| 237 | + - Les trois modèles demandés sont déjà dans llmman : Qwen3.5-4B Q4_K_M | |
| 238 | + (3,4 Go), gemma-4-12b-it Q4_K_M (7,3 Go), Mellum2-12B-A2.5B-Instruct | |
| 239 | + Q4_K_M (8,1 Go). Avec le déchargement, le pic mémoire est un seul | |
| 240 | + modèle de 12B (~8 Go + cache KV), à l'aise sur 32 Go. | |
| 241 | + | |
| 242 | + ## Agents (noms et fichiers en anglais, titres avec emoji) | |
| 243 | + - coordinator (Qwen3.5-4B, sans raisonnement) : seulement `ask_agent`. | |
| 244 | + - reformulator (gemma-4-12b) : `ask_user` activé (et `askUser: true` dans | |
| 245 | + mmConfigs pour que ses questions remontent à l'utilisateur), aucun outil | |
| 246 | + qui modifie. | |
| 247 | + - tutor (Mellum2 Instruct Q4_K_M) : la config « prof » du commentaire 1, | |
| 248 | + adaptée (modèle Q4_K_M au lieu de Q8_0 comme le ticket le demande). | |
| 249 | + - coder (Mellum2 Instruct Q4_K_M) : bash, fichiers, plan. | |
| 250 | + - reviewer (gemma-4-12b) : bash pour lancer les tests, écrit des tests, | |
| 251 | + ne modifie pas le code de l'application. | |
| 252 | + | |
| 253 | + Tutor et coder partagent le même modèle, reformulator et reviewer aussi : | |
| 254 | + passer de l'un à l'autre ne recharge rien. | |
| 255 | + | |
| 256 | + ## Question du modèle de décision | |
| 257 | + À trancher par la mesure : si le coordinateur 4B route bien (prof / code / | |
| 258 | + reformulation), un décideur n'apporte rien ; s'il se trompe, un décideur | |
| 259 | + de choix dans un hook preGeneration (comme demos/decision-chat) peut lui | |
| 260 | + donner la route. | |
| 261 | + - id: 3 | |
| 262 | + author: | |
| 263 | + name: k33g | |
| 264 | + email: ph.charriere@gmail.com | |
| 265 | + createdAt: 2026-10-25T07:45:00.000Z | |
| 266 | + body: | | |
| 267 | + Tâche 1 faite (non commitée) : ./dev.team | |
| 268 | + - agent.yaml (coordinator, 🧭 Coordinator), agent.reformulator.yaml | |
| 269 | + (📝), agent.coder.yaml (🛠️), agent.reviewer.yaml (🔎), | |
| 270 | + agent.tutor.yaml (📘, la config « prof » adaptée : Q4_K_M, sans lsp | |
| 271 | + Rust ni docSearch — pas de code Rust ni de docs/ ici). | |
| 272 | + - hooks/unload.js (copie de demos/unload-models) branché sur preAsk | |
| 273 | + (self) et postAsk (asked) du coordinateur ; unloadModels: false pour | |
| 274 | + que le modèle n'ait pas à y penser. | |
| 275 | + - starter/textstats : un petit paquet Go avec tests, un bug connu | |
| 276 | + (WordCount et les espaces multiples) et de la place pour une | |
| 277 | + fonctionnalité ; `sh reset.sh` le copie dans playground/ et en fait | |
| 278 | + un dépôt git, pour que le reviewer lise `git diff`. | |
| 279 | + - Deux diagrammes (dev-team-flow, dev-team-memory) générés par | |
| 280 | + .claude/skills/drawio-fancy-diagram/generator/examples/dev_team.py. | |
| 281 | + | |
| 282 | + Tâche 2 en cours. Première mesure du coder seul (bug WordCount) : | |
| 283 | + Mellum2 Q4_K_M a produit un appel d'outil coupé à max_tokens | |
| 284 | + (« tool call arguments did not parse … unexpected end of JSON | |
| 285 | + input ») après un edit_file raté — à suivre. | |
| 286 | + - id: 4 | |
| 287 | + author: | |
| 288 | + name: k33g | |
| 289 | + email: ph.charriere@gmail.com | |
| 290 | + createdAt: 2026-10-25T08:30:00.000Z | |
| 291 | + body: | | |
| 292 | + Tâche 2 faite — chaque agent seul, mesuré sur llmman : | |
| 293 | + - coder (Mellum2) : bug WordCount corrigé (strings.Fields) + 4 cas de | |
| 294 | + test, tests verts, 351 s. Un appel d'outil jamais refermé a couru | |
| 295 | + jusqu'à max_tokens (8192) : max_tokens ramené à 4096 ; gofmt ajouté au | |
| 296 | + prompt (le test ajouté n'était pas formaté). | |
| 297 | + - reviewer (Gemma 4 12B) : git diff, tests, review_test.go à lui, | |
| 298 | + « VERDICT: PASS », 151 s. | |
| 299 | + - tutor (Mellum2) : 24 s, mais il a inventé « un fichier typique » au | |
| 300 | + lieu de lire playground/textstats_test.go. Règle ajoutée (read_file | |
| 301 | + d'abord, citer le vrai code) : 3 sur 3 lisent le fichier et citent la | |
| 302 | + vraie table map[string]int, 12 à 19 s. | |
| 303 | + - reformulator (Gemma 4 12B) : appelle bien ask_user ; avec `-p` | |
| 304 | + personne ne peut répondre, et la 1re version décidait seule (et | |
| 305 | + mettait « top N » hors périmètre pour « les mots les plus | |
| 306 | + fréquents »). Prompt resserré + section ASSUMPTIONS : il liste | |
| 307 | + maintenant ses choix (top 5, casse ignorée…), 62 s. | |
| 308 | + - unload_model retiré des 4 membres (unloadModels: false) : ce sont les | |
| 309 | + hooks du coordinateur qui déchargent. | |
| 310 | + | |
| 311 | + Tâche 4 faite — faut-il un modèle de décision ? | |
| 312 | + Mesure du routage du coordinateur Qwen3.5-4B sur 12 demandes (5 code, | |
| 313 | + 5 leçons dont 2 en français, 2 revues) : 12/12 vers le bon agent. Un | |
| 314 | + décideur pour router n'apporterait donc rien ici, et coûterait un modèle | |
| 315 | + et un appel de plus. Où il serait utile, à mesurer si besoin : détecter | |
| 316 | + une demande vague avant d'appeler le reformulateur (noul), ou trier le | |
| 317 | + verdict du reviewer — pas nécessaire tant que le prompt suffit. | |
| 318 | + Effet de bord vu pendant la mesure : quand ask_agent est refusé, le 4B | |
| 319 | + essaie un autre agent au lieu de s'arrêter (sans conséquence avec | |
| 320 | + yolo: true). | |
| 321 | + - id: 5 | |
| 322 | + author: | |
| 323 | + name: k33g | |
| 324 | + email: ph.charriere@gmail.com | |
| 325 | + createdAt: 2026-10-25T10:00:00.000Z | |
| 326 | + body: | | |
| 327 | + Tâche 3 en cours — l'équipe de bout en bout (coordinateur, `-p`, | |
| 328 | + AGENT_YOLO=true), /api/ps échantillonné toutes les 2 s : | |
| 329 | + | |
| 330 | + - Déchargement : sur les 4 exécutions, jamais deux modèles chargés en | |
| 331 | + même temps (0 échantillon avec deux modèles). Séquence typique : | |
| 332 | + 4B → Gemma → 4B → Mellum2 → 4B → Gemma → 4B. | |
| 333 | + - Route A, bug WordCount, 1re exécution : 685 s, PASS, mais le coder a | |
| 334 | + bouclé sur `plan update` (appels en échec) et le coordinateur l'a | |
| 335 | + rappelé ; son rapport final disait à tort « aucune modification ». | |
| 336 | + → planTool: false pour le coder (le brief tient lieu de plan), le | |
| 337 | + reviewer vérifie gofmt et les cas de test supprimés, le rapport | |
| 338 | + reprend les fichiers des réponses du coder et du reviewer. | |
| 339 | + - Route A, bug WordCount, 2e exécution : 398 s, un appel par agent, | |
| 340 | + gofmt propre, VERDICT: PASS, rapport exact. Reste : le coder a | |
| 341 | + réécrit des cas de test existants au lieu d'en ajouter seulement. | |
| 342 | + - Route B (leçon en français) : 49 s, tutor seul, réponse juste en | |
| 343 | + français. | |
| 344 | + - Route A, nouvelle fonction « mots les plus fréquents » : ÉCHEC après | |
| 345 | + 52 min. Le brief était bon (top 5, ponctuation, égalités par ordre | |
| 346 | + alphabétique, ASSUMPTIONS) ; puis le reviewer a testé un comportement | |
| 347 | + absent du brief (garder les apostrophes) et atteint ses 20 tours, le | |
| 348 | + 4B a rappelé le reviewer puis le coder 4 fois (malgré la consigne), | |
| 349 | + et les edit_file de Mellum2 échouaient en série. Tests rouges à la | |
| 350 | + fin. | |
| 351 | + → reviewer : tests limités à ACCEPTANCE/REQUIREMENTS, maxTurns 12 ; | |
| 352 | + coordinateur : maxTurns 6, « ne jamais redemander à un agent ». | |
| 353 | + | |
| 354 | + Je remets en question un choix de modèle, comme le ticket le permet : | |
| 355 | + je compare le coder Mellum2 à Ornith 1.5 9B Q4_K_M (6,7 Go, 5 sur 5 en | |
| 356 | + bout en bout dans demos/team) sur le même brief, chacun seul, avec un | |
| 357 | + test caché tiré de l'ACCEPTANCE du brief. | |
| 358 | + - id: 6 | |
| 359 | + author: | |
| 360 | + name: k33g | |
| 361 | + email: ph.charriere@gmail.com | |
| 362 | + createdAt: 2026-10-25T10:30:00.000Z | |
| 363 | + body: | | |
| 364 | + Tâches 3 et 5 faites — l'état final (non commité, à relire). | |
| 365 | + | |
| 366 | + ## Comparaison des coders (le ticket permet de discuter les modèles) | |
| 367 | + Chacun seul sur le même brief (« mots les plus fréquents »), vérifié par | |
| 368 | + un test caché tiré de l'ACCEPTANCE du brief, go vet et gofmt : | |
| 369 | + - Mellum2 12B-A2.5B : 2 sur 3, 129 s, 132 s, 639 s (l'échec : appels | |
| 370 | + d'outil coupés à max_tokens, test qui compare des slices avec !=) ; | |
| 371 | + jamais formaté → hook postToolCall hooks/gofmt.js (gofmt -w sur chaque | |
| 372 | + fichier .go écrit ; une erreur de syntaxe revient au modèle). | |
| 373 | + - Ornith 1.5 9B (raisonnement activé) : 2 sur 2, 783 s et 810 s, formaté. | |
| 374 | + Mellum2 reste le coder par défaut (ton choix, ~6× plus rapide) ; | |
| 375 | + agent.coder.ornith.yaml est fourni comme alternative plus régulière. | |
| 376 | + | |
| 377 | + ## Équipe complète, 2e exécution « mots les plus fréquents » | |
| 378 | + Échec encore : bon brief (top 3), puis la même coupure du coder, le 4B | |
| 379 | + le redemande malgré la consigne, le reviewer reste à VERDICT: FAIL | |
| 380 | + (2 cas sur 7) ; arrêté à 30 min. | |
| 381 | + | |
| 382 | + ## Bilan | |
| 383 | + - Fonctionne : corrections de bugs (398 s, PASS), leçons (12–49 s, en | |
| 384 | + français quand on écrit en français), revues. | |
| 385 | + - Pas encore fiable : les nouvelles fonctionnalités, à cause du coder | |
| 386 | + Mellum2 et du coordinateur 4B qui relance un agent après un échec. | |
| 387 | + - Mémoire : pendant les passages de main, jamais deux modèles chargés. | |
| 388 | + Seul chevauchement vu : un Mellum2 laissé chargé par une de mes | |
| 389 | + mesures avant le démarrage — les hooks ne déchargent pas un modèle | |
| 390 | + chargé par autre chose (noté dans les limites). | |
| 391 | + - Un membre a écrit un main.go dans dev.team/ (hors playground), ce qui | |
| 392 | + cassait `go vet ./...` de mm : supprimé, et dev.team/go.mod isole | |
| 393 | + maintenant le dossier. | |
| 394 | + - Docs : dev.team/README.en.md et README.fr.md (routes, mémoire, | |
| 395 | + exemples, mesures, limites), deux diagrammes (dev-team-flow, | |
| 396 | + dev-team-memory) + ligne dans le README racine. | |
| 397 | + | |
| 398 | + ## Pistes, non faites | |
| 399 | + - Faire respecter « une seule correction » par un hook preAsk qui | |
| 400 | + compte les appels au coder (au lieu du prompt du 4B). | |
| 401 | + - Essayer l'équipe complète avec agent.coder.ornith.yaml sur la | |
| 402 | + fonctionnalité. | |
| 403 | + - Un hook preToolCall pour que le bash du reformulator ne puisse | |
| 404 | + vraiment que lire. | |
| 405 | + - id: 7 | |
| 406 | + author: | |
| 407 | + name: k33g | |
| 408 | + email: ph.charriere@gmail.com | |
| 409 | + createdAt: 2026-10-25T11:30:00.000Z | |
| 410 | + body: | | |
| 411 | + Demande : « active le lsp go pour les agents ». Fait (non commité). | |
| 412 | + | |
| 413 | + - Bloc `lsp` (gopls, .go) dans les 4 spécialistes et le coder Ornith ; | |
| 414 | + pas dans le coordinateur (seulement ask_agent, par choix). Chaque | |
| 415 | + prompt dit quoi en faire : coder references / rename / diagnostics ; | |
| 416 | + reviewer references + diagnostics sur ce que touche le diff ; | |
| 417 | + reformulator references / symbols ; tutor hover / definition. Seul | |
| 418 | + le coder a le droit de faire `rename`. | |
| 419 | + - gopls doit être dans le PATH (go install | |
| 420 | + golang.org/x/tools/gopls@latest) ; sinon avertissement et pas d'outil. | |
| 421 | + gopls trouve playground/go.mod tout seul depuis dev.team/. | |
| 422 | + | |
| 423 | + Mesures (gopls v0.24.0) : | |
| 424 | + - coder, « Rename LineCount to CountLines everywhere in playground » : | |
| 425 | + 1re version, Mellum2 appelle rename sans new_name puis recopie | |
| 426 | + l'indication : la fonction devient `new_name`, et il annonce | |
| 427 | + « renommée en CountLines ». Avec un exemple rempli dans le prompt (et | |
| 428 | + « vérifie l'ancien ET le nouveau nom avant de répondre ») : 3 sur 3 | |
| 429 | + justes, 5 à 10 s. | |
| 430 | + - reviewer sur ce renommage : il lançait `git diff` depuis dev.team | |
| 431 | + (dépôt de mm, où playground/ est ignoré → diff vide) et tournait en | |
| 432 | + rond jusqu'à maxTurns. Prompt : diff DANS le projet, puis lsp | |
| 433 | + references + diagnostics ; maxTurns 12 → 16 (12 coupait une revue | |
| 434 | + normale de 13 appels). Ensuite : 1 exécution avec un appel d'outil | |
| 435 | + qui se répétait (arrêté par mm), 1 avec references + diagnostics et | |
| 436 | + un vrai constat (le message d'erreur du test dit encore LineCount : | |
| 437 | + rename change les identifiants, pas les chaînes), VERDICT: FAIL. | |
| 438 | + - READMEs EN/FR : section « serveur de langage Go », prérequis gopls, | |
| 439 | + tableau des mesures. | |
| 440 | + - id: 8 | |
| 441 | + author: | |
| 442 | + name: k33g | |
| 443 | + email: ph.charriere@gmail.com | |
| 444 | + createdAt: 2026-10-25T12:30:00.000Z | |
| 445 | + body: | | |
| 446 | + Demande : protéger les fichiers d'agents dans la sandbox (sbxenv.yaml, | |
| 447 | + start-zed.sh, stop-zed.sh), mini-me devant voir le dossier de la démo. | |
| 448 | + Fait (non commité) : | |
| 449 | + | |
| 450 | + - dev.team/ (jamais monté) : sbxenv.yaml, start-zed.sh, stop-zed.sh, | |
| 451 | + READMEs, diagrammes — Docker recommande de garder le fichier | |
| 452 | + d'environnement hors des dossiers montés. | |
| 453 | + - dev.team/team/ : agent*.yaml + hooks/, monté en | |
| 454 | + `additionalWorkspaces: [{path: ./team, readOnly: true}]`. | |
| 455 | + - dev.team/workspace/ : `workspace: ./workspace` (lecture-écriture) — | |
| 456 | + playground/, ton demo/, starter/, reset.sh, .mm/ (sessions). | |
| 457 | + - mm trouve le coordinateur par `env: AGENT_CONFIG: | |
| 458 | + ${{ env.args.DEV_TEAM_DIR }}/team/agent.yaml` ; start-zed.sh passe | |
| 459 | + `--env-arg DEV_TEAM_DIR="$PWD"` et ouvre | |
| 460 | + `ssh://zed-dev-team.sbx$PWD/workspace`. Les autres agents et les hooks | |
| 461 | + sont trouvés à côté de team/agent.yaml. | |
| 462 | + | |
| 463 | + Vérifié ici (sans sbx, team/ mis en lecture seule par chmod pour | |
| 464 | + simuler le montage, mm lancé depuis workspace/ avec seulement | |
| 465 | + AGENT_CONFIG) : route B 55 s ; route A (bug WordCount) VERDICT: PASS en | |
| 466 | + 359 s, team/ inchangé. Droits rétablis ensuite. | |
| 467 | + | |
| 468 | + Non vérifié (pas de sbx dans cet environnement) : que la sandbox monte | |
| 469 | + team/ au même chemin absolu que sur la machine (AGENT_CONFIG en dépend ; | |
| 470 | + ton `ssh://…sbx$PWD` actuel le laisse penser), et qu'une session Zed | |
| 471 | + SSH reçoit bien les variables de `env:`. Les commandes de vérification | |
| 472 | + sont dans les READMEs (section « Lancer »). | |
| 473 | + | |
| 474 | + Remarque : dev.team/go.mod n'était plus là (supprimé de ton côté ?) — | |
| 475 | + je ne l'ai pas remis. | |
| 476 | + | |
| @@ -6,7 +6,7 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-25T04:44:30.351Z | 8 | createdAt: 2026-10-25T04:44:30.351Z |
| 9 | -updatedAt: 2026-10-25T05:15:11.308Z | 9 | +updatedAt: 2026-10-25T12:30:00.000Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | epic: Demos | 11 | epic: Demos |
| 12 | body: |+ | 12 | body: |+ |
| @@ -53,7 +53,52 @@ body: |+ | |||
| 53 | 53 | ||
| 54 | 54 | ||
| 55 | 55 | ||
| 56 | -tasks: [] | 56 | +tasks: |
| 57 | + - id: 1 | ||
| 58 | + title: "Créer ./dev.team : 5 agents (coordinator, reformulator, tutor, coder, reviewer), hook de déchargement, projet d'essai" | ||
| 59 | + state: closed | ||
| 60 | + priority: none | ||
| 61 | + author: | ||
| 62 | + name: k33g | ||
| 63 | + email: ph.charriere@gmail.com | ||
| 64 | + createdAt: 2026-10-25T07:30:00.000Z | ||
| 65 | + updatedAt: 2026-10-25T07:30:00.000Z | ||
| 66 | + - id: 2 | ||
| 67 | + title: "Mesurer chaque agent seul (mm -p) sur des exemples réels, ajuster prompts et réglages" | ||
| 68 | + state: closed | ||
| 69 | + priority: none | ||
| 70 | + author: | ||
| 71 | + name: k33g | ||
| 72 | + email: ph.charriere@gmail.com | ||
| 73 | + createdAt: 2026-10-25T07:30:00.000Z | ||
| 74 | + updatedAt: 2026-10-25T07:30:00.000Z | ||
| 75 | + - id: 3 | ||
| 76 | + title: "Mesurer l'équipe de bout en bout via le coordinateur, vérifier le déchargement des modèles (/api/ps)" | ||
| 77 | + state: closed | ||
| 78 | + priority: none | ||
| 79 | + author: | ||
| 80 | + name: k33g | ||
| 81 | + email: ph.charriere@gmail.com | ||
| 82 | + createdAt: 2026-10-25T07:30:00.000Z | ||
| 83 | + updatedAt: 2026-10-25T07:30:00.000Z | ||
| 84 | + - id: 4 | ||
| 85 | + title: "Répondre à la question du modèle de décision (mesure du routage du coordinateur)" | ||
| 86 | + state: closed | ||
| 87 | + priority: none | ||
| 88 | + author: | ||
| 89 | + name: k33g | ||
| 90 | + email: ph.charriere@gmail.com | ||
| 91 | + createdAt: 2026-10-25T07:30:00.000Z | ||
| 92 | + updatedAt: 2026-10-25T07:30:00.000Z | ||
| 93 | + - id: 5 | ||
| 94 | + title: "README EN + FR avec diagrammes fancy et exemples d'utilisation ; ligne dans le README racine" | ||
| 95 | + state: closed | ||
| 96 | + priority: none | ||
| 97 | + author: | ||
| 98 | + name: k33g | ||
| 99 | + email: ph.charriere@gmail.com | ||
| 100 | + createdAt: 2026-10-25T07:30:00.000Z | ||
| 101 | + updatedAt: 2026-10-25T07:30:00.000Z | ||
| 57 | comments: | 102 | comments: |
| 58 | - id: 1 | 103 | - id: 1 |
| 59 | author: | 104 | author: |
| @@ -172,3 +217,260 @@ comments: | |||
| 172 | name. | 217 | name. |
| 173 | 218 | ||
| 174 | ``` | 219 | ``` |
| 220 | + - id: 2 | ||
| 221 | + author: | ||
| 222 | + name: k33g | ||
| 223 | + email: ph.charriere@gmail.com | ||
| 224 | + createdAt: 2026-10-25T07:30:00.000Z | ||
| 225 | + body: | | ||
| 226 | + Plan (2026-10-25), avant de coder. | ||
| 227 | + | ||
| 228 | + ## Ce qui existe déjà et que je réutilise | ||
| 229 | + - demos/team : un coordinateur + 3 spécialistes via `ask_agent` (mmConfigs). | ||
| 230 | + - demos/unload-models/hooks/unload.js : hooks `preAsk` (décharge le modèle | ||
| 231 | + de l'agent qui demande, juste avant de lancer l'agent demandé) et | ||
| 232 | + `postAsk` (décharge le modèle de l'agent demandé une fois sa réponse | ||
| 233 | + reçue). C'est une garantie, pas une consigne au modèle : la doc | ||
| 234 | + unload-a-model mesure qu'un petit modèle oublie d'appeler unload_model | ||
| 235 | + (4 fois sur 5 avec MiniCPM5 2B). Deux modèles ne sont donc jamais | ||
| 236 | + chargés ensemble. | ||
| 237 | + - Les trois modèles demandés sont déjà dans llmman : Qwen3.5-4B Q4_K_M | ||
| 238 | + (3,4 Go), gemma-4-12b-it Q4_K_M (7,3 Go), Mellum2-12B-A2.5B-Instruct | ||
| 239 | + Q4_K_M (8,1 Go). Avec le déchargement, le pic mémoire est un seul | ||
| 240 | + modèle de 12B (~8 Go + cache KV), à l'aise sur 32 Go. | ||
| 241 | + | ||
| 242 | + ## Agents (noms et fichiers en anglais, titres avec emoji) | ||
| 243 | + - coordinator (Qwen3.5-4B, sans raisonnement) : seulement `ask_agent`. | ||
| 244 | + - reformulator (gemma-4-12b) : `ask_user` activé (et `askUser: true` dans | ||
| 245 | + mmConfigs pour que ses questions remontent à l'utilisateur), aucun outil | ||
| 246 | + qui modifie. | ||
| 247 | + - tutor (Mellum2 Instruct Q4_K_M) : la config « prof » du commentaire 1, | ||
| 248 | + adaptée (modèle Q4_K_M au lieu de Q8_0 comme le ticket le demande). | ||
| 249 | + - coder (Mellum2 Instruct Q4_K_M) : bash, fichiers, plan. | ||
| 250 | + - reviewer (gemma-4-12b) : bash pour lancer les tests, écrit des tests, | ||
| 251 | + ne modifie pas le code de l'application. | ||
| 252 | + | ||
| 253 | + Tutor et coder partagent le même modèle, reformulator et reviewer aussi : | ||
| 254 | + passer de l'un à l'autre ne recharge rien. | ||
| 255 | + | ||
| 256 | + ## Question du modèle de décision | ||
| 257 | + À trancher par la mesure : si le coordinateur 4B route bien (prof / code / | ||
| 258 | + reformulation), un décideur n'apporte rien ; s'il se trompe, un décideur | ||
| 259 | + de choix dans un hook preGeneration (comme demos/decision-chat) peut lui | ||
| 260 | + donner la route. | ||
| 261 | + - id: 3 | ||
| 262 | + author: | ||
| 263 | + name: k33g | ||
| 264 | + email: ph.charriere@gmail.com | ||
| 265 | + createdAt: 2026-10-25T07:45:00.000Z | ||
| 266 | + body: | | ||
| 267 | + Tâche 1 faite (non commitée) : ./dev.team | ||
| 268 | + - agent.yaml (coordinator, 🧭 Coordinator), agent.reformulator.yaml | ||
| 269 | + (📝), agent.coder.yaml (🛠️), agent.reviewer.yaml (🔎), | ||
| 270 | + agent.tutor.yaml (📘, la config « prof » adaptée : Q4_K_M, sans lsp | ||
| 271 | + Rust ni docSearch — pas de code Rust ni de docs/ ici). | ||
| 272 | + - hooks/unload.js (copie de demos/unload-models) branché sur preAsk | ||
| 273 | + (self) et postAsk (asked) du coordinateur ; unloadModels: false pour | ||
| 274 | + que le modèle n'ait pas à y penser. | ||
| 275 | + - starter/textstats : un petit paquet Go avec tests, un bug connu | ||
| 276 | + (WordCount et les espaces multiples) et de la place pour une | ||
| 277 | + fonctionnalité ; `sh reset.sh` le copie dans playground/ et en fait | ||
| 278 | + un dépôt git, pour que le reviewer lise `git diff`. | ||
| 279 | + - Deux diagrammes (dev-team-flow, dev-team-memory) générés par | ||
| 280 | + .claude/skills/drawio-fancy-diagram/generator/examples/dev_team.py. | ||
| 281 | + | ||
| 282 | + Tâche 2 en cours. Première mesure du coder seul (bug WordCount) : | ||
| 283 | + Mellum2 Q4_K_M a produit un appel d'outil coupé à max_tokens | ||
| 284 | + (« tool call arguments did not parse … unexpected end of JSON | ||
| 285 | + input ») après un edit_file raté — à suivre. | ||
| 286 | + - id: 4 | ||
| 287 | + author: | ||
| 288 | + name: k33g | ||
| 289 | + email: ph.charriere@gmail.com | ||
| 290 | + createdAt: 2026-10-25T08:30:00.000Z | ||
| 291 | + body: | | ||
| 292 | + Tâche 2 faite — chaque agent seul, mesuré sur llmman : | ||
| 293 | + - coder (Mellum2) : bug WordCount corrigé (strings.Fields) + 4 cas de | ||
| 294 | + test, tests verts, 351 s. Un appel d'outil jamais refermé a couru | ||
| 295 | + jusqu'à max_tokens (8192) : max_tokens ramené à 4096 ; gofmt ajouté au | ||
| 296 | + prompt (le test ajouté n'était pas formaté). | ||
| 297 | + - reviewer (Gemma 4 12B) : git diff, tests, review_test.go à lui, | ||
| 298 | + « VERDICT: PASS », 151 s. | ||
| 299 | + - tutor (Mellum2) : 24 s, mais il a inventé « un fichier typique » au | ||
| 300 | + lieu de lire playground/textstats_test.go. Règle ajoutée (read_file | ||
| 301 | + d'abord, citer le vrai code) : 3 sur 3 lisent le fichier et citent la | ||
| 302 | + vraie table map[string]int, 12 à 19 s. | ||
| 303 | + - reformulator (Gemma 4 12B) : appelle bien ask_user ; avec `-p` | ||
| 304 | + personne ne peut répondre, et la 1re version décidait seule (et | ||
| 305 | + mettait « top N » hors périmètre pour « les mots les plus | ||
| 306 | + fréquents »). Prompt resserré + section ASSUMPTIONS : il liste | ||
| 307 | + maintenant ses choix (top 5, casse ignorée…), 62 s. | ||
| 308 | + - unload_model retiré des 4 membres (unloadModels: false) : ce sont les | ||
| 309 | + hooks du coordinateur qui déchargent. | ||
| 310 | + | ||
| 311 | + Tâche 4 faite — faut-il un modèle de décision ? | ||
| 312 | + Mesure du routage du coordinateur Qwen3.5-4B sur 12 demandes (5 code, | ||
| 313 | + 5 leçons dont 2 en français, 2 revues) : 12/12 vers le bon agent. Un | ||
| 314 | + décideur pour router n'apporterait donc rien ici, et coûterait un modèle | ||
| 315 | + et un appel de plus. Où il serait utile, à mesurer si besoin : détecter | ||
| 316 | + une demande vague avant d'appeler le reformulateur (noul), ou trier le | ||
| 317 | + verdict du reviewer — pas nécessaire tant que le prompt suffit. | ||
| 318 | + Effet de bord vu pendant la mesure : quand ask_agent est refusé, le 4B | ||
| 319 | + essaie un autre agent au lieu de s'arrêter (sans conséquence avec | ||
| 320 | + yolo: true). | ||
| 321 | + - id: 5 | ||
| 322 | + author: | ||
| 323 | + name: k33g | ||
| 324 | + email: ph.charriere@gmail.com | ||
| 325 | + createdAt: 2026-10-25T10:00:00.000Z | ||
| 326 | + body: | | ||
| 327 | + Tâche 3 en cours — l'équipe de bout en bout (coordinateur, `-p`, | ||
| 328 | + AGENT_YOLO=true), /api/ps échantillonné toutes les 2 s : | ||
| 329 | + | ||
| 330 | + - Déchargement : sur les 4 exécutions, jamais deux modèles chargés en | ||
| 331 | + même temps (0 échantillon avec deux modèles). Séquence typique : | ||
| 332 | + 4B → Gemma → 4B → Mellum2 → 4B → Gemma → 4B. | ||
| 333 | + - Route A, bug WordCount, 1re exécution : 685 s, PASS, mais le coder a | ||
| 334 | + bouclé sur `plan update` (appels en échec) et le coordinateur l'a | ||
| 335 | + rappelé ; son rapport final disait à tort « aucune modification ». | ||
| 336 | + → planTool: false pour le coder (le brief tient lieu de plan), le | ||
| 337 | + reviewer vérifie gofmt et les cas de test supprimés, le rapport | ||
| 338 | + reprend les fichiers des réponses du coder et du reviewer. | ||
| 339 | + - Route A, bug WordCount, 2e exécution : 398 s, un appel par agent, | ||
| 340 | + gofmt propre, VERDICT: PASS, rapport exact. Reste : le coder a | ||
| 341 | + réécrit des cas de test existants au lieu d'en ajouter seulement. | ||
| 342 | + - Route B (leçon en français) : 49 s, tutor seul, réponse juste en | ||
| 343 | + français. | ||
| 344 | + - Route A, nouvelle fonction « mots les plus fréquents » : ÉCHEC après | ||
| 345 | + 52 min. Le brief était bon (top 5, ponctuation, égalités par ordre | ||
| 346 | + alphabétique, ASSUMPTIONS) ; puis le reviewer a testé un comportement | ||
| 347 | + absent du brief (garder les apostrophes) et atteint ses 20 tours, le | ||
| 348 | + 4B a rappelé le reviewer puis le coder 4 fois (malgré la consigne), | ||
| 349 | + et les edit_file de Mellum2 échouaient en série. Tests rouges à la | ||
| 350 | + fin. | ||
| 351 | + → reviewer : tests limités à ACCEPTANCE/REQUIREMENTS, maxTurns 12 ; | ||
| 352 | + coordinateur : maxTurns 6, « ne jamais redemander à un agent ». | ||
| 353 | + | ||
| 354 | + Je remets en question un choix de modèle, comme le ticket le permet : | ||
| 355 | + je compare le coder Mellum2 à Ornith 1.5 9B Q4_K_M (6,7 Go, 5 sur 5 en | ||
| 356 | + bout en bout dans demos/team) sur le même brief, chacun seul, avec un | ||
| 357 | + test caché tiré de l'ACCEPTANCE du brief. | ||
| 358 | + - id: 6 | ||
| 359 | + author: | ||
| 360 | + name: k33g | ||
| 361 | + email: ph.charriere@gmail.com | ||
| 362 | + createdAt: 2026-10-25T10:30:00.000Z | ||
| 363 | + body: | | ||
| 364 | + Tâches 3 et 5 faites — l'état final (non commité, à relire). | ||
| 365 | + | ||
| 366 | + ## Comparaison des coders (le ticket permet de discuter les modèles) | ||
| 367 | + Chacun seul sur le même brief (« mots les plus fréquents »), vérifié par | ||
| 368 | + un test caché tiré de l'ACCEPTANCE du brief, go vet et gofmt : | ||
| 369 | + - Mellum2 12B-A2.5B : 2 sur 3, 129 s, 132 s, 639 s (l'échec : appels | ||
| 370 | + d'outil coupés à max_tokens, test qui compare des slices avec !=) ; | ||
| 371 | + jamais formaté → hook postToolCall hooks/gofmt.js (gofmt -w sur chaque | ||
| 372 | + fichier .go écrit ; une erreur de syntaxe revient au modèle). | ||
| 373 | + - Ornith 1.5 9B (raisonnement activé) : 2 sur 2, 783 s et 810 s, formaté. | ||
| 374 | + Mellum2 reste le coder par défaut (ton choix, ~6× plus rapide) ; | ||
| 375 | + agent.coder.ornith.yaml est fourni comme alternative plus régulière. | ||
| 376 | + | ||
| 377 | + ## Équipe complète, 2e exécution « mots les plus fréquents » | ||
| 378 | + Échec encore : bon brief (top 3), puis la même coupure du coder, le 4B | ||
| 379 | + le redemande malgré la consigne, le reviewer reste à VERDICT: FAIL | ||
| 380 | + (2 cas sur 7) ; arrêté à 30 min. | ||
| 381 | + | ||
| 382 | + ## Bilan | ||
| 383 | + - Fonctionne : corrections de bugs (398 s, PASS), leçons (12–49 s, en | ||
| 384 | + français quand on écrit en français), revues. | ||
| 385 | + - Pas encore fiable : les nouvelles fonctionnalités, à cause du coder | ||
| 386 | + Mellum2 et du coordinateur 4B qui relance un agent après un échec. | ||
| 387 | + - Mémoire : pendant les passages de main, jamais deux modèles chargés. | ||
| 388 | + Seul chevauchement vu : un Mellum2 laissé chargé par une de mes | ||
| 389 | + mesures avant le démarrage — les hooks ne déchargent pas un modèle | ||
| 390 | + chargé par autre chose (noté dans les limites). | ||
| 391 | + - Un membre a écrit un main.go dans dev.team/ (hors playground), ce qui | ||
| 392 | + cassait `go vet ./...` de mm : supprimé, et dev.team/go.mod isole | ||
| 393 | + maintenant le dossier. | ||
| 394 | + - Docs : dev.team/README.en.md et README.fr.md (routes, mémoire, | ||
| 395 | + exemples, mesures, limites), deux diagrammes (dev-team-flow, | ||
| 396 | + dev-team-memory) + ligne dans le README racine. | ||
| 397 | + | ||
| 398 | + ## Pistes, non faites | ||
| 399 | + - Faire respecter « une seule correction » par un hook preAsk qui | ||
| 400 | + compte les appels au coder (au lieu du prompt du 4B). | ||
| 401 | + - Essayer l'équipe complète avec agent.coder.ornith.yaml sur la | ||
| 402 | + fonctionnalité. | ||
| 403 | + - Un hook preToolCall pour que le bash du reformulator ne puisse | ||
| 404 | + vraiment que lire. | ||
| 405 | + - id: 7 | ||
| 406 | + author: | ||
| 407 | + name: k33g | ||
| 408 | + email: ph.charriere@gmail.com | ||
| 409 | + createdAt: 2026-10-25T11:30:00.000Z | ||
| 410 | + body: | | ||
| 411 | + Demande : « active le lsp go pour les agents ». Fait (non commité). | ||
| 412 | + | ||
| 413 | + - Bloc `lsp` (gopls, .go) dans les 4 spécialistes et le coder Ornith ; | ||
| 414 | + pas dans le coordinateur (seulement ask_agent, par choix). Chaque | ||
| 415 | + prompt dit quoi en faire : coder references / rename / diagnostics ; | ||
| 416 | + reviewer references + diagnostics sur ce que touche le diff ; | ||
| 417 | + reformulator references / symbols ; tutor hover / definition. Seul | ||
| 418 | + le coder a le droit de faire `rename`. | ||
| 419 | + - gopls doit être dans le PATH (go install | ||
| 420 | + golang.org/x/tools/gopls@latest) ; sinon avertissement et pas d'outil. | ||
| 421 | + gopls trouve playground/go.mod tout seul depuis dev.team/. | ||
| 422 | + | ||
| 423 | + Mesures (gopls v0.24.0) : | ||
| 424 | + - coder, « Rename LineCount to CountLines everywhere in playground » : | ||
| 425 | + 1re version, Mellum2 appelle rename sans new_name puis recopie | ||
| 426 | + l'indication : la fonction devient `new_name`, et il annonce | ||
| 427 | + « renommée en CountLines ». Avec un exemple rempli dans le prompt (et | ||
| 428 | + « vérifie l'ancien ET le nouveau nom avant de répondre ») : 3 sur 3 | ||
| 429 | + justes, 5 à 10 s. | ||
| 430 | + - reviewer sur ce renommage : il lançait `git diff` depuis dev.team | ||
| 431 | + (dépôt de mm, où playground/ est ignoré → diff vide) et tournait en | ||
| 432 | + rond jusqu'à maxTurns. Prompt : diff DANS le projet, puis lsp | ||
| 433 | + references + diagnostics ; maxTurns 12 → 16 (12 coupait une revue | ||
| 434 | + normale de 13 appels). Ensuite : 1 exécution avec un appel d'outil | ||
| 435 | + qui se répétait (arrêté par mm), 1 avec references + diagnostics et | ||
| 436 | + un vrai constat (le message d'erreur du test dit encore LineCount : | ||
| 437 | + rename change les identifiants, pas les chaînes), VERDICT: FAIL. | ||
| 438 | + - READMEs EN/FR : section « serveur de langage Go », prérequis gopls, | ||
| 439 | + tableau des mesures. | ||
| 440 | + - id: 8 | ||
| 441 | + author: | ||
| 442 | + name: k33g | ||
| 443 | + email: ph.charriere@gmail.com | ||
| 444 | + createdAt: 2026-10-25T12:30:00.000Z | ||
| 445 | + body: | | ||
| 446 | + Demande : protéger les fichiers d'agents dans la sandbox (sbxenv.yaml, | ||
| 447 | + start-zed.sh, stop-zed.sh), mini-me devant voir le dossier de la démo. | ||
| 448 | + Fait (non commité) : | ||
| 449 | + | ||
| 450 | + - dev.team/ (jamais monté) : sbxenv.yaml, start-zed.sh, stop-zed.sh, | ||
| 451 | + READMEs, diagrammes — Docker recommande de garder le fichier | ||
| 452 | + d'environnement hors des dossiers montés. | ||
| 453 | + - dev.team/team/ : agent*.yaml + hooks/, monté en | ||
| 454 | + `additionalWorkspaces: [{path: ./team, readOnly: true}]`. | ||
| 455 | + - dev.team/workspace/ : `workspace: ./workspace` (lecture-écriture) — | ||
| 456 | + playground/, ton demo/, starter/, reset.sh, .mm/ (sessions). | ||
| 457 | + - mm trouve le coordinateur par `env: AGENT_CONFIG: | ||
| 458 | + ${{ env.args.DEV_TEAM_DIR }}/team/agent.yaml` ; start-zed.sh passe | ||
| 459 | + `--env-arg DEV_TEAM_DIR="$PWD"` et ouvre | ||
| 460 | + `ssh://zed-dev-team.sbx$PWD/workspace`. Les autres agents et les hooks | ||
| 461 | + sont trouvés à côté de team/agent.yaml. | ||
| 462 | + | ||
| 463 | + Vérifié ici (sans sbx, team/ mis en lecture seule par chmod pour | ||
| 464 | + simuler le montage, mm lancé depuis workspace/ avec seulement | ||
| 465 | + AGENT_CONFIG) : route B 55 s ; route A (bug WordCount) VERDICT: PASS en | ||
| 466 | + 359 s, team/ inchangé. Droits rétablis ensuite. | ||
| 467 | + | ||
| 468 | + Non vérifié (pas de sbx dans cet environnement) : que la sandbox monte | ||
| 469 | + team/ au même chemin absolu que sur la machine (AGENT_CONFIG en dépend ; | ||
| 470 | + ton `ssh://…sbx$PWD` actuel le laisse penser), et qu'une session Zed | ||
| 471 | + SSH reçoit bien les variables de `env:`. Les commandes de vérification | ||
| 472 | + sont dans les READMEs (section « Lancer »). | ||
| 473 | + | ||
| 474 | + Remarque : dev.team/go.mod n'était plus là (supprimé de ton côté ?) — | ||
| 475 | + je ne l'ai pas remis. | ||
| 476 | + | ||
added
.tickets/issues/0153-add-colored-warning-about-the-status-of-the-agen.yaml +16 -0 | new file mode 100644 | ||
| @@ -0,0 +1,16 @@ | ||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | |
| 2 | +id: 153 | |
| 3 | +title: Add colored warning about the status of the agent (hallucinating, endless loop, ...) | |
| 4 | +state: open | |
| 5 | +author: | |
| 6 | + name: k33g | |
| 7 | + email: ph.charriere@gmail.com | |
| 8 | +createdAt: 2026-10-25T08:40:29.067Z | |
| 9 | +updatedAt: 2026-10-25T08:41:17.587Z | |
| 10 | +labels: | |
| 11 | + - priority::urgent | |
| 12 | + - kind::feature | |
| 13 | +milestone: v1.0.1 | |
| 14 | +body: "" | |
| 15 | +tasks: [] | |
| 16 | +comments: [] | |
| new file mode 100644 | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | ||
| 2 | +id: 153 | ||
| 3 | +title: Add colored warning about the status of the agent (hallucinating, endless loop, ...) | ||
| 4 | +state: open | ||
| 5 | +author: | ||
| 6 | + name: k33g | ||
| 7 | + email: ph.charriere@gmail.com | ||
| 8 | +createdAt: 2026-10-25T08:40:29.067Z | ||
| 9 | +updatedAt: 2026-10-25T08:41:17.587Z | ||
| 10 | +labels: | ||
| 11 | + - priority::urgent | ||
| 12 | + - kind::feature | ||
| 13 | +milestone: v1.0.1 | ||
| 14 | +body: "" | ||
| 15 | +tasks: [] | ||
| 16 | +comments: [] | ||
added
.tickets/issues/0154-improve-code-edition.yaml +20 -0 | new file mode 100644 | ||
| @@ -0,0 +1,20 @@ | ||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | |
| 2 | +id: 154 | |
| 3 | +title: Improve code edition | |
| 4 | +state: open | |
| 5 | +author: | |
| 6 | + name: k33g | |
| 7 | + email: ph.charriere@gmail.com | |
| 8 | +createdAt: 2026-10-25T09:48:22.741Z | |
| 9 | +updatedAt: 2026-10-25T09:48:36.954Z | |
| 10 | +labels: [] | |
| 11 | +epic: Debug | |
| 12 | +body: | | |
| 13 | + How to fix: | |
| 14 | + | |
| 15 | + ``` | |
| 16 | + ‣ coder/edit_file coder · edit_file: demo/main.go (1 edit(s)) ✗ failed 0.00s ░ | |
| 17 | + /Users/k33g/kDrive/Rickub/bots-garden/mini-me/dev.team/workspace/demo/main.go: edit #1 changes nothing: old and new are identical | |
| 18 | + ``` | |
| 19 | +tasks: [] | |
| 20 | +comments: [] | |
| new file mode 100644 | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | ||
| 2 | +id: 154 | ||
| 3 | +title: Improve code edition | ||
| 4 | +state: open | ||
| 5 | +author: | ||
| 6 | + name: k33g | ||
| 7 | + email: ph.charriere@gmail.com | ||
| 8 | +createdAt: 2026-10-25T09:48:22.741Z | ||
| 9 | +updatedAt: 2026-10-25T09:48:36.954Z | ||
| 10 | +labels: [] | ||
| 11 | +epic: Debug | ||
| 12 | +body: | | ||
| 13 | + How to fix: | ||
| 14 | + | ||
| 15 | + ``` | ||
| 16 | + ‣ coder/edit_file coder · edit_file: demo/main.go (1 edit(s)) ✗ failed 0.00s ░ | ||
| 17 | + /Users/k33g/kDrive/Rickub/bots-garden/mini-me/dev.team/workspace/demo/main.go: edit #1 changes nothing: old and new are identical | ||
| 18 | + ``` | ||
| 19 | +tasks: [] | ||
| 20 | +comments: [] | ||
added
.tickets/issues/0155-when-adding-a-message-don-t-cancel-the-running-g.yaml +16 -0 | new file mode 100644 | ||
| @@ -0,0 +1,16 @@ | ||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | |
| 2 | +id: 155 | |
| 3 | +title: When adding a message don't cancel the running generation, use something like /btw | |
| 4 | +state: open | |
| 5 | +author: | |
| 6 | + name: k33g | |
| 7 | + email: ph.charriere@gmail.com | |
| 8 | +createdAt: 2026-10-25T10:00:14.109Z | |
| 9 | +updatedAt: 2026-10-25T10:00:27.072Z | |
| 10 | +labels: | |
| 11 | + - priority::urgent | |
| 12 | + - enhancement | |
| 13 | +milestone: v1.0.1 | |
| 14 | +body: "" | |
| 15 | +tasks: [] | |
| 16 | +comments: [] | |
| new file mode 100644 | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | ||
| 2 | +id: 155 | ||
| 3 | +title: When adding a message don't cancel the running generation, use something like /btw | ||
| 4 | +state: open | ||
| 5 | +author: | ||
| 6 | + name: k33g | ||
| 7 | + email: ph.charriere@gmail.com | ||
| 8 | +createdAt: 2026-10-25T10:00:14.109Z | ||
| 9 | +updatedAt: 2026-10-25T10:00:27.072Z | ||
| 10 | +labels: | ||
| 11 | + - priority::urgent | ||
| 12 | + - enhancement | ||
| 13 | +milestone: v1.0.1 | ||
| 14 | +body: "" | ||
| 15 | +tasks: [] | ||
| 16 | +comments: [] | ||
modified
README.md +1 -0 | @@ -141,6 +141,7 @@ The `demos/` directory holds ready-made set-ups (most with a README explaining h | ||
| 141 | 141 | | `demos/mini-mes/` | small teams of agents (`riker` coordinating a specifier and a coder, `gopher` a Go specialist) | |
| 142 | 142 | | `demos/little-coder/` | a Go + htmx web-app generator for a small local model (Mellum2 12B on llmman, 32 GB RAM): a tested starter, skills, `AGENTS.md`, measured results | |
| 143 | 143 | | `demos/team/` | a team of four agents (lead, specifier, coder, tester) on one small model (Ornith 1.5 9B on llmman) building Go + htmx apps through spec and test files, with measured results | |
| 144 | +| `dev.team/` | a team of five agents for a 32 GB laptop (ticket 152): a Qwen3.5 4B coordinator hands each request to a reformulator, a coder, a reviewer or a tutor (Gemma 4 12B, Mellum2 12B); hooks keep one model in memory at a time; measured: bug fixes, lessons and reviews work, new features not yet | | |
| 144 | 145 | | `demos/blog-team/` | the smallest team: a lead, a coder and a reviewer in 75 lines of YAML, one model (Mellum2 12B Q8_0 on llmman), written for a blog post | |
| 145 | 146 | | `demos/translator/` | a French ↔ English translator (Gemma 4 E4B on llmman): `AGENTS.md` for the style, skills for technical texts, e-mails and idioms, `$styles` for professional / informal / Slack versions, `translate.sh` for files | |
| 146 | 147 | | `demos/qwen-style/` | a general coding agent whose system prompt follows Qwen Code's, adapted to mm's tools, in three configurations on llmman: Qwen3.8 27B, Qwen3-Coder-Next, Qwen3.6 35B-A3B — Qwen Code's `new-app` and `simplify` skills, measured results | |
| @@ -141,6 +141,7 @@ The `demos/` directory holds ready-made set-ups (most with a README explaining h | |||
| 141 | | `demos/mini-mes/` | small teams of agents (`riker` coordinating a specifier and a coder, `gopher` a Go specialist) | | 141 | | `demos/mini-mes/` | small teams of agents (`riker` coordinating a specifier and a coder, `gopher` a Go specialist) | |
| 142 | | `demos/little-coder/` | a Go + htmx web-app generator for a small local model (Mellum2 12B on llmman, 32 GB RAM): a tested starter, skills, `AGENTS.md`, measured results | | 142 | | `demos/little-coder/` | a Go + htmx web-app generator for a small local model (Mellum2 12B on llmman, 32 GB RAM): a tested starter, skills, `AGENTS.md`, measured results | |
| 143 | | `demos/team/` | a team of four agents (lead, specifier, coder, tester) on one small model (Ornith 1.5 9B on llmman) building Go + htmx apps through spec and test files, with measured results | | 143 | | `demos/team/` | a team of four agents (lead, specifier, coder, tester) on one small model (Ornith 1.5 9B on llmman) building Go + htmx apps through spec and test files, with measured results | |
| 144 | +| `dev.team/` | a team of five agents for a 32 GB laptop (ticket 152): a Qwen3.5 4B coordinator hands each request to a reformulator, a coder, a reviewer or a tutor (Gemma 4 12B, Mellum2 12B); hooks keep one model in memory at a time; measured: bug fixes, lessons and reviews work, new features not yet | | ||
| 144 | | `demos/blog-team/` | the smallest team: a lead, a coder and a reviewer in 75 lines of YAML, one model (Mellum2 12B Q8_0 on llmman), written for a blog post | | 145 | | `demos/blog-team/` | the smallest team: a lead, a coder and a reviewer in 75 lines of YAML, one model (Mellum2 12B Q8_0 on llmman), written for a blog post | |
| 145 | | `demos/translator/` | a French ↔ English translator (Gemma 4 E4B on llmman): `AGENTS.md` for the style, skills for technical texts, e-mails and idioms, `$styles` for professional / informal / Slack versions, `translate.sh` for files | | 146 | | `demos/translator/` | a French ↔ English translator (Gemma 4 E4B on llmman): `AGENTS.md` for the style, skills for technical texts, e-mails and idioms, `$styles` for professional / informal / Slack versions, `translate.sh` for files | |
| 146 | | `demos/qwen-style/` | a general coding agent whose system prompt follows Qwen Code's, adapted to mm's tools, in three configurations on llmman: Qwen3.8 27B, Qwen3-Coder-Next, Qwen3.6 35B-A3B — Qwen Code's `new-app` and `simplify` skills, measured results | | 147 | | `demos/qwen-style/` | a general coding agent whose system prompt follows Qwen Code's, adapted to mm's tools, in three configurations on llmman: Qwen3.8 27B, Qwen3-Coder-Next, Qwen3.6 35B-A3B — Qwen Code's `new-app` and `simplify` skills, measured results | |
added
dev.team/README.en.md +238 -0 | new file mode 100644 | ||
| @@ -0,0 +1,238 @@ | ||
| 1 | +# dev.team — a team of agents that helps you code | |
| 2 | + | |
| 3 | +*[Version française](README.fr.md)* | |
| 4 | + | |
| 5 | +Five `mm` agents for a 32 GB MacBook Air: a coordinator you talk to, and four specialists it calls with the built-in `ask_agent` tool, one at a time. A hook unloads each model when the team hands over, so **only one model is in memory at a time**. | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | +| Agent | File | Header title | Model (llmman) | Tools | Job | | |
| 10 | +|---|---|---|---|---|---| | |
| 11 | +| coordinator | `agent.yaml` | 🧭 Coordinator | Qwen3.5 4B · 3.4 GB | `ask_agent` only | picks the route, hands over, reports to you | | |
| 12 | +| reformulator | `agent.reformulator.yaml` | 📝 Reformulator | Gemma 4 12B · 7.3 GB | `bash` (reading), `ask_user`, `lsp` (reading) | turns a code request into a task brief; asks you what only you can decide | | |
| 13 | +| coder | `agent.coder.yaml` | 🛠️ Coder | Mellum2 12B-A2.5B · 8.1 GB | `bash`, files, `lsp`; a `gofmt` hook | fixes, adds, changes code; runs the tests | | |
| 14 | +| reviewer | `agent.reviewer.yaml` | 🔎 Reviewer | Gemma 4 12B · 7.3 GB | `bash`, files (tests only), `lsp` (reading) | reads the diff, runs the tests, writes its own edge-case tests, `VERDICT: PASS / FAIL` | | |
| 15 | +| tutor | `agent.tutor.yaml` | 📘 Tutor | Mellum2 12B-A2.5B · 8.1 GB | `fetch_content`, `save_answer`, `bash`, files, `lsp` (reading) | answers questions with a mini tutorial; saves it on request | | |
| 16 | + | |
| 17 | +The full model ids are `hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M`, `hf.co/unsloth/gemma-4-12b-it-GGUF:Q4_K_M` and `hf.co/JetBrains/Mellum2-12B-A2.5B-Instruct-GGUF-Q4_K_M:Q4_K_M`. | |
| 18 | + | |
| 19 | +## The three routes | |
| 20 | + | |
| 21 | +The coordinator reads the request and picks one route (its prompt, in `agent.yaml`): | |
| 22 | + | |
| 23 | +- **A — code to write or change** (a bug, a feature, a rename, tests): reformulator → coder → reviewer. If the reviewer answers `VERDICT: FAIL`, the coder fixes **once** and the reviewer checks again. Then the coordinator reports: who did what, the files, the tests, the verdict. | |
| 24 | +- **B — a question, a lesson, advice** ("how do I…", "what is…", "explique-moi…"): the tutor, and its answer is given as it is. | |
| 25 | +- **C — only a review** of existing code: the reviewer. | |
| 26 | + | |
| 27 | +The team works on the code in **`workspace/`**, which is empty in the repository: put your project there (a git repository, so that the reviewer can read `git diff`), or ask the team to create one. The measurements below were made on `textstats`, a small Go practice package with a known bug (`WordCount` and several spaces), which this folder no longer ships. | |
| 28 | + | |
| 29 | +## One model in memory at a time | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | +The ticket's constraint: when the team switches agent, the current model leaves memory. That is not left to the models (a small model forgets to call `unload_model`: 4 times out of 5 with MiniCPM5 2B in `demos/unload-models`). Two hooks of the coordinator do it, with `hooks/unload.js` (copied from `demos/unload-models`): | |
| 34 | + | |
| 35 | +| Hook | When | Unloads | | |
| 36 | +|---|---|---| | |
| 37 | +| `preAsk` → `unload.js self` | the coordinator has decided to call an agent, before that agent starts | the coordinator's own 4B | | |
| 38 | +| `postAsk` → `unload.js asked` | the agent has answered, before the coordinator reads the answer | the agent's 12B | | |
| 39 | + | |
| 40 | +llmman reloads a model by itself on the next request, so the coordinator's 4B comes back alone to read each answer. Both hooks have `onError: warn`: a failed unload costs memory, not the hand-off. The four specialists have `unloadModels: false`: no `unload_model` tool to think about. | |
| 41 | + | |
| 42 | +Two models are shared on purpose: the reformulator and the reviewer use Gemma 4 12B, the coder and the tutor Mellum2. **Peak memory: one 12B model**, about 8 GB plus its KV cache at a 32k window. | |
| 43 | + | |
| 44 | +### The coder's formatter hook | |
| 45 | + | |
| 46 | +`agent.coder.yaml` has its own `postToolCall` hook: after each `write_file` or `edit_file` on a `.go` file, `hooks/gofmt.js` runs `gofmt -w` on it. The prompt asked for `gofmt` and Mellum2 skipped it in every measured run. When gofmt cannot parse the file, its error goes back to the model as context. | |
| 47 | + | |
| 48 | +### The Go language server | |
| 49 | + | |
| 50 | +The four specialists have an `lsp` block with gopls for `.go` files; the coordinator has no tool but `ask_agent`, by design. Each prompt says what to use it for: | |
| 51 | + | |
| 52 | +| Agent | Uses `lsp` for | | |
| 53 | +|---|---| | |
| 54 | +| coder | `references` before changing a signature, `rename` to rename an identifier everywhere, `diagnostics` after a change | | |
| 55 | +| reviewer | `references` on every function the diff touches, `diagnostics` on each changed file | | |
| 56 | +| reformulator | `references` and `symbols`, to name the files a change touches | | |
| 57 | +| tutor | `hover` and `definition` on a symbol of the code a question is about | | |
| 58 | + | |
| 59 | +Only the coder may `rename`; the others' prompts forbid it. gopls finds the `go.mod` of a project in a sub-folder of `workspace/` by itself, although the agents run from `workspace/` (measured with `textstats`). | |
| 60 | + | |
| 61 | +## Prerequisites | |
| 62 | + | |
| 63 | +- **llmman** serving on its default address, with the three models: | |
| 64 | + | |
| 65 | + ```bash | |
| 66 | + llmman pull hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M | |
| 67 | + llmman pull hf.co/unsloth/gemma-4-12b-it-GGUF:Q4_K_M | |
| 68 | + llmman pull hf.co/JetBrains/Mellum2-12B-A2.5B-Instruct-GGUF-Q4_K_M:Q4_K_M | |
| 69 | + llmman serve | |
| 70 | + ``` | |
| 71 | + | |
| 72 | +- **Node.js** (the hooks), **Go** ≥ 1.24 and **git** (the reviewer reads `git diff`). | |
| 73 | +- **gopls** on the `PATH`: `go install golang.org/x/tools/gopls@latest` (then `$(go env GOPATH)/bin` in the `PATH`). Without it, each specialist starts with a warning and no `lsp` tool. | |
| 74 | +- **mm** built at the repository root: `go build -o mm .` | |
| 75 | + | |
| 76 | +## Layout: agents read-only, code read-write | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | +``` | |
| 81 | +dev.team/ | |
| 82 | +├── sbxenv.yaml, start-zed.sh, stop-zed.sh the sandbox — never mounted | |
| 83 | +├── README.*, dev-team-*.{drawio,svg,png} this documentation | |
| 84 | +├── team/ the agents and their hooks → mounted READ-ONLY | |
| 85 | +└── workspace/ your code (empty in the repository), .mm/ → the read-write workspace | |
| 86 | +``` | |
| 87 | + | |
| 88 | +The agents' files are what decides what the team may do: their prompts, their tools, `yolo`, the hooks. A team member with `bash` and `write_file` could rewrite them, and the next start would run its version. So they live in `team/`, which the sandbox mounts with `readOnly: true`, apart from the code the team changes. Docker also recommends keeping the environment file outside every mounted directory, so that an agent cannot change the commands your host runs: `sbxenv.yaml` and the scripts stay at the root of `dev.team/`, which is not mounted. | |
| 89 | + | |
| 90 | +mm finds the coordinator through `AGENT_CONFIG`, set in `sbxenv.yaml`; the other agents and the hooks are found next to it (`mmConfigs` paths and `$MM_CONFIG_DIR` are relative to `team/agent.yaml`). Sessions and traces go to `workspace/.mm/`, the session's working directory. | |
| 91 | + | |
| 92 | +## Run | |
| 93 | + | |
| 94 | +### In a sandbox, with Zed | |
| 95 | + | |
| 96 | +```bash | |
| 97 | +cd dev.team | |
| 98 | +sbx setup ssh # once | |
| 99 | +./start-zed.sh # sbx env create --env-arg DEV_TEAM_DIR=$PWD, then Zed on workspace/ | |
| 100 | +./stop-zed.sh # removes the sandbox; team/ and workspace/ stay on the host | |
| 101 | +``` | |
| 102 | + | |
| 103 | +`start-zed.sh` passes the folder of `sbxenv.yaml` as the argument `DEV_TEAM_DIR`; `sbxenv.yaml` builds `AGENT_CONFIG=<DEV_TEAM_DIR>/team/agent.yaml` from it. In a terminal of the sandbox, from `workspace/`: `mm -tui` (it reads `AGENT_CONFIG`). | |
| 104 | + | |
| 105 | +To check, once the sandbox is up: `sbx version` (`sbx env` needs 0.39.0 or newer, which is also past CVE-2026-18171, a way to write into a read-only mount in 0.35.0–0.38.0); in the sandbox, `echo $AGENT_CONFIG`, `ls "$(dirname "$AGENT_CONFIG")"` and `touch "$(dirname "$AGENT_CONFIG")/x"`, which must fail. | |
| 106 | + | |
| 107 | +### On the host | |
| 108 | + | |
| 109 | +```bash | |
| 110 | +cd dev.team/workspace | |
| 111 | +AGENT_CONFIG=$PWD/../team/agent.yaml ../../mm -tui | |
| 112 | +../../mm -config ../team/agent.yaml -tui # the same | |
| 113 | +../../mm -config ../team/agent.yaml -p "…" # one request, then exit (the reformulator cannot ask you anything) | |
| 114 | +``` | |
| 115 | + | |
| 116 | +The sandbox publishes ports 8080, 6060 and 5050 to the same ports on the host (`ports` in `sbxenv.yaml`, applied at creation): a server started in the sandbox must listen on `0.0.0.0` to be reached on `http://localhost:8080`. | |
| 117 | + | |
| 118 | +On the host nothing makes `team/` read-only: that protection is the sandbox's. | |
| 119 | + | |
| 120 | +In the window, the header names the agent at work: `mm [🧭 Coordinator] · qwen3.5-4b:Q4_K_M @ llmman`, then `mm [🛠️ Coder] · … · asked by mm [🧭 Coordinator]` during a hand-off. | |
| 121 | + | |
| 122 | +`yolo: true` in `agent.yaml` and in every `mmConfigs` entry: hand-offs, commands and file writes run without asking. To approve each hand-off and read the prompt the coordinator wrote: `AGENT_YOLO=false` before `mm`. | |
| 123 | + | |
| 124 | +Each specialist also works alone, e.g. `mm -config ../team/agent.tutor.yaml` from `workspace/` (alone, they ask before each command and file change, except the tutor). | |
| 125 | + | |
| 126 | +## Examples to try | |
| 127 | + | |
| 128 | +Put a project in `workspace/`, as a git repository with its last state committed, so that the reviewer's `git diff` shows only the team's change. The examples call it `my-app`. | |
| 129 | + | |
| 130 | +| Route | Request | What should happen | | |
| 131 | +|---|---|---| | |
| 132 | +| A | `Fix the bug in my-app: <what goes wrong, with an input and the expected output>.` | brief → fix + a test case → reviewer `VERDICT: PASS` | | |
| 133 | +| A | `Add a function to my-app that returns the most frequent words of a text.` | the reformulator asks you how many, case, punctuation, return type (in `-p`: it chooses and lists its ASSUMPTIONS) | | |
| 134 | +| A | `Rename <OldName> to <NewName> everywhere in my-app.` | brief → `lsp rename` + tests → review | | |
| 135 | +| B | `What is the difference between strings.Split and strings.Fields?` | a mini tutorial | | |
| 136 | +| B | `Explain table-driven tests in Go, using my-app/<file>_test.go as the example.` | the tutor reads the file and builds the lesson on its real code | | |
| 137 | +| B | `Explique-moi les goroutines avec un petit exemple, et sauve-le dans goroutines.md.` | a tutorial in French, saved with `save_answer` | | |
| 138 | +| C | `Review the code in my-app and tell me what is wrong.` | findings with file:line, tests, verdict | | |
| 139 | + | |
| 140 | +## Measured results | |
| 141 | + | |
| 142 | +llmman on the user's 32 GB machine, 2026-10-25, on the `textstats` practice package (`playground/` in the tables), before `workspace/` was emptied. | |
| 143 | + | |
| 144 | +### Each agent alone | |
| 145 | + | |
| 146 | +| Agent | Task | Result | Time | | |
| 147 | +|---|---|---|---| | |
| 148 | +| coder | the `WordCount` bug | fixed with `strings.Fields`, 4 test cases added, tests green | 351 s | | |
| 149 | +| reviewer | review of that fix | `git diff`, tests, its own `review_test.go`, `VERDICT: PASS` | 151 s | | |
| 150 | +| tutor | table-driven tests on `playground/textstats_test.go` | 3 runs out of 3 read the file and teach on its real `map[string]int` table | 12–19 s | | |
| 151 | +| reformulator | "a function that gives the most frequent words" | reads the code, calls `ask_user`; with nobody to answer (`-p`), lists its choices under ASSUMPTIONS | 62 s | | |
| 152 | + | |
| 153 | +What these runs changed in the files: | |
| 154 | + | |
| 155 | +- **coder**: once, after a failed `edit_file`, Mellum2 wrote a tool call that never closed and ran to `max_tokens` (8192): most of the 351 s. `max_tokens` is now 4096, which halves what such a call costs. | |
| 156 | +- **tutor**: the first version answered in 24 s but showed "a typical" test file it had invented. The prompt now makes `read_file` its first action when a file is named. | |
| 157 | +- **reformulator**: the first version did not list its choices, and put "top N" out of scope for "the most frequent words". The prompt now names what only the user decides, and the brief has an ASSUMPTIONS section. | |
| 158 | + | |
| 159 | +### Does the team need a decision model? | |
| 160 | + | |
| 161 | +The question of the ticket. A decider (see `demos/decision-*`) would pay off if the coordinator chose the wrong route. Measured: the coordinator (Qwen3.5 4B, reasoning off) on 12 requests — 5 code changes, 5 questions (2 in French), 2 reviews — **12 out of 12 to the right agent**. A decider would add a model and a call for nothing. Where one could help later, to be measured first: spotting a request too vague to code (a noul question before the reformulator), or reading the reviewer's verdict. | |
| 162 | + | |
| 163 | +### The whole team | |
| 164 | + | |
| 165 | +Through the coordinator, `-p`, `AGENT_YOLO=true`; llmman's loaded models sampled every 2 seconds. | |
| 166 | + | |
| 167 | +| Run | Route | Result | Time | | |
| 168 | +|---|---|---|---| | |
| 169 | +| bug fix, 1st | A | `VERDICT: PASS`, but the coder looped on `plan update` and was called twice; the report said "no changes" | 685 s | | |
| 170 | +| bug fix, 2nd (after the fixes below) | A | one call per agent, `VERDICT: PASS`, formatted, an exact report | 398 s | | |
| 171 | +| "explique-moi strings.Split et strings.Fields" | B | the tutor answers in French, correct | 49 s | | |
| 172 | +| "the most frequent words", 1st | A | **failed**: the reviewer tested a behaviour not in the brief and hit its 20 turns; the coordinator re-asked it, then called the coder 4 times; tests red at the end | 52 min | | |
| 173 | +| "the most frequent words", 2nd (after the fixes below) | A | **failed**: a good brief (top 3), then the coder hit the cut-off failure and the coordinator re-asked it; the reviewer kept `VERDICT: FAIL` (2 of its 7 cases); stopped by the 30-minute limit of the measurement | 30 min | | |
| 174 | + | |
| 175 | +**Memory: within the team's hand-offs, never two models loaded at the same time**: 4B → Gemma → 4B → Mellum2 → 4B → Gemma → 4B. The one overlap seen (the first 3 minutes of the last run) was a Mellum2 left loaded by a measurement run before the team started: the hooks unload the models of the hand-offs, not a model something else loaded. | |
| 176 | + | |
| 177 | +**In short: bug fixes, lessons and reviews work; new features do not yet.** The weak link is the coder: on a feature, Mellum2 writes tool calls that repeat themselves until `max_tokens`, and the 4B coordinator then re-asks it despite its prompt. Try `agent.coder.ornith.yaml` for features (see below). | |
| 178 | + | |
| 179 | +What the runs changed: | |
| 180 | + | |
| 181 | +- **coder**: no `plan` tool (Mellum2 called `plan update` in a loop); "add test cases, keep the existing ones"; the `gofmt` hook. | |
| 182 | +- **reviewer**: its tests cover the brief's ACCEPTANCE and REQUIREMENTS only, a failing case of its own is a finding (no rewriting until it passes), `gofmt -l` and removed test cases are findings, `maxTurns` 20 → 12 (then 16, see below). | |
| 183 | +- **coordinator**: `maxTurns` 8 → 6; "never re-ask an agent with a new prompt"; the report takes the files from the coder's and the reviewer's answers. | |
| 184 | + | |
| 185 | +### With the Go language server | |
| 186 | + | |
| 187 | +Measured after adding `lsp` (gopls v0.24.0): | |
| 188 | + | |
| 189 | +| Agent | Task | Result | Time | | |
| 190 | +|---|---|---|---| | |
| 191 | +| coder, 1st prompt | "Rename LineCount to CountLines everywhere in playground" | called `rename` without `new_name`, then copied the hint literally: the function became `new_name`, and the report said "renamed to CountLines" | 18 s | | |
| 192 | +| coder, with a filled-in example in the prompt | the same | 3 runs out of 3: `lsp rename` → `CountLines`, tests green | 5–10 s | | |
| 193 | +| reviewer | review of that rename | run 1: a tool call that repeated itself, stopped by mm; run 2: `references` + 2 `diagnostics`, a real finding (the test's error message still says `LineCount`: `rename` changes identifiers, not strings), `VERDICT: FAIL` | 200 s, 167 s | | |
| 194 | + | |
| 195 | +The reviewer's prompt also had to say to run `git diff` **inside** `playground/`: from the folder above it, git reads mm's repository, where `playground/` is ignored, and the diff is empty. Its `maxTurns` is now 16: 12 cut a normal review (13 calls) before its verdict. | |
| 196 | + | |
| 197 | +### Which coder? | |
| 198 | + | |
| 199 | +The ticket allows questioning its model choices, so the coder was measured alone on the reformulator's brief for "the most frequent words", against a hidden test made of the brief's acceptance cases (copied in after the run), `go vet` and `gofmt`: | |
| 200 | + | |
| 201 | +| Coder | Runs correct | Time per run | Formatted | | |
| 202 | +|---|---|---|---| | |
| 203 | +| Mellum2 12B-A2.5B Instruct (`agent.coder.yaml`) | 2 out of 3 | 129 s, 132 s, 639 s (the failure) | no (before the hook) | | |
| 204 | +| Ornith 1.5 9B, reasoning on (`agent.coder.ornith.yaml`) | 2 out of 2 | 783 s, 810 s | yes | | |
| 205 | + | |
| 206 | +Mellum2 stays the default, as the ticket chose: about 6 times faster, and right 2 times out of 3. Its failure mode is the one seen above: a tool call that repeats itself until `max_tokens`. Ornith is the steadier choice when time matters less: point `mmConfigs.coder.path` at `agent.coder.ornith.yaml` (6.7 GB, so it changes nothing to the memory peak). | |
| 207 | + | |
| 208 | +## Limits | |
| 209 | + | |
| 210 | +- **The reformulator's bash is read-only by its prompt only.** It has no file tools, but `bash` could write; with `yolo: true` nothing asks. For a guarantee, add a `preToolCall` hook that refuses commands that write (see `demos/hooks`). | |
| 211 | +- **The team can write anywhere in `workspace/`, not only in `playground/`.** Once, before the split, a member wrote a `main.go` next to `agent.yaml`, which broke mm's `go vet ./...`. In the sandbox it can no longer touch `team/`; check `git status` after a run. | |
| 212 | +- **`-p` cannot ask you anything**: the reformulator then chooses and says so. | |
| 213 | +- **Each reload costs time**: unloading at every hand-off trades seconds of loading for memory. On a machine with more memory, remove the `preAsk` hook to keep the 4B loaded. | |
| 214 | +- When `ask_agent` is refused (`yolo: false` and you say no), the 4B coordinator tends to try another agent rather than stop; after a failed hand-off, it re-asks the agent although its prompt says not to (`maxTurns: 6` bounds it). | |
| 215 | +- A model already loaded before the team starts (by another agent, or `llmman run`) stays loaded beside the team's: unload it first (`curl -s http://127.0.0.1:17434/api/generate -d '{"model":"…","keep_alive":0}'`). | |
| 216 | + | |
| 217 | +## Files | |
| 218 | + | |
| 219 | +``` | |
| 220 | +dev.team/ | |
| 221 | +├── sbxenv.yaml the sandbox: workspace/ read-write, team/ read-only, AGENT_CONFIG | |
| 222 | +├── start-zed.sh, stop-zed.sh create the sandbox and open workspace/ in Zed; remove it | |
| 223 | +├── team/ read-only in the sandbox | |
| 224 | +│ ├── agent.yaml coordinator (🧭) | |
| 225 | +│ ├── agent.reformulator.yaml 📝 | |
| 226 | +│ ├── agent.coder.yaml 🛠️ | |
| 227 | +│ ├── agent.coder.ornith.yaml 🛠️ the coder on Ornith 1.5 9B (steadier, slower) | |
| 228 | +│ ├── agent.reviewer.yaml 🔎 | |
| 229 | +│ ├── agent.tutor.yaml 📘 (the "prof" configuration of ticket 152, adapted) | |
| 230 | +│ └── hooks/ unload.js (one model in memory at a time), gofmt.js (the coder's formatter) | |
| 231 | +├── workspace/ read-write: empty in the repository (.gitkeep) — your project goes here; | |
| 232 | +│ .mm/ (sessions, traces) is created on the first run | |
| 233 | +├── dev-team-flow.* diagram: the three routes (.drawio .svg .png) | |
| 234 | +├── dev-team-memory.* diagram: the unloads (.drawio .svg .png) | |
| 235 | +└── dev-team-sandbox.* diagram: the sandbox mounts (.drawio .svg .png) | |
| 236 | +``` | |
| 237 | + | |
| 238 | +The diagrams are generated by `.claude/skills/drawio-fancy-diagram/generator/examples/dev_team.py dev.team`. | |
| new file mode 100644 | |||
| @@ -0,0 +1,238 @@ | |||
| 1 | +# dev.team — a team of agents that helps you code | ||
| 2 | + | ||
| 3 | +*[Version française](README.fr.md)* | ||
| 4 | + | ||
| 5 | +Five `mm` agents for a 32 GB MacBook Air: a coordinator you talk to, and four specialists it calls with the built-in `ask_agent` tool, one at a time. A hook unloads each model when the team hands over, so **only one model is in memory at a time**. | ||
| 6 | + | ||
| 7 | + | ||
| 8 | + | ||
| 9 | +| Agent | File | Header title | Model (llmman) | Tools | Job | | ||
| 10 | +|---|---|---|---|---|---| | ||
| 11 | +| coordinator | `agent.yaml` | 🧭 Coordinator | Qwen3.5 4B · 3.4 GB | `ask_agent` only | picks the route, hands over, reports to you | | ||
| 12 | +| reformulator | `agent.reformulator.yaml` | 📝 Reformulator | Gemma 4 12B · 7.3 GB | `bash` (reading), `ask_user`, `lsp` (reading) | turns a code request into a task brief; asks you what only you can decide | | ||
| 13 | +| coder | `agent.coder.yaml` | 🛠️ Coder | Mellum2 12B-A2.5B · 8.1 GB | `bash`, files, `lsp`; a `gofmt` hook | fixes, adds, changes code; runs the tests | | ||
| 14 | +| reviewer | `agent.reviewer.yaml` | 🔎 Reviewer | Gemma 4 12B · 7.3 GB | `bash`, files (tests only), `lsp` (reading) | reads the diff, runs the tests, writes its own edge-case tests, `VERDICT: PASS / FAIL` | | ||
| 15 | +| tutor | `agent.tutor.yaml` | 📘 Tutor | Mellum2 12B-A2.5B · 8.1 GB | `fetch_content`, `save_answer`, `bash`, files, `lsp` (reading) | answers questions with a mini tutorial; saves it on request | | ||
| 16 | + | ||
| 17 | +The full model ids are `hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M`, `hf.co/unsloth/gemma-4-12b-it-GGUF:Q4_K_M` and `hf.co/JetBrains/Mellum2-12B-A2.5B-Instruct-GGUF-Q4_K_M:Q4_K_M`. | ||
| 18 | + | ||
| 19 | +## The three routes | ||
| 20 | + | ||
| 21 | +The coordinator reads the request and picks one route (its prompt, in `agent.yaml`): | ||
| 22 | + | ||
| 23 | +- **A — code to write or change** (a bug, a feature, a rename, tests): reformulator → coder → reviewer. If the reviewer answers `VERDICT: FAIL`, the coder fixes **once** and the reviewer checks again. Then the coordinator reports: who did what, the files, the tests, the verdict. | ||
| 24 | +- **B — a question, a lesson, advice** ("how do I…", "what is…", "explique-moi…"): the tutor, and its answer is given as it is. | ||
| 25 | +- **C — only a review** of existing code: the reviewer. | ||
| 26 | + | ||
| 27 | +The team works on the code in **`workspace/`**, which is empty in the repository: put your project there (a git repository, so that the reviewer can read `git diff`), or ask the team to create one. The measurements below were made on `textstats`, a small Go practice package with a known bug (`WordCount` and several spaces), which this folder no longer ships. | ||
| 28 | + | ||
| 29 | +## One model in memory at a time | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | +The ticket's constraint: when the team switches agent, the current model leaves memory. That is not left to the models (a small model forgets to call `unload_model`: 4 times out of 5 with MiniCPM5 2B in `demos/unload-models`). Two hooks of the coordinator do it, with `hooks/unload.js` (copied from `demos/unload-models`): | ||
| 34 | + | ||
| 35 | +| Hook | When | Unloads | | ||
| 36 | +|---|---|---| | ||
| 37 | +| `preAsk` → `unload.js self` | the coordinator has decided to call an agent, before that agent starts | the coordinator's own 4B | | ||
| 38 | +| `postAsk` → `unload.js asked` | the agent has answered, before the coordinator reads the answer | the agent's 12B | | ||
| 39 | + | ||
| 40 | +llmman reloads a model by itself on the next request, so the coordinator's 4B comes back alone to read each answer. Both hooks have `onError: warn`: a failed unload costs memory, not the hand-off. The four specialists have `unloadModels: false`: no `unload_model` tool to think about. | ||
| 41 | + | ||
| 42 | +Two models are shared on purpose: the reformulator and the reviewer use Gemma 4 12B, the coder and the tutor Mellum2. **Peak memory: one 12B model**, about 8 GB plus its KV cache at a 32k window. | ||
| 43 | + | ||
| 44 | +### The coder's formatter hook | ||
| 45 | + | ||
| 46 | +`agent.coder.yaml` has its own `postToolCall` hook: after each `write_file` or `edit_file` on a `.go` file, `hooks/gofmt.js` runs `gofmt -w` on it. The prompt asked for `gofmt` and Mellum2 skipped it in every measured run. When gofmt cannot parse the file, its error goes back to the model as context. | ||
| 47 | + | ||
| 48 | +### The Go language server | ||
| 49 | + | ||
| 50 | +The four specialists have an `lsp` block with gopls for `.go` files; the coordinator has no tool but `ask_agent`, by design. Each prompt says what to use it for: | ||
| 51 | + | ||
| 52 | +| Agent | Uses `lsp` for | | ||
| 53 | +|---|---| | ||
| 54 | +| coder | `references` before changing a signature, `rename` to rename an identifier everywhere, `diagnostics` after a change | | ||
| 55 | +| reviewer | `references` on every function the diff touches, `diagnostics` on each changed file | | ||
| 56 | +| reformulator | `references` and `symbols`, to name the files a change touches | | ||
| 57 | +| tutor | `hover` and `definition` on a symbol of the code a question is about | | ||
| 58 | + | ||
| 59 | +Only the coder may `rename`; the others' prompts forbid it. gopls finds the `go.mod` of a project in a sub-folder of `workspace/` by itself, although the agents run from `workspace/` (measured with `textstats`). | ||
| 60 | + | ||
| 61 | +## Prerequisites | ||
| 62 | + | ||
| 63 | +- **llmman** serving on its default address, with the three models: | ||
| 64 | + | ||
| 65 | + ```bash | ||
| 66 | + llmman pull hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M | ||
| 67 | + llmman pull hf.co/unsloth/gemma-4-12b-it-GGUF:Q4_K_M | ||
| 68 | + llmman pull hf.co/JetBrains/Mellum2-12B-A2.5B-Instruct-GGUF-Q4_K_M:Q4_K_M | ||
| 69 | + llmman serve | ||
| 70 | + ``` | ||
| 71 | + | ||
| 72 | +- **Node.js** (the hooks), **Go** ≥ 1.24 and **git** (the reviewer reads `git diff`). | ||
| 73 | +- **gopls** on the `PATH`: `go install golang.org/x/tools/gopls@latest` (then `$(go env GOPATH)/bin` in the `PATH`). Without it, each specialist starts with a warning and no `lsp` tool. | ||
| 74 | +- **mm** built at the repository root: `go build -o mm .` | ||
| 75 | + | ||
| 76 | +## Layout: agents read-only, code read-write | ||
| 77 | + | ||
| 78 | + | ||
| 79 | + | ||
| 80 | +``` | ||
| 81 | +dev.team/ | ||
| 82 | +├── sbxenv.yaml, start-zed.sh, stop-zed.sh the sandbox — never mounted | ||
| 83 | +├── README.*, dev-team-*.{drawio,svg,png} this documentation | ||
| 84 | +├── team/ the agents and their hooks → mounted READ-ONLY | ||
| 85 | +└── workspace/ your code (empty in the repository), .mm/ → the read-write workspace | ||
| 86 | +``` | ||
| 87 | + | ||
| 88 | +The agents' files are what decides what the team may do: their prompts, their tools, `yolo`, the hooks. A team member with `bash` and `write_file` could rewrite them, and the next start would run its version. So they live in `team/`, which the sandbox mounts with `readOnly: true`, apart from the code the team changes. Docker also recommends keeping the environment file outside every mounted directory, so that an agent cannot change the commands your host runs: `sbxenv.yaml` and the scripts stay at the root of `dev.team/`, which is not mounted. | ||
| 89 | + | ||
| 90 | +mm finds the coordinator through `AGENT_CONFIG`, set in `sbxenv.yaml`; the other agents and the hooks are found next to it (`mmConfigs` paths and `$MM_CONFIG_DIR` are relative to `team/agent.yaml`). Sessions and traces go to `workspace/.mm/`, the session's working directory. | ||
| 91 | + | ||
| 92 | +## Run | ||
| 93 | + | ||
| 94 | +### In a sandbox, with Zed | ||
| 95 | + | ||
| 96 | +```bash | ||
| 97 | +cd dev.team | ||
| 98 | +sbx setup ssh # once | ||
| 99 | +./start-zed.sh # sbx env create --env-arg DEV_TEAM_DIR=$PWD, then Zed on workspace/ | ||
| 100 | +./stop-zed.sh # removes the sandbox; team/ and workspace/ stay on the host | ||
| 101 | +``` | ||
| 102 | + | ||
| 103 | +`start-zed.sh` passes the folder of `sbxenv.yaml` as the argument `DEV_TEAM_DIR`; `sbxenv.yaml` builds `AGENT_CONFIG=<DEV_TEAM_DIR>/team/agent.yaml` from it. In a terminal of the sandbox, from `workspace/`: `mm -tui` (it reads `AGENT_CONFIG`). | ||
| 104 | + | ||
| 105 | +To check, once the sandbox is up: `sbx version` (`sbx env` needs 0.39.0 or newer, which is also past CVE-2026-18171, a way to write into a read-only mount in 0.35.0–0.38.0); in the sandbox, `echo $AGENT_CONFIG`, `ls "$(dirname "$AGENT_CONFIG")"` and `touch "$(dirname "$AGENT_CONFIG")/x"`, which must fail. | ||
| 106 | + | ||
| 107 | +### On the host | ||
| 108 | + | ||
| 109 | +```bash | ||
| 110 | +cd dev.team/workspace | ||
| 111 | +AGENT_CONFIG=$PWD/../team/agent.yaml ../../mm -tui | ||
| 112 | +../../mm -config ../team/agent.yaml -tui # the same | ||
| 113 | +../../mm -config ../team/agent.yaml -p "…" # one request, then exit (the reformulator cannot ask you anything) | ||
| 114 | +``` | ||
| 115 | + | ||
| 116 | +The sandbox publishes ports 8080, 6060 and 5050 to the same ports on the host (`ports` in `sbxenv.yaml`, applied at creation): a server started in the sandbox must listen on `0.0.0.0` to be reached on `http://localhost:8080`. | ||
| 117 | + | ||
| 118 | +On the host nothing makes `team/` read-only: that protection is the sandbox's. | ||
| 119 | + | ||
| 120 | +In the window, the header names the agent at work: `mm [🧭 Coordinator] · qwen3.5-4b:Q4_K_M @ llmman`, then `mm [🛠️ Coder] · … · asked by mm [🧭 Coordinator]` during a hand-off. | ||
| 121 | + | ||
| 122 | +`yolo: true` in `agent.yaml` and in every `mmConfigs` entry: hand-offs, commands and file writes run without asking. To approve each hand-off and read the prompt the coordinator wrote: `AGENT_YOLO=false` before `mm`. | ||
| 123 | + | ||
| 124 | +Each specialist also works alone, e.g. `mm -config ../team/agent.tutor.yaml` from `workspace/` (alone, they ask before each command and file change, except the tutor). | ||
| 125 | + | ||
| 126 | +## Examples to try | ||
| 127 | + | ||
| 128 | +Put a project in `workspace/`, as a git repository with its last state committed, so that the reviewer's `git diff` shows only the team's change. The examples call it `my-app`. | ||
| 129 | + | ||
| 130 | +| Route | Request | What should happen | | ||
| 131 | +|---|---|---| | ||
| 132 | +| A | `Fix the bug in my-app: <what goes wrong, with an input and the expected output>.` | brief → fix + a test case → reviewer `VERDICT: PASS` | | ||
| 133 | +| A | `Add a function to my-app that returns the most frequent words of a text.` | the reformulator asks you how many, case, punctuation, return type (in `-p`: it chooses and lists its ASSUMPTIONS) | | ||
| 134 | +| A | `Rename <OldName> to <NewName> everywhere in my-app.` | brief → `lsp rename` + tests → review | | ||
| 135 | +| B | `What is the difference between strings.Split and strings.Fields?` | a mini tutorial | | ||
| 136 | +| B | `Explain table-driven tests in Go, using my-app/<file>_test.go as the example.` | the tutor reads the file and builds the lesson on its real code | | ||
| 137 | +| B | `Explique-moi les goroutines avec un petit exemple, et sauve-le dans goroutines.md.` | a tutorial in French, saved with `save_answer` | | ||
| 138 | +| C | `Review the code in my-app and tell me what is wrong.` | findings with file:line, tests, verdict | | ||
| 139 | + | ||
| 140 | +## Measured results | ||
| 141 | + | ||
| 142 | +llmman on the user's 32 GB machine, 2026-10-25, on the `textstats` practice package (`playground/` in the tables), before `workspace/` was emptied. | ||
| 143 | + | ||
| 144 | +### Each agent alone | ||
| 145 | + | ||
| 146 | +| Agent | Task | Result | Time | | ||
| 147 | +|---|---|---|---| | ||
| 148 | +| coder | the `WordCount` bug | fixed with `strings.Fields`, 4 test cases added, tests green | 351 s | | ||
| 149 | +| reviewer | review of that fix | `git diff`, tests, its own `review_test.go`, `VERDICT: PASS` | 151 s | | ||
| 150 | +| tutor | table-driven tests on `playground/textstats_test.go` | 3 runs out of 3 read the file and teach on its real `map[string]int` table | 12–19 s | | ||
| 151 | +| reformulator | "a function that gives the most frequent words" | reads the code, calls `ask_user`; with nobody to answer (`-p`), lists its choices under ASSUMPTIONS | 62 s | | ||
| 152 | + | ||
| 153 | +What these runs changed in the files: | ||
| 154 | + | ||
| 155 | +- **coder**: once, after a failed `edit_file`, Mellum2 wrote a tool call that never closed and ran to `max_tokens` (8192): most of the 351 s. `max_tokens` is now 4096, which halves what such a call costs. | ||
| 156 | +- **tutor**: the first version answered in 24 s but showed "a typical" test file it had invented. The prompt now makes `read_file` its first action when a file is named. | ||
| 157 | +- **reformulator**: the first version did not list its choices, and put "top N" out of scope for "the most frequent words". The prompt now names what only the user decides, and the brief has an ASSUMPTIONS section. | ||
| 158 | + | ||
| 159 | +### Does the team need a decision model? | ||
| 160 | + | ||
| 161 | +The question of the ticket. A decider (see `demos/decision-*`) would pay off if the coordinator chose the wrong route. Measured: the coordinator (Qwen3.5 4B, reasoning off) on 12 requests — 5 code changes, 5 questions (2 in French), 2 reviews — **12 out of 12 to the right agent**. A decider would add a model and a call for nothing. Where one could help later, to be measured first: spotting a request too vague to code (a noul question before the reformulator), or reading the reviewer's verdict. | ||
| 162 | + | ||
| 163 | +### The whole team | ||
| 164 | + | ||
| 165 | +Through the coordinator, `-p`, `AGENT_YOLO=true`; llmman's loaded models sampled every 2 seconds. | ||
| 166 | + | ||
| 167 | +| Run | Route | Result | Time | | ||
| 168 | +|---|---|---|---| | ||
| 169 | +| bug fix, 1st | A | `VERDICT: PASS`, but the coder looped on `plan update` and was called twice; the report said "no changes" | 685 s | | ||
| 170 | +| bug fix, 2nd (after the fixes below) | A | one call per agent, `VERDICT: PASS`, formatted, an exact report | 398 s | | ||
| 171 | +| "explique-moi strings.Split et strings.Fields" | B | the tutor answers in French, correct | 49 s | | ||
| 172 | +| "the most frequent words", 1st | A | **failed**: the reviewer tested a behaviour not in the brief and hit its 20 turns; the coordinator re-asked it, then called the coder 4 times; tests red at the end | 52 min | | ||
| 173 | +| "the most frequent words", 2nd (after the fixes below) | A | **failed**: a good brief (top 3), then the coder hit the cut-off failure and the coordinator re-asked it; the reviewer kept `VERDICT: FAIL` (2 of its 7 cases); stopped by the 30-minute limit of the measurement | 30 min | | ||
| 174 | + | ||
| 175 | +**Memory: within the team's hand-offs, never two models loaded at the same time**: 4B → Gemma → 4B → Mellum2 → 4B → Gemma → 4B. The one overlap seen (the first 3 minutes of the last run) was a Mellum2 left loaded by a measurement run before the team started: the hooks unload the models of the hand-offs, not a model something else loaded. | ||
| 176 | + | ||
| 177 | +**In short: bug fixes, lessons and reviews work; new features do not yet.** The weak link is the coder: on a feature, Mellum2 writes tool calls that repeat themselves until `max_tokens`, and the 4B coordinator then re-asks it despite its prompt. Try `agent.coder.ornith.yaml` for features (see below). | ||
| 178 | + | ||
| 179 | +What the runs changed: | ||
| 180 | + | ||
| 181 | +- **coder**: no `plan` tool (Mellum2 called `plan update` in a loop); "add test cases, keep the existing ones"; the `gofmt` hook. | ||
| 182 | +- **reviewer**: its tests cover the brief's ACCEPTANCE and REQUIREMENTS only, a failing case of its own is a finding (no rewriting until it passes), `gofmt -l` and removed test cases are findings, `maxTurns` 20 → 12 (then 16, see below). | ||
| 183 | +- **coordinator**: `maxTurns` 8 → 6; "never re-ask an agent with a new prompt"; the report takes the files from the coder's and the reviewer's answers. | ||
| 184 | + | ||
| 185 | +### With the Go language server | ||
| 186 | + | ||
| 187 | +Measured after adding `lsp` (gopls v0.24.0): | ||
| 188 | + | ||
| 189 | +| Agent | Task | Result | Time | | ||
| 190 | +|---|---|---|---| | ||
| 191 | +| coder, 1st prompt | "Rename LineCount to CountLines everywhere in playground" | called `rename` without `new_name`, then copied the hint literally: the function became `new_name`, and the report said "renamed to CountLines" | 18 s | | ||
| 192 | +| coder, with a filled-in example in the prompt | the same | 3 runs out of 3: `lsp rename` → `CountLines`, tests green | 5–10 s | | ||
| 193 | +| reviewer | review of that rename | run 1: a tool call that repeated itself, stopped by mm; run 2: `references` + 2 `diagnostics`, a real finding (the test's error message still says `LineCount`: `rename` changes identifiers, not strings), `VERDICT: FAIL` | 200 s, 167 s | | ||
| 194 | + | ||
| 195 | +The reviewer's prompt also had to say to run `git diff` **inside** `playground/`: from the folder above it, git reads mm's repository, where `playground/` is ignored, and the diff is empty. Its `maxTurns` is now 16: 12 cut a normal review (13 calls) before its verdict. | ||
| 196 | + | ||
| 197 | +### Which coder? | ||
| 198 | + | ||
| 199 | +The ticket allows questioning its model choices, so the coder was measured alone on the reformulator's brief for "the most frequent words", against a hidden test made of the brief's acceptance cases (copied in after the run), `go vet` and `gofmt`: | ||
| 200 | + | ||
| 201 | +| Coder | Runs correct | Time per run | Formatted | | ||
| 202 | +|---|---|---|---| | ||
| 203 | +| Mellum2 12B-A2.5B Instruct (`agent.coder.yaml`) | 2 out of 3 | 129 s, 132 s, 639 s (the failure) | no (before the hook) | | ||
| 204 | +| Ornith 1.5 9B, reasoning on (`agent.coder.ornith.yaml`) | 2 out of 2 | 783 s, 810 s | yes | | ||
| 205 | + | ||
| 206 | +Mellum2 stays the default, as the ticket chose: about 6 times faster, and right 2 times out of 3. Its failure mode is the one seen above: a tool call that repeats itself until `max_tokens`. Ornith is the steadier choice when time matters less: point `mmConfigs.coder.path` at `agent.coder.ornith.yaml` (6.7 GB, so it changes nothing to the memory peak). | ||
| 207 | + | ||
| 208 | +## Limits | ||
| 209 | + | ||
| 210 | +- **The reformulator's bash is read-only by its prompt only.** It has no file tools, but `bash` could write; with `yolo: true` nothing asks. For a guarantee, add a `preToolCall` hook that refuses commands that write (see `demos/hooks`). | ||
| 211 | +- **The team can write anywhere in `workspace/`, not only in `playground/`.** Once, before the split, a member wrote a `main.go` next to `agent.yaml`, which broke mm's `go vet ./...`. In the sandbox it can no longer touch `team/`; check `git status` after a run. | ||
| 212 | +- **`-p` cannot ask you anything**: the reformulator then chooses and says so. | ||
| 213 | +- **Each reload costs time**: unloading at every hand-off trades seconds of loading for memory. On a machine with more memory, remove the `preAsk` hook to keep the 4B loaded. | ||
| 214 | +- When `ask_agent` is refused (`yolo: false` and you say no), the 4B coordinator tends to try another agent rather than stop; after a failed hand-off, it re-asks the agent although its prompt says not to (`maxTurns: 6` bounds it). | ||
| 215 | +- A model already loaded before the team starts (by another agent, or `llmman run`) stays loaded beside the team's: unload it first (`curl -s http://127.0.0.1:17434/api/generate -d '{"model":"…","keep_alive":0}'`). | ||
| 216 | + | ||
| 217 | +## Files | ||
| 218 | + | ||
| 219 | +``` | ||
| 220 | +dev.team/ | ||
| 221 | +├── sbxenv.yaml the sandbox: workspace/ read-write, team/ read-only, AGENT_CONFIG | ||
| 222 | +├── start-zed.sh, stop-zed.sh create the sandbox and open workspace/ in Zed; remove it | ||
| 223 | +├── team/ read-only in the sandbox | ||
| 224 | +│ ├── agent.yaml coordinator (🧭) | ||
| 225 | +│ ├── agent.reformulator.yaml 📝 | ||
| 226 | +│ ├── agent.coder.yaml 🛠️ | ||
| 227 | +│ ├── agent.coder.ornith.yaml 🛠️ the coder on Ornith 1.5 9B (steadier, slower) | ||
| 228 | +│ ├── agent.reviewer.yaml 🔎 | ||
| 229 | +│ ├── agent.tutor.yaml 📘 (the "prof" configuration of ticket 152, adapted) | ||
| 230 | +│ └── hooks/ unload.js (one model in memory at a time), gofmt.js (the coder's formatter) | ||
| 231 | +├── workspace/ read-write: empty in the repository (.gitkeep) — your project goes here; | ||
| 232 | +│ .mm/ (sessions, traces) is created on the first run | ||
| 233 | +├── dev-team-flow.* diagram: the three routes (.drawio .svg .png) | ||
| 234 | +├── dev-team-memory.* diagram: the unloads (.drawio .svg .png) | ||
| 235 | +└── dev-team-sandbox.* diagram: the sandbox mounts (.drawio .svg .png) | ||
| 236 | +``` | ||
| 237 | + | ||
| 238 | +The diagrams are generated by `.claude/skills/drawio-fancy-diagram/generator/examples/dev_team.py dev.team`. | ||
added
dev.team/README.fr.md +238 -0 | new file mode 100644 | ||
| @@ -0,0 +1,238 @@ | ||
| 1 | +# dev.team — une équipe d'agents qui aide à coder | |
| 2 | + | |
| 3 | +*[English version](README.en.md)* | |
| 4 | + | |
| 5 | +Cinq agents `mm` pour un MacBook Air de 32 Go : un coordinateur à qui vous parlez, et quatre spécialistes qu'il appelle avec l'outil intégré `ask_agent`, un à la fois. Un hook décharge chaque modèle quand l'équipe passe la main : **un seul modèle en mémoire à la fois**. | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | +| Agent | Fichier | Titre dans l'en-tête | Modèle (llmman) | Outils | Rôle | | |
| 10 | +|---|---|---|---|---|---| | |
| 11 | +| coordinator | `agent.yaml` | 🧭 Coordinator | Qwen3.5 4B · 3,4 Go | `ask_agent` seulement | choisit la route, passe la main, vous fait le compte rendu | | |
| 12 | +| reformulator | `agent.reformulator.yaml` | 📝 Reformulator | Gemma 4 12B · 7,3 Go | `bash` (lecture), `ask_user`, `lsp` (lecture) | transforme une demande de code en cahier de tâche (brief) ; vous demande ce que vous seul pouvez décider | | |
| 13 | +| coder | `agent.coder.yaml` | 🛠️ Coder | Mellum2 12B-A2.5B · 8,1 Go | `bash`, fichiers, `lsp` ; un hook `gofmt` | corrige, ajoute, modifie le code ; lance les tests | | |
| 14 | +| reviewer | `agent.reviewer.yaml` | 🔎 Reviewer | Gemma 4 12B · 7,3 Go | `bash`, fichiers (tests seulement), `lsp` (lecture) | lit le diff, lance les tests, écrit ses propres tests de cas limites, `VERDICT: PASS / FAIL` | | |
| 15 | +| tutor | `agent.tutor.yaml` | 📘 Tutor | Mellum2 12B-A2.5B · 8,1 Go | `fetch_content`, `save_answer`, `bash`, fichiers, `lsp` (lecture) | répond par un mini tutoriel ; l'enregistre sur demande | | |
| 16 | + | |
| 17 | +Les identifiants complets des modèles sont `hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M`, `hf.co/unsloth/gemma-4-12b-it-GGUF:Q4_K_M` et `hf.co/JetBrains/Mellum2-12B-A2.5B-Instruct-GGUF-Q4_K_M:Q4_K_M`. Les noms, les fichiers et les prompts sont en anglais ; les agents vous répondent dans votre langue. | |
| 18 | + | |
| 19 | +## Les trois routes | |
| 20 | + | |
| 21 | +Le coordinateur lit la demande et choisit une route (son prompt, dans `agent.yaml`) : | |
| 22 | + | |
| 23 | +- **A — du code à écrire ou modifier** (un bug, une fonctionnalité, un renommage, des tests) : reformulator → coder → reviewer. Si le reviewer répond `VERDICT: FAIL`, le coder corrige **une fois** et le reviewer vérifie à nouveau. Puis le coordinateur fait le compte rendu : qui a fait quoi, les fichiers, les tests, le verdict. | |
| 24 | +- **B — une question, une leçon, un conseil** (« comment… », « c'est quoi… », « explique-moi… ») : le tutor, dont la réponse est transmise telle quelle. | |
| 25 | +- **C — seulement une revue** de code existant : le reviewer. | |
| 26 | + | |
| 27 | +L'équipe travaille sur le code de **`workspace/`**, vide dans le dépôt : mettez-y votre projet (un dépôt git, pour que le reviewer puisse lire `git diff`), ou demandez à l'équipe d'en créer un. Les mesures plus bas ont été faites sur `textstats`, un petit paquet Go d'entraînement avec un bug connu (`WordCount` et les espaces multiples), que ce dossier ne fournit plus. | |
| 28 | + | |
| 29 | +## Un seul modèle en mémoire à la fois | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | +La contrainte du ticket : quand l'équipe change d'agent, le modèle en cours quitte la mémoire. Ce n'est pas laissé aux modèles (un petit modèle oublie d'appeler `unload_model` : 4 fois sur 5 avec MiniCPM5 2B dans `demos/unload-models`). Deux hooks du coordinateur s'en chargent, avec `hooks/unload.js` (copié de `demos/unload-models`) : | |
| 34 | + | |
| 35 | +| Hook | Quand | Décharge | | |
| 36 | +|---|---|---| | |
| 37 | +| `preAsk` → `unload.js self` | le coordinateur a décidé d'appeler un agent, avant que cet agent démarre | le 4B du coordinateur | | |
| 38 | +| `postAsk` → `unload.js asked` | l'agent a répondu, avant que le coordinateur lise la réponse | le 12B de l'agent | | |
| 39 | + | |
| 40 | +llmman recharge un modèle de lui-même à la requête suivante : le 4B du coordinateur revient donc seul pour lire chaque réponse. Les deux hooks ont `onError: warn` : un déchargement raté coûte de la mémoire, pas le passage de main. Les quatre spécialistes ont `unloadModels: false` : pas d'outil `unload_model` auquel penser. | |
| 41 | + | |
| 42 | +Deux modèles sont partagés exprès : le reformulator et le reviewer utilisent Gemma 4 12B, le coder et le tutor Mellum2. **Pic mémoire : un seul modèle de 12B**, environ 8 Go plus son cache KV avec une fenêtre de 32k. | |
| 43 | + | |
| 44 | +### Le hook de formatage du coder | |
| 45 | + | |
| 46 | +`agent.coder.yaml` a son propre hook `postToolCall` : après chaque `write_file` ou `edit_file` sur un fichier `.go`, `hooks/gofmt.js` lance `gofmt -w` dessus. Le prompt demandait `gofmt`, et Mellum2 l'a sauté à chaque exécution mesurée. Quand gofmt ne peut pas lire le fichier, son erreur revient au modèle comme contexte. | |
| 47 | + | |
| 48 | +### Le serveur de langage Go | |
| 49 | + | |
| 50 | +Les quatre spécialistes ont un bloc `lsp` avec gopls pour les fichiers `.go` ; le coordinateur n'a pas d'autre outil qu'`ask_agent`, par choix. Chaque prompt dit à quoi il sert : | |
| 51 | + | |
| 52 | +| Agent | Utilise `lsp` pour | | |
| 53 | +|---|---| | |
| 54 | +| coder | `references` avant de changer une signature, `rename` pour renommer un identifiant partout, `diagnostics` après une modification | | |
| 55 | +| reviewer | `references` sur chaque fonction touchée par le diff, `diagnostics` sur chaque fichier modifié | | |
| 56 | +| reformulator | `references` et `symbols`, pour nommer les fichiers qu'une modification touche | | |
| 57 | +| tutor | `hover` et `definition` sur un symbole du code dont parle la question | | |
| 58 | + | |
| 59 | +Seul le coder peut faire `rename` ; les prompts des autres l'interdisent. gopls trouve tout seul le `go.mod` d'un projet placé dans un sous-dossier de `workspace/`, bien que les agents tournent depuis `workspace/` (mesuré avec `textstats`). | |
| 60 | + | |
| 61 | +## Prérequis | |
| 62 | + | |
| 63 | +- **llmman** sur son adresse par défaut, avec les trois modèles : | |
| 64 | + | |
| 65 | + ```bash | |
| 66 | + llmman pull hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M | |
| 67 | + llmman pull hf.co/unsloth/gemma-4-12b-it-GGUF:Q4_K_M | |
| 68 | + llmman pull hf.co/JetBrains/Mellum2-12B-A2.5B-Instruct-GGUF-Q4_K_M:Q4_K_M | |
| 69 | + llmman serve | |
| 70 | + ``` | |
| 71 | + | |
| 72 | +- **Node.js** (les hooks), **Go** ≥ 1.24 et **git** (le reviewer lit `git diff`). | |
| 73 | +- **gopls** dans le `PATH` : `go install golang.org/x/tools/gopls@latest` (puis `$(go env GOPATH)/bin` dans le `PATH`). Sans lui, chaque spécialiste démarre avec un avertissement et sans outil `lsp`. | |
| 74 | +- **mm** compilé à la racine du dépôt : `go build -o mm .` | |
| 75 | + | |
| 76 | +## Organisation : agents en lecture seule, code en lecture-écriture | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | +``` | |
| 81 | +dev.team/ | |
| 82 | +├── sbxenv.yaml, start-zed.sh, stop-zed.sh la sandbox — jamais montés | |
| 83 | +├── README.*, dev-team-*.{drawio,svg,png} cette documentation | |
| 84 | +├── team/ les agents et leurs hooks → monté en LECTURE SEULE | |
| 85 | +└── workspace/ votre code (vide dans le dépôt), .mm/ → l'espace de travail en lecture-écriture | |
| 86 | +``` | |
| 87 | + | |
| 88 | +Les fichiers des agents décident de ce que l'équipe a le droit de faire : leurs prompts, leurs outils, `yolo`, les hooks. Un membre de l'équipe qui a `bash` et `write_file` pourrait les réécrire, et le prochain démarrage exécuterait sa version. Ils sont donc dans `team/`, que la sandbox monte avec `readOnly: true`, à part du code que l'équipe modifie. Docker recommande aussi de garder le fichier d'environnement hors de tout dossier monté, pour qu'un agent ne puisse pas changer les commandes que lance votre machine : `sbxenv.yaml` et les scripts restent à la racine de `dev.team/`, qui n'est pas montée. | |
| 89 | + | |
| 90 | +mm trouve le coordinateur grâce à `AGENT_CONFIG`, défini dans `sbxenv.yaml` ; les autres agents et les hooks sont trouvés à côté (les chemins de `mmConfigs` et `$MM_CONFIG_DIR` sont relatifs à `team/agent.yaml`). Les sessions et les traces vont dans `workspace/.mm/`, le dossier de travail de la session. | |
| 91 | + | |
| 92 | +## Lancer | |
| 93 | + | |
| 94 | +### Dans une sandbox, avec Zed | |
| 95 | + | |
| 96 | +```bash | |
| 97 | +cd dev.team | |
| 98 | +sbx setup ssh # une fois | |
| 99 | +./start-zed.sh # sbx env create --env-arg DEV_TEAM_DIR=$PWD, puis Zed sur workspace/ | |
| 100 | +./stop-zed.sh # supprime la sandbox ; team/ et workspace/ restent sur la machine | |
| 101 | +``` | |
| 102 | + | |
| 103 | +`start-zed.sh` passe le dossier de `sbxenv.yaml` comme argument `DEV_TEAM_DIR` ; `sbxenv.yaml` en construit `AGENT_CONFIG=<DEV_TEAM_DIR>/team/agent.yaml`. Dans un terminal de la sandbox, depuis `workspace/` : `mm -tui` (il lit `AGENT_CONFIG`). | |
| 104 | + | |
| 105 | +Pour vérifier, une fois la sandbox lancée : `sbx version` (`sbx env` demande la 0.39.0 ou plus, ce qui place aussi après la CVE-2026-18171, qui permettait d'écrire dans un montage en lecture seule en 0.35.0–0.38.0) ; dans la sandbox, `echo $AGENT_CONFIG`, `ls "$(dirname "$AGENT_CONFIG")"` et `touch "$(dirname "$AGENT_CONFIG")/x"`, qui doit échouer. | |
| 106 | + | |
| 107 | +### Sur la machine | |
| 108 | + | |
| 109 | +```bash | |
| 110 | +cd dev.team/workspace | |
| 111 | +AGENT_CONFIG=$PWD/../team/agent.yaml ../../mm -tui | |
| 112 | +../../mm -config ../team/agent.yaml -tui # la même chose | |
| 113 | +../../mm -config ../team/agent.yaml -p "…" # une demande, puis sortie (le reformulator ne peut rien vous demander) | |
| 114 | +``` | |
| 115 | + | |
| 116 | +La sandbox publie les ports 8080, 6060 et 5050 sur les mêmes ports de la machine (`ports` dans `sbxenv.yaml`, appliqué à la création) : un serveur lancé dans la sandbox doit écouter sur `0.0.0.0` pour être joignable sur `http://localhost:8080`. | |
| 117 | + | |
| 118 | +Sur la machine, rien ne met `team/` en lecture seule : cette protection est celle de la sandbox. | |
| 119 | + | |
| 120 | +Dans la fenêtre, l'en-tête nomme l'agent au travail : `mm [🧭 Coordinator] · qwen3.5-4b:Q4_K_M @ llmman`, puis `mm [🛠️ Coder] · … · asked by mm [🧭 Coordinator]` pendant un passage de main. | |
| 121 | + | |
| 122 | +`yolo: true` dans `agent.yaml` et dans chaque entrée de `mmConfigs` : les passages de main, les commandes et les écritures de fichiers se font sans demander. Pour approuver chaque passage de main et lire le prompt écrit par le coordinateur : `AGENT_YOLO=false` devant `mm`. | |
| 123 | + | |
| 124 | +Chaque spécialiste fonctionne aussi seul, par exemple `mm -config ../team/agent.tutor.yaml` depuis `workspace/` (seuls, ils demandent avant chaque commande et chaque modification de fichier, sauf le tutor). | |
| 125 | + | |
| 126 | +## Exemples à essayer | |
| 127 | + | |
| 128 | +Mettez un projet dans `workspace/`, en dépôt git avec son dernier état commité, pour que le `git diff` du reviewer ne montre que la modification de l'équipe. Les exemples l'appellent `my-app`. | |
| 129 | + | |
| 130 | +| Route | Demande | Ce qui doit se passer | | |
| 131 | +|---|---|---| | |
| 132 | +| A | `Corrige le bug de my-app : <ce qui ne va pas, avec une entrée et la sortie attendue>.` | brief → correction + un cas de test → reviewer `VERDICT: PASS` | | |
| 133 | +| A | `Ajoute à my-app une fonction qui renvoie les mots les plus fréquents d'un texte.` | le reformulator vous demande combien, la casse, la ponctuation, le type de retour (avec `-p` : il choisit et liste ses ASSUMPTIONS) | | |
| 134 | +| A | `Renomme <AncienNom> en <NouveauNom> partout dans my-app.` | brief → `lsp rename` + tests → revue | | |
| 135 | +| B | `Quelle est la différence entre strings.Split et strings.Fields ?` | un mini tutoriel en français | | |
| 136 | +| B | `Explique les tests en table en Go, avec my-app/<fichier>_test.go comme exemple.` | le tutor lit le fichier et bâtit la leçon sur son vrai code | | |
| 137 | +| B | `Explique-moi les goroutines avec un petit exemple, et sauve-le dans goroutines.md.` | un tutoriel en français, enregistré avec `save_answer` | | |
| 138 | +| C | `Fais la revue du code de my-app et dis-moi ce qui ne va pas.` | des constats avec fichier:ligne, les tests, le verdict | | |
| 139 | + | |
| 140 | +## Résultats mesurés | |
| 141 | + | |
| 142 | +llmman sur la machine de 32 Go de l'utilisateur, le 2026-10-25, sur le paquet d'entraînement `textstats` (`playground/` dans les tableaux), avant que `workspace/` soit vidé. | |
| 143 | + | |
| 144 | +### Chaque agent seul | |
| 145 | + | |
| 146 | +| Agent | Tâche | Résultat | Temps | | |
| 147 | +|---|---|---|---| | |
| 148 | +| coder | le bug de `WordCount` | corrigé avec `strings.Fields`, 4 cas de test ajoutés, tests au vert | 351 s | | |
| 149 | +| reviewer | revue de cette correction | `git diff`, tests, son propre `review_test.go`, `VERDICT: PASS` | 151 s | | |
| 150 | +| tutor | les tests en table sur `playground/textstats_test.go` | 3 exécutions sur 3 lisent le fichier et enseignent sur sa vraie table `map[string]int` | 12–19 s | | |
| 151 | +| reformulator | « une fonction qui donne les mots les plus fréquents » | lit le code, appelle `ask_user` ; sans personne pour répondre (`-p`), liste ses choix sous ASSUMPTIONS | 62 s | | |
| 152 | + | |
| 153 | +Ce que ces exécutions ont changé dans les fichiers : | |
| 154 | + | |
| 155 | +- **coder** : une fois, après un `edit_file` raté, Mellum2 a écrit un appel d'outil jamais refermé, qui a couru jusqu'à `max_tokens` (8192) : l'essentiel des 351 s. `max_tokens` vaut maintenant 4096, ce qui divise par deux le coût d'un tel appel. | |
| 156 | +- **tutor** : la première version répondait en 24 s mais montrait un fichier de test « typique » qu'elle avait inventé. Le prompt fait maintenant de `read_file` sa première action quand un fichier est nommé. | |
| 157 | +- **reformulator** : la première version ne listait pas ses choix, et mettait « top N » hors périmètre pour « les mots les plus fréquents ». Le prompt nomme maintenant ce que seul l'utilisateur décide, et le brief a une section ASSUMPTIONS. | |
| 158 | + | |
| 159 | +### L'équipe a-t-elle besoin d'un modèle de décision ? | |
| 160 | + | |
| 161 | +La question du ticket. Un décideur (voir `demos/decision-*`) serait utile si le coordinateur se trompait de route. Mesuré : le coordinateur (Qwen3.5 4B, sans raisonnement) sur 12 demandes — 5 modifications de code, 5 questions (dont 2 en français), 2 revues — **12 sur 12 vers le bon agent**. Un décideur ajouterait un modèle et un appel pour rien. Là où il pourrait servir plus tard, à mesurer d'abord : repérer une demande trop vague pour être codée (une question noul avant le reformulator), ou lire le verdict du reviewer. | |
| 162 | + | |
| 163 | +### L'équipe entière | |
| 164 | + | |
| 165 | +Par le coordinateur, `-p`, `AGENT_YOLO=true` ; les modèles chargés dans llmman relevés toutes les 2 secondes. | |
| 166 | + | |
| 167 | +| Exécution | Route | Résultat | Temps | | |
| 168 | +|---|---|---|---| | |
| 169 | +| correction du bug, 1re | A | `VERDICT: PASS`, mais le coder a bouclé sur `plan update` et a été appelé deux fois ; le compte rendu disait « aucune modification » | 685 s | | |
| 170 | +| correction du bug, 2e (après les corrections ci-dessous) | A | un appel par agent, `VERDICT: PASS`, code formaté, compte rendu exact | 398 s | | |
| 171 | +| « explique-moi strings.Split et strings.Fields » | B | le tutor répond en français, juste | 49 s | | |
| 172 | +| « les mots les plus fréquents », 1re | A | **échec** : le reviewer a testé un comportement absent du brief et atteint ses 20 tours ; le coordinateur l'a redemandé, puis a appelé le coder 4 fois ; tests rouges à la fin | 52 min | | |
| 173 | +| « les mots les plus fréquents », 2e (après les corrections ci-dessous) | A | **échec** : un bon brief (top 3), puis le coder a eu la même coupure et le coordinateur l'a redemandé ; le reviewer est resté à `VERDICT: FAIL` (2 de ses 7 cas) ; arrêté par la limite de 30 minutes de la mesure | 30 min | | |
| 174 | + | |
| 175 | +**Mémoire : pendant les passages de main de l'équipe, jamais deux modèles chargés en même temps** : 4B → Gemma → 4B → Mellum2 → 4B → Gemma → 4B. Le seul chevauchement vu (les 3 premières minutes de la dernière exécution) était un Mellum2 laissé chargé par une mesure lancée avant l'équipe : les hooks déchargent les modèles des passages de main, pas un modèle chargé par autre chose. | |
| 176 | + | |
| 177 | +**En bref : les corrections de bugs, les leçons et les revues fonctionnent ; les nouvelles fonctionnalités, pas encore.** Le maillon faible est le coder : sur une fonctionnalité, Mellum2 écrit des appels d'outil qui se répètent jusqu'à `max_tokens`, et le coordinateur 4B le redemande alors malgré son prompt. Essayez `agent.coder.ornith.yaml` pour les fonctionnalités (voir plus bas). | |
| 178 | + | |
| 179 | +Ce que ces exécutions ont changé : | |
| 180 | + | |
| 181 | +- **coder** : plus d'outil `plan` (Mellum2 appelait `plan update` en boucle) ; « ajoute des cas de test, garde les existants » ; le hook `gofmt`. | |
| 182 | +- **reviewer** : ses tests couvrent seulement l'ACCEPTANCE et les REQUIREMENTS du brief ; un de ses cas qui échoue est un constat (pas de réécriture jusqu'à ce qu'il passe) ; `gofmt -l` et des cas de test supprimés sont des constats ; `maxTurns` 20 → 12 (puis 16, voir plus bas). | |
| 183 | +- **coordinateur** : `maxTurns` 8 → 6 ; « ne jamais redemander à un agent avec un nouveau prompt » ; le compte rendu prend les fichiers dans les réponses du coder et du reviewer. | |
| 184 | + | |
| 185 | +### Avec le serveur de langage Go | |
| 186 | + | |
| 187 | +Mesuré après l'ajout de `lsp` (gopls v0.24.0) : | |
| 188 | + | |
| 189 | +| Agent | Tâche | Résultat | Temps | | |
| 190 | +|---|---|---|---| | |
| 191 | +| coder, 1er prompt | « Rename LineCount to CountLines everywhere in playground » | a appelé `rename` sans `new_name`, puis a recopié l'indication mot pour mot : la fonction est devenue `new_name`, et le compte rendu disait « renommée en CountLines » | 18 s | | |
| 192 | +| coder, avec un exemple rempli dans le prompt | la même | 3 exécutions sur 3 : `lsp rename` → `CountLines`, tests au vert | 5–10 s | | |
| 193 | +| reviewer | revue de ce renommage | exécution 1 : un appel d'outil qui se répétait, arrêté par mm ; exécution 2 : `references` + 2 `diagnostics`, un vrai constat (le message d'erreur du test dit encore `LineCount` : `rename` change les identifiants, pas les chaînes), `VERDICT: FAIL` | 200 s, 167 s | | |
| 194 | + | |
| 195 | +Le prompt du reviewer a aussi dû préciser de lancer `git diff` **dans** `playground/` : depuis le dossier au-dessus, git lit le dépôt de mm, où `playground/` est ignoré, et le diff est vide. Son `maxTurns` vaut maintenant 16 : 12 coupait une revue normale (13 appels) avant son verdict. | |
| 196 | + | |
| 197 | +### Quel coder ? | |
| 198 | + | |
| 199 | +Le ticket permet de remettre en question ses choix de modèles : le coder a donc été mesuré seul sur le brief du reformulator pour « les mots les plus fréquents », contre un test caché fait des cas d'acceptation du brief (copié après l'exécution), `go vet` et `gofmt` : | |
| 200 | + | |
| 201 | +| Coder | Exécutions justes | Temps par exécution | Formaté | | |
| 202 | +|---|---|---|---| | |
| 203 | +| Mellum2 12B-A2.5B Instruct (`agent.coder.yaml`) | 2 sur 3 | 129 s, 132 s, 639 s (l'échec) | non (avant le hook) | | |
| 204 | +| Ornith 1.5 9B, raisonnement activé (`agent.coder.ornith.yaml`) | 2 sur 2 | 783 s, 810 s | oui | | |
| 205 | + | |
| 206 | +Mellum2 reste le coder par défaut, comme le ticket l'a choisi : environ 6 fois plus rapide, et juste 2 fois sur 3. Son mode d'échec est celui vu plus haut : un appel d'outil qui se répète jusqu'à `max_tokens`. Ornith est le choix le plus régulier quand le temps compte moins : faites pointer `mmConfigs.coder.path` sur `agent.coder.ornith.yaml` (6,7 Go, donc rien ne change au pic mémoire). | |
| 207 | + | |
| 208 | +## Limites | |
| 209 | + | |
| 210 | +- **Le bash du reformulator n'est en lecture seule que par son prompt.** Il n'a pas d'outils de fichiers, mais `bash` pourrait écrire ; avec `yolo: true`, rien ne demande. Pour une garantie, ajoutez un hook `preToolCall` qui refuse les commandes qui écrivent (voir `demos/hooks`). | |
| 211 | +- **L'équipe peut écrire partout dans `workspace/`, pas seulement dans `playground/`.** Une fois, avant la séparation, un membre a écrit un `main.go` à côté de `agent.yaml`, ce qui cassait le `go vet ./...` de mm. Dans la sandbox, il ne peut plus toucher `team/` ; regardez `git status` après une exécution. | |
| 212 | +- **`-p` ne peut rien vous demander** : le reformulator choisit alors, et le dit. | |
| 213 | +- **Chaque rechargement coûte du temps** : décharger à chaque passage de main échange des secondes de chargement contre de la mémoire. Sur une machine avec plus de mémoire, retirez le hook `preAsk` pour garder le 4B chargé. | |
| 214 | +- Quand `ask_agent` est refusé (`yolo: false` et vous dites non), le coordinateur 4B a tendance à essayer un autre agent plutôt qu'à s'arrêter ; après un passage de main raté, il redemande à l'agent bien que son prompt le lui interdise (`maxTurns: 6` le borne). | |
| 215 | +- Un modèle déjà chargé avant que l'équipe démarre (par un autre agent, ou `llmman run`) reste chargé à côté de ceux de l'équipe : déchargez-le d'abord (`curl -s http://127.0.0.1:17434/api/generate -d '{"model":"…","keep_alive":0}'`). | |
| 216 | + | |
| 217 | +## Fichiers | |
| 218 | + | |
| 219 | +``` | |
| 220 | +dev.team/ | |
| 221 | +├── sbxenv.yaml la sandbox : workspace/ en lecture-écriture, team/ en lecture seule, AGENT_CONFIG | |
| 222 | +├── start-zed.sh, stop-zed.sh créer la sandbox et ouvrir workspace/ dans Zed ; la supprimer | |
| 223 | +├── team/ en lecture seule dans la sandbox | |
| 224 | +│ ├── agent.yaml coordinateur (🧭) | |
| 225 | +│ ├── agent.reformulator.yaml 📝 | |
| 226 | +│ ├── agent.coder.yaml 🛠️ | |
| 227 | +│ ├── agent.coder.ornith.yaml 🛠️ le coder sur Ornith 1.5 9B (plus régulier, plus lent) | |
| 228 | +│ ├── agent.reviewer.yaml 🔎 | |
| 229 | +│ ├── agent.tutor.yaml 📘 (la configuration « prof » du ticket 152, adaptée) | |
| 230 | +│ └── hooks/ unload.js (un seul modèle en mémoire), gofmt.js (le formatage du coder) | |
| 231 | +├── workspace/ en lecture-écriture : vide dans le dépôt (.gitkeep) — votre projet va ici ; | |
| 232 | +│ .mm/ (sessions, traces) est créé à la première exécution | |
| 233 | +├── dev-team-flow.* diagramme : les trois routes (.drawio .svg .png) | |
| 234 | +├── dev-team-memory.* diagramme : les déchargements (.drawio .svg .png) | |
| 235 | +└── dev-team-sandbox.* diagramme : les montages de la sandbox (.drawio .svg .png) | |
| 236 | +``` | |
| 237 | + | |
| 238 | +Les diagrammes sont générés par `.claude/skills/drawio-fancy-diagram/generator/examples/dev_team.py dev.team`. | |
| new file mode 100644 | |||
| @@ -0,0 +1,238 @@ | |||
| 1 | +# dev.team — une équipe d'agents qui aide à coder | ||
| 2 | + | ||
| 3 | +*[English version](README.en.md)* | ||
| 4 | + | ||
| 5 | +Cinq agents `mm` pour un MacBook Air de 32 Go : un coordinateur à qui vous parlez, et quatre spécialistes qu'il appelle avec l'outil intégré `ask_agent`, un à la fois. Un hook décharge chaque modèle quand l'équipe passe la main : **un seul modèle en mémoire à la fois**. | ||
| 6 | + | ||
| 7 | + | ||
| 8 | + | ||
| 9 | +| Agent | Fichier | Titre dans l'en-tête | Modèle (llmman) | Outils | Rôle | | ||
| 10 | +|---|---|---|---|---|---| | ||
| 11 | +| coordinator | `agent.yaml` | 🧭 Coordinator | Qwen3.5 4B · 3,4 Go | `ask_agent` seulement | choisit la route, passe la main, vous fait le compte rendu | | ||
| 12 | +| reformulator | `agent.reformulator.yaml` | 📝 Reformulator | Gemma 4 12B · 7,3 Go | `bash` (lecture), `ask_user`, `lsp` (lecture) | transforme une demande de code en cahier de tâche (brief) ; vous demande ce que vous seul pouvez décider | | ||
| 13 | +| coder | `agent.coder.yaml` | 🛠️ Coder | Mellum2 12B-A2.5B · 8,1 Go | `bash`, fichiers, `lsp` ; un hook `gofmt` | corrige, ajoute, modifie le code ; lance les tests | | ||
| 14 | +| reviewer | `agent.reviewer.yaml` | 🔎 Reviewer | Gemma 4 12B · 7,3 Go | `bash`, fichiers (tests seulement), `lsp` (lecture) | lit le diff, lance les tests, écrit ses propres tests de cas limites, `VERDICT: PASS / FAIL` | | ||
| 15 | +| tutor | `agent.tutor.yaml` | 📘 Tutor | Mellum2 12B-A2.5B · 8,1 Go | `fetch_content`, `save_answer`, `bash`, fichiers, `lsp` (lecture) | répond par un mini tutoriel ; l'enregistre sur demande | | ||
| 16 | + | ||
| 17 | +Les identifiants complets des modèles sont `hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M`, `hf.co/unsloth/gemma-4-12b-it-GGUF:Q4_K_M` et `hf.co/JetBrains/Mellum2-12B-A2.5B-Instruct-GGUF-Q4_K_M:Q4_K_M`. Les noms, les fichiers et les prompts sont en anglais ; les agents vous répondent dans votre langue. | ||
| 18 | + | ||
| 19 | +## Les trois routes | ||
| 20 | + | ||
| 21 | +Le coordinateur lit la demande et choisit une route (son prompt, dans `agent.yaml`) : | ||
| 22 | + | ||
| 23 | +- **A — du code à écrire ou modifier** (un bug, une fonctionnalité, un renommage, des tests) : reformulator → coder → reviewer. Si le reviewer répond `VERDICT: FAIL`, le coder corrige **une fois** et le reviewer vérifie à nouveau. Puis le coordinateur fait le compte rendu : qui a fait quoi, les fichiers, les tests, le verdict. | ||
| 24 | +- **B — une question, une leçon, un conseil** (« comment… », « c'est quoi… », « explique-moi… ») : le tutor, dont la réponse est transmise telle quelle. | ||
| 25 | +- **C — seulement une revue** de code existant : le reviewer. | ||
| 26 | + | ||
| 27 | +L'équipe travaille sur le code de **`workspace/`**, vide dans le dépôt : mettez-y votre projet (un dépôt git, pour que le reviewer puisse lire `git diff`), ou demandez à l'équipe d'en créer un. Les mesures plus bas ont été faites sur `textstats`, un petit paquet Go d'entraînement avec un bug connu (`WordCount` et les espaces multiples), que ce dossier ne fournit plus. | ||
| 28 | + | ||
| 29 | +## Un seul modèle en mémoire à la fois | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | +La contrainte du ticket : quand l'équipe change d'agent, le modèle en cours quitte la mémoire. Ce n'est pas laissé aux modèles (un petit modèle oublie d'appeler `unload_model` : 4 fois sur 5 avec MiniCPM5 2B dans `demos/unload-models`). Deux hooks du coordinateur s'en chargent, avec `hooks/unload.js` (copié de `demos/unload-models`) : | ||
| 34 | + | ||
| 35 | +| Hook | Quand | Décharge | | ||
| 36 | +|---|---|---| | ||
| 37 | +| `preAsk` → `unload.js self` | le coordinateur a décidé d'appeler un agent, avant que cet agent démarre | le 4B du coordinateur | | ||
| 38 | +| `postAsk` → `unload.js asked` | l'agent a répondu, avant que le coordinateur lise la réponse | le 12B de l'agent | | ||
| 39 | + | ||
| 40 | +llmman recharge un modèle de lui-même à la requête suivante : le 4B du coordinateur revient donc seul pour lire chaque réponse. Les deux hooks ont `onError: warn` : un déchargement raté coûte de la mémoire, pas le passage de main. Les quatre spécialistes ont `unloadModels: false` : pas d'outil `unload_model` auquel penser. | ||
| 41 | + | ||
| 42 | +Deux modèles sont partagés exprès : le reformulator et le reviewer utilisent Gemma 4 12B, le coder et le tutor Mellum2. **Pic mémoire : un seul modèle de 12B**, environ 8 Go plus son cache KV avec une fenêtre de 32k. | ||
| 43 | + | ||
| 44 | +### Le hook de formatage du coder | ||
| 45 | + | ||
| 46 | +`agent.coder.yaml` a son propre hook `postToolCall` : après chaque `write_file` ou `edit_file` sur un fichier `.go`, `hooks/gofmt.js` lance `gofmt -w` dessus. Le prompt demandait `gofmt`, et Mellum2 l'a sauté à chaque exécution mesurée. Quand gofmt ne peut pas lire le fichier, son erreur revient au modèle comme contexte. | ||
| 47 | + | ||
| 48 | +### Le serveur de langage Go | ||
| 49 | + | ||
| 50 | +Les quatre spécialistes ont un bloc `lsp` avec gopls pour les fichiers `.go` ; le coordinateur n'a pas d'autre outil qu'`ask_agent`, par choix. Chaque prompt dit à quoi il sert : | ||
| 51 | + | ||
| 52 | +| Agent | Utilise `lsp` pour | | ||
| 53 | +|---|---| | ||
| 54 | +| coder | `references` avant de changer une signature, `rename` pour renommer un identifiant partout, `diagnostics` après une modification | | ||
| 55 | +| reviewer | `references` sur chaque fonction touchée par le diff, `diagnostics` sur chaque fichier modifié | | ||
| 56 | +| reformulator | `references` et `symbols`, pour nommer les fichiers qu'une modification touche | | ||
| 57 | +| tutor | `hover` et `definition` sur un symbole du code dont parle la question | | ||
| 58 | + | ||
| 59 | +Seul le coder peut faire `rename` ; les prompts des autres l'interdisent. gopls trouve tout seul le `go.mod` d'un projet placé dans un sous-dossier de `workspace/`, bien que les agents tournent depuis `workspace/` (mesuré avec `textstats`). | ||
| 60 | + | ||
| 61 | +## Prérequis | ||
| 62 | + | ||
| 63 | +- **llmman** sur son adresse par défaut, avec les trois modèles : | ||
| 64 | + | ||
| 65 | + ```bash | ||
| 66 | + llmman pull hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M | ||
| 67 | + llmman pull hf.co/unsloth/gemma-4-12b-it-GGUF:Q4_K_M | ||
| 68 | + llmman pull hf.co/JetBrains/Mellum2-12B-A2.5B-Instruct-GGUF-Q4_K_M:Q4_K_M | ||
| 69 | + llmman serve | ||
| 70 | + ``` | ||
| 71 | + | ||
| 72 | +- **Node.js** (les hooks), **Go** ≥ 1.24 et **git** (le reviewer lit `git diff`). | ||
| 73 | +- **gopls** dans le `PATH` : `go install golang.org/x/tools/gopls@latest` (puis `$(go env GOPATH)/bin` dans le `PATH`). Sans lui, chaque spécialiste démarre avec un avertissement et sans outil `lsp`. | ||
| 74 | +- **mm** compilé à la racine du dépôt : `go build -o mm .` | ||
| 75 | + | ||
| 76 | +## Organisation : agents en lecture seule, code en lecture-écriture | ||
| 77 | + | ||
| 78 | + | ||
| 79 | + | ||
| 80 | +``` | ||
| 81 | +dev.team/ | ||
| 82 | +├── sbxenv.yaml, start-zed.sh, stop-zed.sh la sandbox — jamais montés | ||
| 83 | +├── README.*, dev-team-*.{drawio,svg,png} cette documentation | ||
| 84 | +├── team/ les agents et leurs hooks → monté en LECTURE SEULE | ||
| 85 | +└── workspace/ votre code (vide dans le dépôt), .mm/ → l'espace de travail en lecture-écriture | ||
| 86 | +``` | ||
| 87 | + | ||
| 88 | +Les fichiers des agents décident de ce que l'équipe a le droit de faire : leurs prompts, leurs outils, `yolo`, les hooks. Un membre de l'équipe qui a `bash` et `write_file` pourrait les réécrire, et le prochain démarrage exécuterait sa version. Ils sont donc dans `team/`, que la sandbox monte avec `readOnly: true`, à part du code que l'équipe modifie. Docker recommande aussi de garder le fichier d'environnement hors de tout dossier monté, pour qu'un agent ne puisse pas changer les commandes que lance votre machine : `sbxenv.yaml` et les scripts restent à la racine de `dev.team/`, qui n'est pas montée. | ||
| 89 | + | ||
| 90 | +mm trouve le coordinateur grâce à `AGENT_CONFIG`, défini dans `sbxenv.yaml` ; les autres agents et les hooks sont trouvés à côté (les chemins de `mmConfigs` et `$MM_CONFIG_DIR` sont relatifs à `team/agent.yaml`). Les sessions et les traces vont dans `workspace/.mm/`, le dossier de travail de la session. | ||
| 91 | + | ||
| 92 | +## Lancer | ||
| 93 | + | ||
| 94 | +### Dans une sandbox, avec Zed | ||
| 95 | + | ||
| 96 | +```bash | ||
| 97 | +cd dev.team | ||
| 98 | +sbx setup ssh # une fois | ||
| 99 | +./start-zed.sh # sbx env create --env-arg DEV_TEAM_DIR=$PWD, puis Zed sur workspace/ | ||
| 100 | +./stop-zed.sh # supprime la sandbox ; team/ et workspace/ restent sur la machine | ||
| 101 | +``` | ||
| 102 | + | ||
| 103 | +`start-zed.sh` passe le dossier de `sbxenv.yaml` comme argument `DEV_TEAM_DIR` ; `sbxenv.yaml` en construit `AGENT_CONFIG=<DEV_TEAM_DIR>/team/agent.yaml`. Dans un terminal de la sandbox, depuis `workspace/` : `mm -tui` (il lit `AGENT_CONFIG`). | ||
| 104 | + | ||
| 105 | +Pour vérifier, une fois la sandbox lancée : `sbx version` (`sbx env` demande la 0.39.0 ou plus, ce qui place aussi après la CVE-2026-18171, qui permettait d'écrire dans un montage en lecture seule en 0.35.0–0.38.0) ; dans la sandbox, `echo $AGENT_CONFIG`, `ls "$(dirname "$AGENT_CONFIG")"` et `touch "$(dirname "$AGENT_CONFIG")/x"`, qui doit échouer. | ||
| 106 | + | ||
| 107 | +### Sur la machine | ||
| 108 | + | ||
| 109 | +```bash | ||
| 110 | +cd dev.team/workspace | ||
| 111 | +AGENT_CONFIG=$PWD/../team/agent.yaml ../../mm -tui | ||
| 112 | +../../mm -config ../team/agent.yaml -tui # la même chose | ||
| 113 | +../../mm -config ../team/agent.yaml -p "…" # une demande, puis sortie (le reformulator ne peut rien vous demander) | ||
| 114 | +``` | ||
| 115 | + | ||
| 116 | +La sandbox publie les ports 8080, 6060 et 5050 sur les mêmes ports de la machine (`ports` dans `sbxenv.yaml`, appliqué à la création) : un serveur lancé dans la sandbox doit écouter sur `0.0.0.0` pour être joignable sur `http://localhost:8080`. | ||
| 117 | + | ||
| 118 | +Sur la machine, rien ne met `team/` en lecture seule : cette protection est celle de la sandbox. | ||
| 119 | + | ||
| 120 | +Dans la fenêtre, l'en-tête nomme l'agent au travail : `mm [🧭 Coordinator] · qwen3.5-4b:Q4_K_M @ llmman`, puis `mm [🛠️ Coder] · … · asked by mm [🧭 Coordinator]` pendant un passage de main. | ||
| 121 | + | ||
| 122 | +`yolo: true` dans `agent.yaml` et dans chaque entrée de `mmConfigs` : les passages de main, les commandes et les écritures de fichiers se font sans demander. Pour approuver chaque passage de main et lire le prompt écrit par le coordinateur : `AGENT_YOLO=false` devant `mm`. | ||
| 123 | + | ||
| 124 | +Chaque spécialiste fonctionne aussi seul, par exemple `mm -config ../team/agent.tutor.yaml` depuis `workspace/` (seuls, ils demandent avant chaque commande et chaque modification de fichier, sauf le tutor). | ||
| 125 | + | ||
| 126 | +## Exemples à essayer | ||
| 127 | + | ||
| 128 | +Mettez un projet dans `workspace/`, en dépôt git avec son dernier état commité, pour que le `git diff` du reviewer ne montre que la modification de l'équipe. Les exemples l'appellent `my-app`. | ||
| 129 | + | ||
| 130 | +| Route | Demande | Ce qui doit se passer | | ||
| 131 | +|---|---|---| | ||
| 132 | +| A | `Corrige le bug de my-app : <ce qui ne va pas, avec une entrée et la sortie attendue>.` | brief → correction + un cas de test → reviewer `VERDICT: PASS` | | ||
| 133 | +| A | `Ajoute à my-app une fonction qui renvoie les mots les plus fréquents d'un texte.` | le reformulator vous demande combien, la casse, la ponctuation, le type de retour (avec `-p` : il choisit et liste ses ASSUMPTIONS) | | ||
| 134 | +| A | `Renomme <AncienNom> en <NouveauNom> partout dans my-app.` | brief → `lsp rename` + tests → revue | | ||
| 135 | +| B | `Quelle est la différence entre strings.Split et strings.Fields ?` | un mini tutoriel en français | | ||
| 136 | +| B | `Explique les tests en table en Go, avec my-app/<fichier>_test.go comme exemple.` | le tutor lit le fichier et bâtit la leçon sur son vrai code | | ||
| 137 | +| B | `Explique-moi les goroutines avec un petit exemple, et sauve-le dans goroutines.md.` | un tutoriel en français, enregistré avec `save_answer` | | ||
| 138 | +| C | `Fais la revue du code de my-app et dis-moi ce qui ne va pas.` | des constats avec fichier:ligne, les tests, le verdict | | ||
| 139 | + | ||
| 140 | +## Résultats mesurés | ||
| 141 | + | ||
| 142 | +llmman sur la machine de 32 Go de l'utilisateur, le 2026-10-25, sur le paquet d'entraînement `textstats` (`playground/` dans les tableaux), avant que `workspace/` soit vidé. | ||
| 143 | + | ||
| 144 | +### Chaque agent seul | ||
| 145 | + | ||
| 146 | +| Agent | Tâche | Résultat | Temps | | ||
| 147 | +|---|---|---|---| | ||
| 148 | +| coder | le bug de `WordCount` | corrigé avec `strings.Fields`, 4 cas de test ajoutés, tests au vert | 351 s | | ||
| 149 | +| reviewer | revue de cette correction | `git diff`, tests, son propre `review_test.go`, `VERDICT: PASS` | 151 s | | ||
| 150 | +| tutor | les tests en table sur `playground/textstats_test.go` | 3 exécutions sur 3 lisent le fichier et enseignent sur sa vraie table `map[string]int` | 12–19 s | | ||
| 151 | +| reformulator | « une fonction qui donne les mots les plus fréquents » | lit le code, appelle `ask_user` ; sans personne pour répondre (`-p`), liste ses choix sous ASSUMPTIONS | 62 s | | ||
| 152 | + | ||
| 153 | +Ce que ces exécutions ont changé dans les fichiers : | ||
| 154 | + | ||
| 155 | +- **coder** : une fois, après un `edit_file` raté, Mellum2 a écrit un appel d'outil jamais refermé, qui a couru jusqu'à `max_tokens` (8192) : l'essentiel des 351 s. `max_tokens` vaut maintenant 4096, ce qui divise par deux le coût d'un tel appel. | ||
| 156 | +- **tutor** : la première version répondait en 24 s mais montrait un fichier de test « typique » qu'elle avait inventé. Le prompt fait maintenant de `read_file` sa première action quand un fichier est nommé. | ||
| 157 | +- **reformulator** : la première version ne listait pas ses choix, et mettait « top N » hors périmètre pour « les mots les plus fréquents ». Le prompt nomme maintenant ce que seul l'utilisateur décide, et le brief a une section ASSUMPTIONS. | ||
| 158 | + | ||
| 159 | +### L'équipe a-t-elle besoin d'un modèle de décision ? | ||
| 160 | + | ||
| 161 | +La question du ticket. Un décideur (voir `demos/decision-*`) serait utile si le coordinateur se trompait de route. Mesuré : le coordinateur (Qwen3.5 4B, sans raisonnement) sur 12 demandes — 5 modifications de code, 5 questions (dont 2 en français), 2 revues — **12 sur 12 vers le bon agent**. Un décideur ajouterait un modèle et un appel pour rien. Là où il pourrait servir plus tard, à mesurer d'abord : repérer une demande trop vague pour être codée (une question noul avant le reformulator), ou lire le verdict du reviewer. | ||
| 162 | + | ||
| 163 | +### L'équipe entière | ||
| 164 | + | ||
| 165 | +Par le coordinateur, `-p`, `AGENT_YOLO=true` ; les modèles chargés dans llmman relevés toutes les 2 secondes. | ||
| 166 | + | ||
| 167 | +| Exécution | Route | Résultat | Temps | | ||
| 168 | +|---|---|---|---| | ||
| 169 | +| correction du bug, 1re | A | `VERDICT: PASS`, mais le coder a bouclé sur `plan update` et a été appelé deux fois ; le compte rendu disait « aucune modification » | 685 s | | ||
| 170 | +| correction du bug, 2e (après les corrections ci-dessous) | A | un appel par agent, `VERDICT: PASS`, code formaté, compte rendu exact | 398 s | | ||
| 171 | +| « explique-moi strings.Split et strings.Fields » | B | le tutor répond en français, juste | 49 s | | ||
| 172 | +| « les mots les plus fréquents », 1re | A | **échec** : le reviewer a testé un comportement absent du brief et atteint ses 20 tours ; le coordinateur l'a redemandé, puis a appelé le coder 4 fois ; tests rouges à la fin | 52 min | | ||
| 173 | +| « les mots les plus fréquents », 2e (après les corrections ci-dessous) | A | **échec** : un bon brief (top 3), puis le coder a eu la même coupure et le coordinateur l'a redemandé ; le reviewer est resté à `VERDICT: FAIL` (2 de ses 7 cas) ; arrêté par la limite de 30 minutes de la mesure | 30 min | | ||
| 174 | + | ||
| 175 | +**Mémoire : pendant les passages de main de l'équipe, jamais deux modèles chargés en même temps** : 4B → Gemma → 4B → Mellum2 → 4B → Gemma → 4B. Le seul chevauchement vu (les 3 premières minutes de la dernière exécution) était un Mellum2 laissé chargé par une mesure lancée avant l'équipe : les hooks déchargent les modèles des passages de main, pas un modèle chargé par autre chose. | ||
| 176 | + | ||
| 177 | +**En bref : les corrections de bugs, les leçons et les revues fonctionnent ; les nouvelles fonctionnalités, pas encore.** Le maillon faible est le coder : sur une fonctionnalité, Mellum2 écrit des appels d'outil qui se répètent jusqu'à `max_tokens`, et le coordinateur 4B le redemande alors malgré son prompt. Essayez `agent.coder.ornith.yaml` pour les fonctionnalités (voir plus bas). | ||
| 178 | + | ||
| 179 | +Ce que ces exécutions ont changé : | ||
| 180 | + | ||
| 181 | +- **coder** : plus d'outil `plan` (Mellum2 appelait `plan update` en boucle) ; « ajoute des cas de test, garde les existants » ; le hook `gofmt`. | ||
| 182 | +- **reviewer** : ses tests couvrent seulement l'ACCEPTANCE et les REQUIREMENTS du brief ; un de ses cas qui échoue est un constat (pas de réécriture jusqu'à ce qu'il passe) ; `gofmt -l` et des cas de test supprimés sont des constats ; `maxTurns` 20 → 12 (puis 16, voir plus bas). | ||
| 183 | +- **coordinateur** : `maxTurns` 8 → 6 ; « ne jamais redemander à un agent avec un nouveau prompt » ; le compte rendu prend les fichiers dans les réponses du coder et du reviewer. | ||
| 184 | + | ||
| 185 | +### Avec le serveur de langage Go | ||
| 186 | + | ||
| 187 | +Mesuré après l'ajout de `lsp` (gopls v0.24.0) : | ||
| 188 | + | ||
| 189 | +| Agent | Tâche | Résultat | Temps | | ||
| 190 | +|---|---|---|---| | ||
| 191 | +| coder, 1er prompt | « Rename LineCount to CountLines everywhere in playground » | a appelé `rename` sans `new_name`, puis a recopié l'indication mot pour mot : la fonction est devenue `new_name`, et le compte rendu disait « renommée en CountLines » | 18 s | | ||
| 192 | +| coder, avec un exemple rempli dans le prompt | la même | 3 exécutions sur 3 : `lsp rename` → `CountLines`, tests au vert | 5–10 s | | ||
| 193 | +| reviewer | revue de ce renommage | exécution 1 : un appel d'outil qui se répétait, arrêté par mm ; exécution 2 : `references` + 2 `diagnostics`, un vrai constat (le message d'erreur du test dit encore `LineCount` : `rename` change les identifiants, pas les chaînes), `VERDICT: FAIL` | 200 s, 167 s | | ||
| 194 | + | ||
| 195 | +Le prompt du reviewer a aussi dû préciser de lancer `git diff` **dans** `playground/` : depuis le dossier au-dessus, git lit le dépôt de mm, où `playground/` est ignoré, et le diff est vide. Son `maxTurns` vaut maintenant 16 : 12 coupait une revue normale (13 appels) avant son verdict. | ||
| 196 | + | ||
| 197 | +### Quel coder ? | ||
| 198 | + | ||
| 199 | +Le ticket permet de remettre en question ses choix de modèles : le coder a donc été mesuré seul sur le brief du reformulator pour « les mots les plus fréquents », contre un test caché fait des cas d'acceptation du brief (copié après l'exécution), `go vet` et `gofmt` : | ||
| 200 | + | ||
| 201 | +| Coder | Exécutions justes | Temps par exécution | Formaté | | ||
| 202 | +|---|---|---|---| | ||
| 203 | +| Mellum2 12B-A2.5B Instruct (`agent.coder.yaml`) | 2 sur 3 | 129 s, 132 s, 639 s (l'échec) | non (avant le hook) | | ||
| 204 | +| Ornith 1.5 9B, raisonnement activé (`agent.coder.ornith.yaml`) | 2 sur 2 | 783 s, 810 s | oui | | ||
| 205 | + | ||
| 206 | +Mellum2 reste le coder par défaut, comme le ticket l'a choisi : environ 6 fois plus rapide, et juste 2 fois sur 3. Son mode d'échec est celui vu plus haut : un appel d'outil qui se répète jusqu'à `max_tokens`. Ornith est le choix le plus régulier quand le temps compte moins : faites pointer `mmConfigs.coder.path` sur `agent.coder.ornith.yaml` (6,7 Go, donc rien ne change au pic mémoire). | ||
| 207 | + | ||
| 208 | +## Limites | ||
| 209 | + | ||
| 210 | +- **Le bash du reformulator n'est en lecture seule que par son prompt.** Il n'a pas d'outils de fichiers, mais `bash` pourrait écrire ; avec `yolo: true`, rien ne demande. Pour une garantie, ajoutez un hook `preToolCall` qui refuse les commandes qui écrivent (voir `demos/hooks`). | ||
| 211 | +- **L'équipe peut écrire partout dans `workspace/`, pas seulement dans `playground/`.** Une fois, avant la séparation, un membre a écrit un `main.go` à côté de `agent.yaml`, ce qui cassait le `go vet ./...` de mm. Dans la sandbox, il ne peut plus toucher `team/` ; regardez `git status` après une exécution. | ||
| 212 | +- **`-p` ne peut rien vous demander** : le reformulator choisit alors, et le dit. | ||
| 213 | +- **Chaque rechargement coûte du temps** : décharger à chaque passage de main échange des secondes de chargement contre de la mémoire. Sur une machine avec plus de mémoire, retirez le hook `preAsk` pour garder le 4B chargé. | ||
| 214 | +- Quand `ask_agent` est refusé (`yolo: false` et vous dites non), le coordinateur 4B a tendance à essayer un autre agent plutôt qu'à s'arrêter ; après un passage de main raté, il redemande à l'agent bien que son prompt le lui interdise (`maxTurns: 6` le borne). | ||
| 215 | +- Un modèle déjà chargé avant que l'équipe démarre (par un autre agent, ou `llmman run`) reste chargé à côté de ceux de l'équipe : déchargez-le d'abord (`curl -s http://127.0.0.1:17434/api/generate -d '{"model":"…","keep_alive":0}'`). | ||
| 216 | + | ||
| 217 | +## Fichiers | ||
| 218 | + | ||
| 219 | +``` | ||
| 220 | +dev.team/ | ||
| 221 | +├── sbxenv.yaml la sandbox : workspace/ en lecture-écriture, team/ en lecture seule, AGENT_CONFIG | ||
| 222 | +├── start-zed.sh, stop-zed.sh créer la sandbox et ouvrir workspace/ dans Zed ; la supprimer | ||
| 223 | +├── team/ en lecture seule dans la sandbox | ||
| 224 | +│ ├── agent.yaml coordinateur (🧭) | ||
| 225 | +│ ├── agent.reformulator.yaml 📝 | ||
| 226 | +│ ├── agent.coder.yaml 🛠️ | ||
| 227 | +│ ├── agent.coder.ornith.yaml 🛠️ le coder sur Ornith 1.5 9B (plus régulier, plus lent) | ||
| 228 | +│ ├── agent.reviewer.yaml 🔎 | ||
| 229 | +│ ├── agent.tutor.yaml 📘 (la configuration « prof » du ticket 152, adaptée) | ||
| 230 | +│ └── hooks/ unload.js (un seul modèle en mémoire), gofmt.js (le formatage du coder) | ||
| 231 | +├── workspace/ en lecture-écriture : vide dans le dépôt (.gitkeep) — votre projet va ici ; | ||
| 232 | +│ .mm/ (sessions, traces) est créé à la première exécution | ||
| 233 | +├── dev-team-flow.* diagramme : les trois routes (.drawio .svg .png) | ||
| 234 | +├── dev-team-memory.* diagramme : les déchargements (.drawio .svg .png) | ||
| 235 | +└── dev-team-sandbox.* diagramme : les montages de la sandbox (.drawio .svg .png) | ||
| 236 | +``` | ||
| 237 | + | ||
| 238 | +Les diagrammes sont générés par `.claude/skills/drawio-fancy-diagram/generator/examples/dev_team.py dev.team`. | ||
added
dev.team/dev-team-flow.drawio +37 -0 | new file mode 100644 | ||
| @@ -0,0 +1,37 @@ | ||
| 1 | +<mxfile host="app.diagrams.net"> | |
| 2 | + <diagram id="dev-team-flow" name="dev.team — a coordinator and four specialists"> | |
| 3 | + <mxGraphModel dx="1200" dy="720" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1200" pageHeight="720" background="#F5F7FC" math="0" shadow="0"> | |
| 4 | + <root> | |
| 5 | + <mxCell id="0"/> | |
| 6 | + <mxCell id="1" parent="0"/> | |
| 7 | + <mxCell id="title" value="<b style="font-size:25px;color:#1A237E">dev.team — a coordinator and four specialists</b><br><i style="font-size:14px;color:#546E7A">the coordinator picks a route and calls each agent with ask_agent, one at a time</i>" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="150.0" y="12" width="900" height="56" as="geometry"/></mxCell> | |
| 8 | + <mxCell id="c9" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="880" y="185" as="sourcePoint"/><mxPoint x="910" y="185" as="targetPoint"/></mxGeometry></mxCell> | |
| 9 | + <mxCell id="c10" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="1025" y="240" as="sourcePoint"/><mxPoint x="930" y="290" as="targetPoint"/><Array as="points"><mxPoint x="1025" y="265"/><mxPoint x="930" y="265"/></Array></mxGeometry></mxCell> | |
| 10 | + <mxCell id="c17" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=block;startFill=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="220" y="210" as="sourcePoint"/><mxPoint x="300" y="210" as="targetPoint"/></mxGeometry></mxCell> | |
| 11 | + <mxCell id="c19" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="550" y="180" as="sourcePoint"/><mxPoint x="620" y="180" as="targetPoint"/></mxGeometry></mxCell> | |
| 12 | + <mxCell id="c21" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="425" y="280" as="sourcePoint"/><mxPoint x="650" y="605" as="targetPoint"/><Array as="points"><mxPoint x="425" y="605"/></Array></mxGeometry></mxCell> | |
| 13 | + <mxCell id="c23" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="550" y="250" as="sourcePoint"/><mxPoint x="1055" y="660" as="targetPoint"/><Array as="points"><mxPoint x="590" y="250"/><mxPoint x="590" y="690"/><mxPoint x="1055" y="690"/></Array></mxGeometry></mxCell> | |
| 14 | + <mxCell id="c25" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;dashed=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="620" y="470" as="sourcePoint"/><mxPoint x="260" y="500" as="targetPoint"/></mxGeometry></mxCell> | |
| 15 | + <mxCell id="c1" value="🧑<br><b style="font-size:16px">You</b><br><span style="font-size:11.5px;font-weight:normal">a request<br>Zed or mm -tui · workspace/</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E3F2FD;gradientColor=#BBDEFB;strokeColor=#1565C0;strokeWidth=2;shadow=1;fontSize=20;fontColor=#0D47A1;" vertex="1" parent="1"><mxGeometry x="40" y="150" width="180" height="120" as="geometry"/></mxCell> | |
| 16 | + <mxCell id="c2" value="🔀<br><b style="font-size:16px">Coordinator</b><br><span style="font-size:11.5px;font-weight:normal">Qwen3.5-4B · agent.yaml<br>only tool: ask_agent<br>picks route A, B or C</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#F3E5F5;gradientColor=#E1BEE7;strokeColor=#6A1B9A;strokeWidth=3;shadow=1;fontSize=20;fontColor=#4A148C;" vertex="1" parent="1"><mxGeometry x="300" y="140" width="250" height="140" as="geometry"/></mxCell> | |
| 17 | + <mxCell id="c3" value="<b>★ routes</b>" style="rounded=1;arcSize=50;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=11;" vertex="1" parent="1"><mxGeometry x="488.4" y="128" width="71.6" height="24" as="geometry"/></mxCell> | |
| 18 | + <mxCell id="c4" value="<i><b>route A — code to write or change (in order)</b></i>" style="rounded=1;arcSize=3;html=1;dashed=1;dashPattern=7 5;fillColor=#FAFAFA;strokeColor=#90A4AE;strokeWidth=2;verticalAlign=top;fontColor=#607D8B;fontSize=13;" vertex="1" parent="1"><mxGeometry x="620" y="90" width="550" height="400" as="geometry"/></mxCell> | |
| 19 | + <mxCell id="c5" value="💬<br><b style="font-size:15px">1 · Reformulator</b><br><span style="font-size:11.5px;font-weight:normal">Gemma 4 12B<br>task brief · ask_user</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="650" y="130" width="230" height="110" as="geometry"/></mxCell> | |
| 20 | + <mxCell id="c6" value="🛠️<br><b style="font-size:15px">2 · Coder</b><br><span style="font-size:11.5px;font-weight:normal">Mellum2 12B<br>bash · files · tests</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="910" y="130" width="230" height="110" as="geometry"/></mxCell> | |
| 21 | + <mxCell id="c7" value="🔎<br><b style="font-size:15px">3 · Reviewer</b><br><span style="font-size:11.5px;font-weight:normal">Gemma 4 12B<br>tests · VERDICT</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="780" y="290" width="230" height="110" as="geometry"/></mxCell> | |
| 22 | + <mxCell id="c8" value="VERDICT: FAIL → the coder fixes ONCE → the reviewer again" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;fontSize=12;fontColor=#455A64;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="682.96" y="438" width="424.08" height="18" as="geometry"/></mxCell> | |
| 23 | + <mxCell id="c11" value="<b style="font-size:12.5px;color:#263238">brief + report</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="1005.0" y="253.0" width="110" height="24" as="geometry"/></mxCell> | |
| 24 | + <mxCell id="c12" value="📘<br><b style="font-size:15px">Tutor</b><br><span style="font-size:11.5px;font-weight:normal">Mellum2 12B<br>mini tutorials · save_answer</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="650" y="550" width="230" height="110" as="geometry"/></mxCell> | |
| 25 | + <mxCell id="c13" value="route B — a question, a lesson" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;fontSize=12.5;fontColor=#607D8B;fontStyle=3;" vertex="1" parent="1"><mxGeometry x="648.75" y="517.5" width="232.5" height="18.5" as="geometry"/></mxCell> | |
| 26 | + <mxCell id="c14" value="🔎<br><b style="font-size:15px">Reviewer</b><br><span style="font-size:11.5px;font-weight:normal">review existing code<br>no change</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="940" y="550" width="230" height="110" as="geometry"/></mxCell> | |
| 27 | + <mxCell id="c15" value="route C — only a review" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;fontSize=12.5;fontColor=#607D8B;fontStyle=3;" vertex="1" parent="1"><mxGeometry x="965.875" y="517.5" width="178.25" height="18.5" as="geometry"/></mxCell> | |
| 28 | + <mxCell id="c16" value="💻<br><b style="font-size:15px">workspace/</b><br><span style="font-size:11.5px;font-weight:normal">your project<br>a git repo: git diff</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=20;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="40" y="440" width="220" height="120" as="geometry"/></mxCell> | |
| 29 | + <mxCell id="c18" value="<b style="font-size:12.5px;color:#263238">request</b><br><span style="font-size:10.5px;color:#78909C">← report</span>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="222.0" y="218.0" width="76" height="40" as="geometry"/></mxCell> | |
| 30 | + <mxCell id="c20" value="<b style="font-size:12.5px;color:#263238">A</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="570.0" y="168.0" width="30" height="24" as="geometry"/></mxCell> | |
| 31 | + <mxCell id="c22" value="<b style="font-size:12.5px;color:#263238">B</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="410.0" y="428.0" width="30" height="24" as="geometry"/></mxCell> | |
| 32 | + <mxCell id="c24" value="<b style="font-size:12.5px;color:#263238">C</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="815.0" y="678.0" width="30" height="24" as="geometry"/></mxCell> | |
| 33 | + <mxCell id="c26" value="<b style="font-size:12.5px;color:#263238">reads · changes · tests</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="255.0" y="482.0" width="150" height="24" as="geometry"/></mxCell> | |
| 34 | + </root> | |
| 35 | + </mxGraphModel> | |
| 36 | + </diagram> | |
| 37 | +</mxfile> | |
| new file mode 100644 | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | +<mxfile host="app.diagrams.net"> | ||
| 2 | + <diagram id="dev-team-flow" name="dev.team — a coordinator and four specialists"> | ||
| 3 | + <mxGraphModel dx="1200" dy="720" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1200" pageHeight="720" background="#F5F7FC" math="0" shadow="0"> | ||
| 4 | + <root> | ||
| 5 | + <mxCell id="0"/> | ||
| 6 | + <mxCell id="1" parent="0"/> | ||
| 7 | + <mxCell id="title" value="<b style="font-size:25px;color:#1A237E">dev.team — a coordinator and four specialists</b><br><i style="font-size:14px;color:#546E7A">the coordinator picks a route and calls each agent with ask_agent, one at a time</i>" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="150.0" y="12" width="900" height="56" as="geometry"/></mxCell> | ||
| 8 | + <mxCell id="c9" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="880" y="185" as="sourcePoint"/><mxPoint x="910" y="185" as="targetPoint"/></mxGeometry></mxCell> | ||
| 9 | + <mxCell id="c10" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="1025" y="240" as="sourcePoint"/><mxPoint x="930" y="290" as="targetPoint"/><Array as="points"><mxPoint x="1025" y="265"/><mxPoint x="930" y="265"/></Array></mxGeometry></mxCell> | ||
| 10 | + <mxCell id="c17" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=block;startFill=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="220" y="210" as="sourcePoint"/><mxPoint x="300" y="210" as="targetPoint"/></mxGeometry></mxCell> | ||
| 11 | + <mxCell id="c19" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="550" y="180" as="sourcePoint"/><mxPoint x="620" y="180" as="targetPoint"/></mxGeometry></mxCell> | ||
| 12 | + <mxCell id="c21" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="425" y="280" as="sourcePoint"/><mxPoint x="650" y="605" as="targetPoint"/><Array as="points"><mxPoint x="425" y="605"/></Array></mxGeometry></mxCell> | ||
| 13 | + <mxCell id="c23" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="550" y="250" as="sourcePoint"/><mxPoint x="1055" y="660" as="targetPoint"/><Array as="points"><mxPoint x="590" y="250"/><mxPoint x="590" y="690"/><mxPoint x="1055" y="690"/></Array></mxGeometry></mxCell> | ||
| 14 | + <mxCell id="c25" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;dashed=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="620" y="470" as="sourcePoint"/><mxPoint x="260" y="500" as="targetPoint"/></mxGeometry></mxCell> | ||
| 15 | + <mxCell id="c1" value="🧑<br><b style="font-size:16px">You</b><br><span style="font-size:11.5px;font-weight:normal">a request<br>Zed or mm -tui · workspace/</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E3F2FD;gradientColor=#BBDEFB;strokeColor=#1565C0;strokeWidth=2;shadow=1;fontSize=20;fontColor=#0D47A1;" vertex="1" parent="1"><mxGeometry x="40" y="150" width="180" height="120" as="geometry"/></mxCell> | ||
| 16 | + <mxCell id="c2" value="🔀<br><b style="font-size:16px">Coordinator</b><br><span style="font-size:11.5px;font-weight:normal">Qwen3.5-4B · agent.yaml<br>only tool: ask_agent<br>picks route A, B or C</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#F3E5F5;gradientColor=#E1BEE7;strokeColor=#6A1B9A;strokeWidth=3;shadow=1;fontSize=20;fontColor=#4A148C;" vertex="1" parent="1"><mxGeometry x="300" y="140" width="250" height="140" as="geometry"/></mxCell> | ||
| 17 | + <mxCell id="c3" value="<b>★ routes</b>" style="rounded=1;arcSize=50;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=11;" vertex="1" parent="1"><mxGeometry x="488.4" y="128" width="71.6" height="24" as="geometry"/></mxCell> | ||
| 18 | + <mxCell id="c4" value="<i><b>route A — code to write or change (in order)</b></i>" style="rounded=1;arcSize=3;html=1;dashed=1;dashPattern=7 5;fillColor=#FAFAFA;strokeColor=#90A4AE;strokeWidth=2;verticalAlign=top;fontColor=#607D8B;fontSize=13;" vertex="1" parent="1"><mxGeometry x="620" y="90" width="550" height="400" as="geometry"/></mxCell> | ||
| 19 | + <mxCell id="c5" value="💬<br><b style="font-size:15px">1 · Reformulator</b><br><span style="font-size:11.5px;font-weight:normal">Gemma 4 12B<br>task brief · ask_user</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="650" y="130" width="230" height="110" as="geometry"/></mxCell> | ||
| 20 | + <mxCell id="c6" value="🛠️<br><b style="font-size:15px">2 · Coder</b><br><span style="font-size:11.5px;font-weight:normal">Mellum2 12B<br>bash · files · tests</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="910" y="130" width="230" height="110" as="geometry"/></mxCell> | ||
| 21 | + <mxCell id="c7" value="🔎<br><b style="font-size:15px">3 · Reviewer</b><br><span style="font-size:11.5px;font-weight:normal">Gemma 4 12B<br>tests · VERDICT</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="780" y="290" width="230" height="110" as="geometry"/></mxCell> | ||
| 22 | + <mxCell id="c8" value="VERDICT: FAIL → the coder fixes ONCE → the reviewer again" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;fontSize=12;fontColor=#455A64;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="682.96" y="438" width="424.08" height="18" as="geometry"/></mxCell> | ||
| 23 | + <mxCell id="c11" value="<b style="font-size:12.5px;color:#263238">brief + report</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="1005.0" y="253.0" width="110" height="24" as="geometry"/></mxCell> | ||
| 24 | + <mxCell id="c12" value="📘<br><b style="font-size:15px">Tutor</b><br><span style="font-size:11.5px;font-weight:normal">Mellum2 12B<br>mini tutorials · save_answer</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="650" y="550" width="230" height="110" as="geometry"/></mxCell> | ||
| 25 | + <mxCell id="c13" value="route B — a question, a lesson" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;fontSize=12.5;fontColor=#607D8B;fontStyle=3;" vertex="1" parent="1"><mxGeometry x="648.75" y="517.5" width="232.5" height="18.5" as="geometry"/></mxCell> | ||
| 26 | + <mxCell id="c14" value="🔎<br><b style="font-size:15px">Reviewer</b><br><span style="font-size:11.5px;font-weight:normal">review existing code<br>no change</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="940" y="550" width="230" height="110" as="geometry"/></mxCell> | ||
| 27 | + <mxCell id="c15" value="route C — only a review" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;fontSize=12.5;fontColor=#607D8B;fontStyle=3;" vertex="1" parent="1"><mxGeometry x="965.875" y="517.5" width="178.25" height="18.5" as="geometry"/></mxCell> | ||
| 28 | + <mxCell id="c16" value="💻<br><b style="font-size:15px">workspace/</b><br><span style="font-size:11.5px;font-weight:normal">your project<br>a git repo: git diff</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=20;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="40" y="440" width="220" height="120" as="geometry"/></mxCell> | ||
| 29 | + <mxCell id="c18" value="<b style="font-size:12.5px;color:#263238">request</b><br><span style="font-size:10.5px;color:#78909C">← report</span>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="222.0" y="218.0" width="76" height="40" as="geometry"/></mxCell> | ||
| 30 | + <mxCell id="c20" value="<b style="font-size:12.5px;color:#263238">A</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="570.0" y="168.0" width="30" height="24" as="geometry"/></mxCell> | ||
| 31 | + <mxCell id="c22" value="<b style="font-size:12.5px;color:#263238">B</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="410.0" y="428.0" width="30" height="24" as="geometry"/></mxCell> | ||
| 32 | + <mxCell id="c24" value="<b style="font-size:12.5px;color:#263238">C</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="815.0" y="678.0" width="30" height="24" as="geometry"/></mxCell> | ||
| 33 | + <mxCell id="c26" value="<b style="font-size:12.5px;color:#263238">reads · changes · tests</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="255.0" y="482.0" width="150" height="24" as="geometry"/></mxCell> | ||
| 34 | + </root> | ||
| 35 | + </mxGraphModel> | ||
| 36 | + </diagram> | ||
| 37 | +</mxfile> | ||
added
dev.team/dev-team-flow.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/dev.team/dev-team-flow.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/dev.team/dev-team-flow.png differ | Binary files /dev/null and b/dev.team/dev-team-flow.png differ | ||
added
dev.team/dev-team-flow.svg +83 -0 | new file mode 100644 | ||
| @@ -0,0 +1,83 @@ | ||
| 1 | +<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="720" viewBox="0 0 1200 720" font-family="DejaVu Sans, Verdana, sans-serif"> | |
| 2 | + <defs> | |
| 3 | + <linearGradient id="gBg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#EEF2FA"/></linearGradient> | |
| 4 | + <linearGradient id="gBlue" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#E3F2FD"/><stop offset="100%" stop-color="#BBDEFB"/></linearGradient> | |
| 5 | + <linearGradient id="gBlue2" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#E1F5FE"/><stop offset="100%" stop-color="#B3E5FC"/></linearGradient> | |
| 6 | + <linearGradient id="gPurple" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#F3E5F5"/><stop offset="100%" stop-color="#E1BEE7"/></linearGradient> | |
| 7 | + <linearGradient id="gYellow" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#FFFDE7"/><stop offset="100%" stop-color="#FFF9C4"/></linearGradient> | |
| 8 | + <linearGradient id="gGrey" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#ECEFF1"/><stop offset="100%" stop-color="#CFD8DC"/></linearGradient> | |
| 9 | + <filter id="shadow" x="-30%" y="-30%" width="160%" height="160%"><feDropShadow dx="2" dy="3" stdDeviation="4" flood-color="#000000" flood-opacity="0.25"/></filter> | |
| 10 | + <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#37474F"/></marker> | |
| 11 | + </defs> | |
| 12 | + <rect x="0" y="0" width="1200" height="720" fill="url(#gBg)"/> | |
| 13 | + <text x="600.0" y="38" text-anchor="middle" font-size="25" font-weight="700" fill="#1A237E">dev.team — a coordinator and four specialists</text> | |
| 14 | + <text x="600.0" y="61" text-anchor="middle" font-size="14" font-style="italic" fill="#546E7A">the coordinator picks a route and calls each agent with ask_agent, one at a time</text> | |
| 15 | + <path d="M880,185 L910,185" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | |
| 16 | + <path d="M1025,240 L1025,265 L930,265 L930,290" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | |
| 17 | + <path d="M220,210 L300,210" fill="none" stroke="#37474F" stroke-width="2.2" marker-start="url(#arrow)" marker-end="url(#arrow)"/> | |
| 18 | + <path d="M550,180 L620,180" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | |
| 19 | + <path d="M425,280 L425,605 L650,605" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | |
| 20 | + <path d="M550,250 L590,250 L590,690 L1055,690 L1055,660" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | |
| 21 | + <path d="M620,470 L260,500" fill="none" stroke="#37474F" stroke-width="2.2" stroke-dasharray="6,4" marker-end="url(#arrow)"/> | |
| 22 | + <g filter="url(#shadow)"><rect x="40" y="150" width="180" height="120" rx="16" fill="url(#gBlue)" stroke="#1565C0" stroke-width="2"/></g> | |
| 23 | + <text x="130.0" y="190.0" text-anchor="middle" font-size="22">🧑</text> | |
| 24 | + <text x="130.0" y="213.0" text-anchor="middle" font-size="16" font-weight="700" fill="#0D47A1">You</text> | |
| 25 | + <text x="130.0" y="231.0" text-anchor="middle" font-size="11.5" fill="#0D47A1">a request</text> | |
| 26 | + <text x="130.0" y="248.0" text-anchor="middle" font-size="11.5" fill="#0D47A1">Zed or mm -tui · workspace/</text> | |
| 27 | + <g filter="url(#shadow)"><rect x="300" y="140" width="250" height="140" rx="16" fill="url(#gPurple)" stroke="#6A1B9A" stroke-width="3"/></g> | |
| 28 | + <text x="425.0" y="181.5" text-anchor="middle" font-size="22">🔀</text> | |
| 29 | + <text x="425.0" y="204.5" text-anchor="middle" font-size="16" font-weight="700" fill="#4A148C">Coordinator</text> | |
| 30 | + <text x="425.0" y="222.5" text-anchor="middle" font-size="11.5" fill="#4A148C">Qwen3.5-4B · agent.yaml</text> | |
| 31 | + <text x="425.0" y="239.5" text-anchor="middle" font-size="11.5" fill="#4A148C">only tool: ask_agent</text> | |
| 32 | + <text x="425.0" y="256.5" text-anchor="middle" font-size="11.5" fill="#4A148C">picks route A, B or C</text> | |
| 33 | + <rect x="488.4" y="128" width="71.6" height="24" rx="12" fill="#6A1B9A"/> | |
| 34 | + <text x="524.1999999999999" y="144" text-anchor="middle" font-size="11.5" font-weight="700" fill="#FFFFFF">★ routes</text> | |
| 35 | + <rect x="620" y="90" width="550" height="400" rx="10" fill="#FAFAFA" fill-opacity="0.7" stroke="#90A4AE" stroke-width="2" stroke-dasharray="7,5"/> | |
| 36 | + <text x="895.0" y="112" text-anchor="middle" font-size="13" font-style="italic" font-weight="700" fill="#607D8B">route A — code to write or change (in order)</text> | |
| 37 | + <g filter="url(#shadow)"><rect x="650" y="130" width="230" height="110" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | |
| 38 | + <text x="765.0" y="165.0" text-anchor="middle" font-size="22">💬</text> | |
| 39 | + <text x="765.0" y="188.0" text-anchor="middle" font-size="15" font-weight="700" fill="#01579B">1 · Reformulator</text> | |
| 40 | + <text x="765.0" y="206.0" text-anchor="middle" font-size="11.5" fill="#01579B">Gemma 4 12B</text> | |
| 41 | + <text x="765.0" y="223.0" text-anchor="middle" font-size="11.5" fill="#01579B">task brief · ask_user</text> | |
| 42 | + <g filter="url(#shadow)"><rect x="910" y="130" width="230" height="110" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | |
| 43 | + <text x="1025.0" y="165.0" text-anchor="middle" font-size="22">🛠️</text> | |
| 44 | + <text x="1025.0" y="188.0" text-anchor="middle" font-size="15" font-weight="700" fill="#01579B">2 · Coder</text> | |
| 45 | + <text x="1025.0" y="206.0" text-anchor="middle" font-size="11.5" fill="#01579B">Mellum2 12B</text> | |
| 46 | + <text x="1025.0" y="223.0" text-anchor="middle" font-size="11.5" fill="#01579B">bash · files · tests</text> | |
| 47 | + <g filter="url(#shadow)"><rect x="780" y="290" width="230" height="110" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | |
| 48 | + <text x="895.0" y="325.0" text-anchor="middle" font-size="22">🔎</text> | |
| 49 | + <text x="895.0" y="348.0" text-anchor="middle" font-size="15" font-weight="700" fill="#01579B">3 · Reviewer</text> | |
| 50 | + <text x="895.0" y="366.0" text-anchor="middle" font-size="11.5" fill="#01579B">Gemma 4 12B</text> | |
| 51 | + <text x="895.0" y="383.0" text-anchor="middle" font-size="11.5" fill="#01579B">tests · VERDICT</text> | |
| 52 | + <text x="895" y="450" text-anchor="middle" font-size="12" fill="#455A64" font-style="italic">VERDICT: FAIL → the coder fixes ONCE → the reviewer again</text> | |
| 53 | + <rect x="1005.0" y="253.0" width="110" height="24" rx="5" fill="#FFFFFF"/> | |
| 54 | + <text x="1060" y="269.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">brief + report</text> | |
| 55 | + <g filter="url(#shadow)"><rect x="650" y="550" width="230" height="110" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | |
| 56 | + <text x="765.0" y="585.0" text-anchor="middle" font-size="22">📘</text> | |
| 57 | + <text x="765.0" y="608.0" text-anchor="middle" font-size="15" font-weight="700" fill="#01579B">Tutor</text> | |
| 58 | + <text x="765.0" y="626.0" text-anchor="middle" font-size="11.5" fill="#01579B">Mellum2 12B</text> | |
| 59 | + <text x="765.0" y="643.0" text-anchor="middle" font-size="11.5" fill="#01579B">mini tutorials · save_answer</text> | |
| 60 | + <text x="765" y="530" text-anchor="middle" font-size="12.5" fill="#607D8B" font-style="italic" font-weight="700">route B — a question, a lesson</text> | |
| 61 | + <g filter="url(#shadow)"><rect x="940" y="550" width="230" height="110" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | |
| 62 | + <text x="1055.0" y="585.0" text-anchor="middle" font-size="22">🔎</text> | |
| 63 | + <text x="1055.0" y="608.0" text-anchor="middle" font-size="15" font-weight="700" fill="#01579B">Reviewer</text> | |
| 64 | + <text x="1055.0" y="626.0" text-anchor="middle" font-size="11.5" fill="#01579B">review existing code</text> | |
| 65 | + <text x="1055.0" y="643.0" text-anchor="middle" font-size="11.5" fill="#01579B">no change</text> | |
| 66 | + <text x="1055" y="530" text-anchor="middle" font-size="12.5" fill="#607D8B" font-style="italic" font-weight="700">route C — only a review</text> | |
| 67 | + <g filter="url(#shadow)"><rect x="40" y="440" width="220" height="120" rx="16" fill="url(#gGrey)" stroke="#455A64" stroke-width="2"/></g> | |
| 68 | + <text x="150.0" y="480.0" text-anchor="middle" font-size="22">💻</text> | |
| 69 | + <text x="150.0" y="503.0" text-anchor="middle" font-size="15" font-weight="700" fill="#263238">workspace/</text> | |
| 70 | + <text x="150.0" y="521.0" text-anchor="middle" font-size="11.5" fill="#263238">your project</text> | |
| 71 | + <text x="150.0" y="538.0" text-anchor="middle" font-size="11.5" fill="#263238">a git repo: git diff</text> | |
| 72 | + <rect x="222.0" y="218.0" width="76" height="40" rx="5" fill="#FFFFFF"/> | |
| 73 | + <text x="260" y="235" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">request</text> | |
| 74 | + <text x="260" y="251" text-anchor="middle" font-size="10.5" fill="#78909C">← report</text> | |
| 75 | + <rect x="570.0" y="168.0" width="30" height="24" rx="5" fill="#FFFFFF"/> | |
| 76 | + <text x="585" y="184.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">A</text> | |
| 77 | + <rect x="410.0" y="428.0" width="30" height="24" rx="5" fill="#FFFFFF"/> | |
| 78 | + <text x="425" y="444.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">B</text> | |
| 79 | + <rect x="815.0" y="678.0" width="30" height="24" rx="5" fill="#FFFFFF"/> | |
| 80 | + <text x="830" y="694.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">C</text> | |
| 81 | + <rect x="255.0" y="482.0" width="150" height="24" rx="5" fill="#FFFFFF"/> | |
| 82 | + <text x="330" y="498.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">reads · changes · tests</text> | |
| 83 | +</svg> | |
| new file mode 100644 | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | +<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="720" viewBox="0 0 1200 720" font-family="DejaVu Sans, Verdana, sans-serif"> | ||
| 2 | + <defs> | ||
| 3 | + <linearGradient id="gBg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#EEF2FA"/></linearGradient> | ||
| 4 | + <linearGradient id="gBlue" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#E3F2FD"/><stop offset="100%" stop-color="#BBDEFB"/></linearGradient> | ||
| 5 | + <linearGradient id="gBlue2" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#E1F5FE"/><stop offset="100%" stop-color="#B3E5FC"/></linearGradient> | ||
| 6 | + <linearGradient id="gPurple" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#F3E5F5"/><stop offset="100%" stop-color="#E1BEE7"/></linearGradient> | ||
| 7 | + <linearGradient id="gYellow" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#FFFDE7"/><stop offset="100%" stop-color="#FFF9C4"/></linearGradient> | ||
| 8 | + <linearGradient id="gGrey" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#ECEFF1"/><stop offset="100%" stop-color="#CFD8DC"/></linearGradient> | ||
| 9 | + <filter id="shadow" x="-30%" y="-30%" width="160%" height="160%"><feDropShadow dx="2" dy="3" stdDeviation="4" flood-color="#000000" flood-opacity="0.25"/></filter> | ||
| 10 | + <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#37474F"/></marker> | ||
| 11 | + </defs> | ||
| 12 | + <rect x="0" y="0" width="1200" height="720" fill="url(#gBg)"/> | ||
| 13 | + <text x="600.0" y="38" text-anchor="middle" font-size="25" font-weight="700" fill="#1A237E">dev.team — a coordinator and four specialists</text> | ||
| 14 | + <text x="600.0" y="61" text-anchor="middle" font-size="14" font-style="italic" fill="#546E7A">the coordinator picks a route and calls each agent with ask_agent, one at a time</text> | ||
| 15 | + <path d="M880,185 L910,185" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | ||
| 16 | + <path d="M1025,240 L1025,265 L930,265 L930,290" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | ||
| 17 | + <path d="M220,210 L300,210" fill="none" stroke="#37474F" stroke-width="2.2" marker-start="url(#arrow)" marker-end="url(#arrow)"/> | ||
| 18 | + <path d="M550,180 L620,180" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | ||
| 19 | + <path d="M425,280 L425,605 L650,605" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | ||
| 20 | + <path d="M550,250 L590,250 L590,690 L1055,690 L1055,660" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | ||
| 21 | + <path d="M620,470 L260,500" fill="none" stroke="#37474F" stroke-width="2.2" stroke-dasharray="6,4" marker-end="url(#arrow)"/> | ||
| 22 | + <g filter="url(#shadow)"><rect x="40" y="150" width="180" height="120" rx="16" fill="url(#gBlue)" stroke="#1565C0" stroke-width="2"/></g> | ||
| 23 | + <text x="130.0" y="190.0" text-anchor="middle" font-size="22">🧑</text> | ||
| 24 | + <text x="130.0" y="213.0" text-anchor="middle" font-size="16" font-weight="700" fill="#0D47A1">You</text> | ||
| 25 | + <text x="130.0" y="231.0" text-anchor="middle" font-size="11.5" fill="#0D47A1">a request</text> | ||
| 26 | + <text x="130.0" y="248.0" text-anchor="middle" font-size="11.5" fill="#0D47A1">Zed or mm -tui · workspace/</text> | ||
| 27 | + <g filter="url(#shadow)"><rect x="300" y="140" width="250" height="140" rx="16" fill="url(#gPurple)" stroke="#6A1B9A" stroke-width="3"/></g> | ||
| 28 | + <text x="425.0" y="181.5" text-anchor="middle" font-size="22">🔀</text> | ||
| 29 | + <text x="425.0" y="204.5" text-anchor="middle" font-size="16" font-weight="700" fill="#4A148C">Coordinator</text> | ||
| 30 | + <text x="425.0" y="222.5" text-anchor="middle" font-size="11.5" fill="#4A148C">Qwen3.5-4B · agent.yaml</text> | ||
| 31 | + <text x="425.0" y="239.5" text-anchor="middle" font-size="11.5" fill="#4A148C">only tool: ask_agent</text> | ||
| 32 | + <text x="425.0" y="256.5" text-anchor="middle" font-size="11.5" fill="#4A148C">picks route A, B or C</text> | ||
| 33 | + <rect x="488.4" y="128" width="71.6" height="24" rx="12" fill="#6A1B9A"/> | ||
| 34 | + <text x="524.1999999999999" y="144" text-anchor="middle" font-size="11.5" font-weight="700" fill="#FFFFFF">★ routes</text> | ||
| 35 | + <rect x="620" y="90" width="550" height="400" rx="10" fill="#FAFAFA" fill-opacity="0.7" stroke="#90A4AE" stroke-width="2" stroke-dasharray="7,5"/> | ||
| 36 | + <text x="895.0" y="112" text-anchor="middle" font-size="13" font-style="italic" font-weight="700" fill="#607D8B">route A — code to write or change (in order)</text> | ||
| 37 | + <g filter="url(#shadow)"><rect x="650" y="130" width="230" height="110" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | ||
| 38 | + <text x="765.0" y="165.0" text-anchor="middle" font-size="22">💬</text> | ||
| 39 | + <text x="765.0" y="188.0" text-anchor="middle" font-size="15" font-weight="700" fill="#01579B">1 · Reformulator</text> | ||
| 40 | + <text x="765.0" y="206.0" text-anchor="middle" font-size="11.5" fill="#01579B">Gemma 4 12B</text> | ||
| 41 | + <text x="765.0" y="223.0" text-anchor="middle" font-size="11.5" fill="#01579B">task brief · ask_user</text> | ||
| 42 | + <g filter="url(#shadow)"><rect x="910" y="130" width="230" height="110" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | ||
| 43 | + <text x="1025.0" y="165.0" text-anchor="middle" font-size="22">🛠️</text> | ||
| 44 | + <text x="1025.0" y="188.0" text-anchor="middle" font-size="15" font-weight="700" fill="#01579B">2 · Coder</text> | ||
| 45 | + <text x="1025.0" y="206.0" text-anchor="middle" font-size="11.5" fill="#01579B">Mellum2 12B</text> | ||
| 46 | + <text x="1025.0" y="223.0" text-anchor="middle" font-size="11.5" fill="#01579B">bash · files · tests</text> | ||
| 47 | + <g filter="url(#shadow)"><rect x="780" y="290" width="230" height="110" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | ||
| 48 | + <text x="895.0" y="325.0" text-anchor="middle" font-size="22">🔎</text> | ||
| 49 | + <text x="895.0" y="348.0" text-anchor="middle" font-size="15" font-weight="700" fill="#01579B">3 · Reviewer</text> | ||
| 50 | + <text x="895.0" y="366.0" text-anchor="middle" font-size="11.5" fill="#01579B">Gemma 4 12B</text> | ||
| 51 | + <text x="895.0" y="383.0" text-anchor="middle" font-size="11.5" fill="#01579B">tests · VERDICT</text> | ||
| 52 | + <text x="895" y="450" text-anchor="middle" font-size="12" fill="#455A64" font-style="italic">VERDICT: FAIL → the coder fixes ONCE → the reviewer again</text> | ||
| 53 | + <rect x="1005.0" y="253.0" width="110" height="24" rx="5" fill="#FFFFFF"/> | ||
| 54 | + <text x="1060" y="269.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">brief + report</text> | ||
| 55 | + <g filter="url(#shadow)"><rect x="650" y="550" width="230" height="110" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | ||
| 56 | + <text x="765.0" y="585.0" text-anchor="middle" font-size="22">📘</text> | ||
| 57 | + <text x="765.0" y="608.0" text-anchor="middle" font-size="15" font-weight="700" fill="#01579B">Tutor</text> | ||
| 58 | + <text x="765.0" y="626.0" text-anchor="middle" font-size="11.5" fill="#01579B">Mellum2 12B</text> | ||
| 59 | + <text x="765.0" y="643.0" text-anchor="middle" font-size="11.5" fill="#01579B">mini tutorials · save_answer</text> | ||
| 60 | + <text x="765" y="530" text-anchor="middle" font-size="12.5" fill="#607D8B" font-style="italic" font-weight="700">route B — a question, a lesson</text> | ||
| 61 | + <g filter="url(#shadow)"><rect x="940" y="550" width="230" height="110" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | ||
| 62 | + <text x="1055.0" y="585.0" text-anchor="middle" font-size="22">🔎</text> | ||
| 63 | + <text x="1055.0" y="608.0" text-anchor="middle" font-size="15" font-weight="700" fill="#01579B">Reviewer</text> | ||
| 64 | + <text x="1055.0" y="626.0" text-anchor="middle" font-size="11.5" fill="#01579B">review existing code</text> | ||
| 65 | + <text x="1055.0" y="643.0" text-anchor="middle" font-size="11.5" fill="#01579B">no change</text> | ||
| 66 | + <text x="1055" y="530" text-anchor="middle" font-size="12.5" fill="#607D8B" font-style="italic" font-weight="700">route C — only a review</text> | ||
| 67 | + <g filter="url(#shadow)"><rect x="40" y="440" width="220" height="120" rx="16" fill="url(#gGrey)" stroke="#455A64" stroke-width="2"/></g> | ||
| 68 | + <text x="150.0" y="480.0" text-anchor="middle" font-size="22">💻</text> | ||
| 69 | + <text x="150.0" y="503.0" text-anchor="middle" font-size="15" font-weight="700" fill="#263238">workspace/</text> | ||
| 70 | + <text x="150.0" y="521.0" text-anchor="middle" font-size="11.5" fill="#263238">your project</text> | ||
| 71 | + <text x="150.0" y="538.0" text-anchor="middle" font-size="11.5" fill="#263238">a git repo: git diff</text> | ||
| 72 | + <rect x="222.0" y="218.0" width="76" height="40" rx="5" fill="#FFFFFF"/> | ||
| 73 | + <text x="260" y="235" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">request</text> | ||
| 74 | + <text x="260" y="251" text-anchor="middle" font-size="10.5" fill="#78909C">← report</text> | ||
| 75 | + <rect x="570.0" y="168.0" width="30" height="24" rx="5" fill="#FFFFFF"/> | ||
| 76 | + <text x="585" y="184.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">A</text> | ||
| 77 | + <rect x="410.0" y="428.0" width="30" height="24" rx="5" fill="#FFFFFF"/> | ||
| 78 | + <text x="425" y="444.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">B</text> | ||
| 79 | + <rect x="815.0" y="678.0" width="30" height="24" rx="5" fill="#FFFFFF"/> | ||
| 80 | + <text x="830" y="694.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">C</text> | ||
| 81 | + <rect x="255.0" y="482.0" width="150" height="24" rx="5" fill="#FFFFFF"/> | ||
| 82 | + <text x="330" y="498.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">reads · changes · tests</text> | ||
| 83 | +</svg> | ||
added
dev.team/dev-team-memory.drawio +26 -0 | new file mode 100644 | ||
| @@ -0,0 +1,26 @@ | ||
| 1 | +<mxfile host="app.diagrams.net"> | |
| 2 | + <diagram id="dev-team-memory" name="dev.team — one model in memory at a time"> | |
| 3 | + <mxGraphModel dx="1200" dy="600" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1200" pageHeight="600" background="#F5F7FC" math="0" shadow="0"> | |
| 4 | + <root> | |
| 5 | + <mxCell id="0"/> | |
| 6 | + <mxCell id="1" parent="0"/> | |
| 7 | + <mxCell id="title" value="<b style="font-size:25px;color:#1A237E">dev.team — one model in memory at a time</b><br><i style="font-size:14px;color:#546E7A">two hooks of the coordinator unload a model at each hand-off; llmman reloads on the next request</i>" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="150.0" y="12" width="900" height="56" as="geometry"/></mxCell> | |
| 8 | + <mxCell id="c7" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="270" y="205" as="sourcePoint"/><mxPoint x="400" y="205" as="targetPoint"/></mxGeometry></mxCell> | |
| 9 | + <mxCell id="c9" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="660" y="205" as="sourcePoint"/><mxPoint x="790" y="205" as="targetPoint"/></mxGeometry></mxCell> | |
| 10 | + <mxCell id="c11" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="975" y="270" as="sourcePoint"/><mxPoint x="975" y="380" as="targetPoint"/></mxGeometry></mxCell> | |
| 11 | + <mxCell id="c13" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="790" y="445" as="sourcePoint"/><mxPoint x="270" y="445" as="targetPoint"/></mxGeometry></mxCell> | |
| 12 | + <mxCell id="c1" value="🔀<br><b style="font-size:16px">Coordinator</b><br><span style="font-size:11.5px;font-weight:normal">Qwen3.5-4B · 3.4 GB<br>decides: ask_agent coder</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#F3E5F5;gradientColor=#E1BEE7;strokeColor=#6A1B9A;strokeWidth=3;shadow=1;fontSize=20;fontColor=#4A148C;" vertex="1" parent="1"><mxGeometry x="40" y="140" width="230" height="130" as="geometry"/></mxCell> | |
| 13 | + <mxCell id="c2" value="<b>★ asks</b>" style="rounded=1;arcSize=50;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=11;" vertex="1" parent="1"><mxGeometry x="222.8" y="128" width="57.2" height="24" as="geometry"/></mxCell> | |
| 14 | + <mxCell id="c3" value="⚙️<br><b style="font-size:16px">preAsk hook</b><br><span style="font-size:11.5px;font-weight:normal">node hooks/unload.js self<br>unloads the 4B<br>before the agent starts</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#FFFDE7;gradientColor=#FFF9C4;strokeColor=#F9A825;strokeWidth=2;shadow=1;fontSize=20;fontColor=#E65100;" vertex="1" parent="1"><mxGeometry x="400" y="140" width="260" height="130" as="geometry"/></mxCell> | |
| 15 | + <mxCell id="c4" value="🛠️<br><b style="font-size:16px">Team member</b><br><span style="font-size:11.5px;font-weight:normal">Mellum2 12B · 8.1 GB or Gemma 4 12B · 7.3 GB<br>loaded alone · does the work</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="790" y="140" width="370" height="130" as="geometry"/></mxCell> | |
| 16 | + <mxCell id="c5" value="⚙️<br><b style="font-size:16px">postAsk hook</b><br><span style="font-size:11.5px;font-weight:normal">node hooks/unload.js asked<br>unloads the 12B<br>before the coordinator reads</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#FFFDE7;gradientColor=#FFF9C4;strokeColor=#F9A825;strokeWidth=2;shadow=1;fontSize=20;fontColor=#E65100;" vertex="1" parent="1"><mxGeometry x="790" y="380" width="370" height="130" as="geometry"/></mxCell> | |
| 17 | + <mxCell id="c6" value="🔀<br><b style="font-size:16px">Coordinator</b><br><span style="font-size:11.5px;font-weight:normal">the 4B reloads alone<br>reads the answer · next step</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#F3E5F5;gradientColor=#E1BEE7;strokeColor=#6A1B9A;strokeWidth=3;shadow=1;fontSize=20;fontColor=#4A148C;" vertex="1" parent="1"><mxGeometry x="40" y="380" width="230" height="130" as="geometry"/></mxCell> | |
| 18 | + <mxCell id="c8" value="<b style="font-size:12.5px;color:#263238">ask_agent</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="295.0" y="221.0" width="80" height="24" as="geometry"/></mxCell> | |
| 19 | + <mxCell id="c10" value="<b style="font-size:12.5px;color:#263238">keep_alive: 0</b><br><span style="font-size:10.5px;color:#78909C">POST /api/generate</span>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="670.0" y="185.0" width="110" height="40" as="geometry"/></mxCell> | |
| 20 | + <mxCell id="c12" value="<b style="font-size:12.5px;color:#263238">answer</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="975.0" y="313.0" width="70" height="24" as="geometry"/></mxCell> | |
| 21 | + <mxCell id="c14" value="<b style="font-size:12.5px;color:#263238">answer, then</b><br><span style="font-size:10.5px;color:#78909C">the 4B reloads</span>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="470.0" y="425.0" width="120" height="40" as="geometry"/></mxCell> | |
| 22 | + <mxCell id="c15" value="Peak: one 12B model (~8 GB + KV cache at 32k) — reformulator &amp; reviewer share Gemma, coder &amp; tutor share Mellum2." style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;fontSize=12;fontColor=#455A64;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="179.64" y="548" width="840.72" height="18" as="geometry"/></mxCell> | |
| 23 | + </root> | |
| 24 | + </mxGraphModel> | |
| 25 | + </diagram> | |
| 26 | +</mxfile> | |
| new file mode 100644 | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | +<mxfile host="app.diagrams.net"> | ||
| 2 | + <diagram id="dev-team-memory" name="dev.team — one model in memory at a time"> | ||
| 3 | + <mxGraphModel dx="1200" dy="600" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1200" pageHeight="600" background="#F5F7FC" math="0" shadow="0"> | ||
| 4 | + <root> | ||
| 5 | + <mxCell id="0"/> | ||
| 6 | + <mxCell id="1" parent="0"/> | ||
| 7 | + <mxCell id="title" value="<b style="font-size:25px;color:#1A237E">dev.team — one model in memory at a time</b><br><i style="font-size:14px;color:#546E7A">two hooks of the coordinator unload a model at each hand-off; llmman reloads on the next request</i>" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="150.0" y="12" width="900" height="56" as="geometry"/></mxCell> | ||
| 8 | + <mxCell id="c7" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="270" y="205" as="sourcePoint"/><mxPoint x="400" y="205" as="targetPoint"/></mxGeometry></mxCell> | ||
| 9 | + <mxCell id="c9" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="660" y="205" as="sourcePoint"/><mxPoint x="790" y="205" as="targetPoint"/></mxGeometry></mxCell> | ||
| 10 | + <mxCell id="c11" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="975" y="270" as="sourcePoint"/><mxPoint x="975" y="380" as="targetPoint"/></mxGeometry></mxCell> | ||
| 11 | + <mxCell id="c13" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="790" y="445" as="sourcePoint"/><mxPoint x="270" y="445" as="targetPoint"/></mxGeometry></mxCell> | ||
| 12 | + <mxCell id="c1" value="🔀<br><b style="font-size:16px">Coordinator</b><br><span style="font-size:11.5px;font-weight:normal">Qwen3.5-4B · 3.4 GB<br>decides: ask_agent coder</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#F3E5F5;gradientColor=#E1BEE7;strokeColor=#6A1B9A;strokeWidth=3;shadow=1;fontSize=20;fontColor=#4A148C;" vertex="1" parent="1"><mxGeometry x="40" y="140" width="230" height="130" as="geometry"/></mxCell> | ||
| 13 | + <mxCell id="c2" value="<b>★ asks</b>" style="rounded=1;arcSize=50;html=1;fillColor=#6A1B9A;strokeColor=none;fontColor=#FFFFFF;fontSize=11;" vertex="1" parent="1"><mxGeometry x="222.8" y="128" width="57.2" height="24" as="geometry"/></mxCell> | ||
| 14 | + <mxCell id="c3" value="⚙️<br><b style="font-size:16px">preAsk hook</b><br><span style="font-size:11.5px;font-weight:normal">node hooks/unload.js self<br>unloads the 4B<br>before the agent starts</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#FFFDE7;gradientColor=#FFF9C4;strokeColor=#F9A825;strokeWidth=2;shadow=1;fontSize=20;fontColor=#E65100;" vertex="1" parent="1"><mxGeometry x="400" y="140" width="260" height="130" as="geometry"/></mxCell> | ||
| 15 | + <mxCell id="c4" value="🛠️<br><b style="font-size:16px">Team member</b><br><span style="font-size:11.5px;font-weight:normal">Mellum2 12B · 8.1 GB or Gemma 4 12B · 7.3 GB<br>loaded alone · does the work</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="790" y="140" width="370" height="130" as="geometry"/></mxCell> | ||
| 16 | + <mxCell id="c5" value="⚙️<br><b style="font-size:16px">postAsk hook</b><br><span style="font-size:11.5px;font-weight:normal">node hooks/unload.js asked<br>unloads the 12B<br>before the coordinator reads</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#FFFDE7;gradientColor=#FFF9C4;strokeColor=#F9A825;strokeWidth=2;shadow=1;fontSize=20;fontColor=#E65100;" vertex="1" parent="1"><mxGeometry x="790" y="380" width="370" height="130" as="geometry"/></mxCell> | ||
| 17 | + <mxCell id="c6" value="🔀<br><b style="font-size:16px">Coordinator</b><br><span style="font-size:11.5px;font-weight:normal">the 4B reloads alone<br>reads the answer · next step</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#F3E5F5;gradientColor=#E1BEE7;strokeColor=#6A1B9A;strokeWidth=3;shadow=1;fontSize=20;fontColor=#4A148C;" vertex="1" parent="1"><mxGeometry x="40" y="380" width="230" height="130" as="geometry"/></mxCell> | ||
| 18 | + <mxCell id="c8" value="<b style="font-size:12.5px;color:#263238">ask_agent</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="295.0" y="221.0" width="80" height="24" as="geometry"/></mxCell> | ||
| 19 | + <mxCell id="c10" value="<b style="font-size:12.5px;color:#263238">keep_alive: 0</b><br><span style="font-size:10.5px;color:#78909C">POST /api/generate</span>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="670.0" y="185.0" width="110" height="40" as="geometry"/></mxCell> | ||
| 20 | + <mxCell id="c12" value="<b style="font-size:12.5px;color:#263238">answer</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="975.0" y="313.0" width="70" height="24" as="geometry"/></mxCell> | ||
| 21 | + <mxCell id="c14" value="<b style="font-size:12.5px;color:#263238">answer, then</b><br><span style="font-size:10.5px;color:#78909C">the 4B reloads</span>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="470.0" y="425.0" width="120" height="40" as="geometry"/></mxCell> | ||
| 22 | + <mxCell id="c15" value="Peak: one 12B model (~8 GB + KV cache at 32k) — reformulator &amp; reviewer share Gemma, coder &amp; tutor share Mellum2." style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;fontSize=12;fontColor=#455A64;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="179.64" y="548" width="840.72" height="18" as="geometry"/></mxCell> | ||
| 23 | + </root> | ||
| 24 | + </mxGraphModel> | ||
| 25 | + </diagram> | ||
| 26 | +</mxfile> | ||
added
dev.team/dev-team-memory.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/dev.team/dev-team-memory.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/dev.team/dev-team-memory.png differ | Binary files /dev/null and b/dev.team/dev-team-memory.png differ | ||
added
dev.team/dev-team-memory.svg +59 -0 | new file mode 100644 | ||
| @@ -0,0 +1,59 @@ | ||
| 1 | +<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600" viewBox="0 0 1200 600" font-family="DejaVu Sans, Verdana, sans-serif"> | |
| 2 | + <defs> | |
| 3 | + <linearGradient id="gBg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#EEF2FA"/></linearGradient> | |
| 4 | + <linearGradient id="gBlue" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#E3F2FD"/><stop offset="100%" stop-color="#BBDEFB"/></linearGradient> | |
| 5 | + <linearGradient id="gBlue2" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#E1F5FE"/><stop offset="100%" stop-color="#B3E5FC"/></linearGradient> | |
| 6 | + <linearGradient id="gPurple" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#F3E5F5"/><stop offset="100%" stop-color="#E1BEE7"/></linearGradient> | |
| 7 | + <linearGradient id="gYellow" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#FFFDE7"/><stop offset="100%" stop-color="#FFF9C4"/></linearGradient> | |
| 8 | + <linearGradient id="gGrey" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#ECEFF1"/><stop offset="100%" stop-color="#CFD8DC"/></linearGradient> | |
| 9 | + <filter id="shadow" x="-30%" y="-30%" width="160%" height="160%"><feDropShadow dx="2" dy="3" stdDeviation="4" flood-color="#000000" flood-opacity="0.25"/></filter> | |
| 10 | + <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#37474F"/></marker> | |
| 11 | + </defs> | |
| 12 | + <rect x="0" y="0" width="1200" height="600" fill="url(#gBg)"/> | |
| 13 | + <text x="600.0" y="38" text-anchor="middle" font-size="25" font-weight="700" fill="#1A237E">dev.team — one model in memory at a time</text> | |
| 14 | + <text x="600.0" y="61" text-anchor="middle" font-size="14" font-style="italic" fill="#546E7A">two hooks of the coordinator unload a model at each hand-off; llmman reloads on the next request</text> | |
| 15 | + <path d="M270,205 L400,205" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | |
| 16 | + <path d="M660,205 L790,205" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | |
| 17 | + <path d="M975,270 L975,380" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | |
| 18 | + <path d="M790,445 L270,445" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | |
| 19 | + <g filter="url(#shadow)"><rect x="40" y="140" width="230" height="130" rx="16" fill="url(#gPurple)" stroke="#6A1B9A" stroke-width="3"/></g> | |
| 20 | + <text x="155.0" y="185.0" text-anchor="middle" font-size="22">🔀</text> | |
| 21 | + <text x="155.0" y="208.0" text-anchor="middle" font-size="16" font-weight="700" fill="#4A148C">Coordinator</text> | |
| 22 | + <text x="155.0" y="226.0" text-anchor="middle" font-size="11.5" fill="#4A148C">Qwen3.5-4B · 3.4 GB</text> | |
| 23 | + <text x="155.0" y="243.0" text-anchor="middle" font-size="11.5" fill="#4A148C">decides: ask_agent coder</text> | |
| 24 | + <rect x="222.8" y="128" width="57.2" height="24" rx="12" fill="#6A1B9A"/> | |
| 25 | + <text x="251.4" y="144" text-anchor="middle" font-size="11.5" font-weight="700" fill="#FFFFFF">★ asks</text> | |
| 26 | + <g filter="url(#shadow)"><rect x="400" y="140" width="260" height="130" rx="16" fill="url(#gYellow)" stroke="#F9A825" stroke-width="2"/></g> | |
| 27 | + <text x="530.0" y="176.5" text-anchor="middle" font-size="22">⚙️</text> | |
| 28 | + <text x="530.0" y="199.5" text-anchor="middle" font-size="16" font-weight="700" fill="#E65100">preAsk hook</text> | |
| 29 | + <text x="530.0" y="217.5" text-anchor="middle" font-size="11.5" fill="#E65100">node hooks/unload.js self</text> | |
| 30 | + <text x="530.0" y="234.5" text-anchor="middle" font-size="11.5" fill="#E65100">unloads the 4B</text> | |
| 31 | + <text x="530.0" y="251.5" text-anchor="middle" font-size="11.5" fill="#E65100">before the agent starts</text> | |
| 32 | + <g filter="url(#shadow)"><rect x="790" y="140" width="370" height="130" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | |
| 33 | + <text x="975.0" y="185.0" text-anchor="middle" font-size="22">🛠️</text> | |
| 34 | + <text x="975.0" y="208.0" text-anchor="middle" font-size="16" font-weight="700" fill="#01579B">Team member</text> | |
| 35 | + <text x="975.0" y="226.0" text-anchor="middle" font-size="11.5" fill="#01579B">Mellum2 12B · 8.1 GB or Gemma 4 12B · 7.3 GB</text> | |
| 36 | + <text x="975.0" y="243.0" text-anchor="middle" font-size="11.5" fill="#01579B">loaded alone · does the work</text> | |
| 37 | + <g filter="url(#shadow)"><rect x="790" y="380" width="370" height="130" rx="16" fill="url(#gYellow)" stroke="#F9A825" stroke-width="2"/></g> | |
| 38 | + <text x="975.0" y="416.5" text-anchor="middle" font-size="22">⚙️</text> | |
| 39 | + <text x="975.0" y="439.5" text-anchor="middle" font-size="16" font-weight="700" fill="#E65100">postAsk hook</text> | |
| 40 | + <text x="975.0" y="457.5" text-anchor="middle" font-size="11.5" fill="#E65100">node hooks/unload.js asked</text> | |
| 41 | + <text x="975.0" y="474.5" text-anchor="middle" font-size="11.5" fill="#E65100">unloads the 12B</text> | |
| 42 | + <text x="975.0" y="491.5" text-anchor="middle" font-size="11.5" fill="#E65100">before the coordinator reads</text> | |
| 43 | + <g filter="url(#shadow)"><rect x="40" y="380" width="230" height="130" rx="16" fill="url(#gPurple)" stroke="#6A1B9A" stroke-width="3"/></g> | |
| 44 | + <text x="155.0" y="425.0" text-anchor="middle" font-size="22">🔀</text> | |
| 45 | + <text x="155.0" y="448.0" text-anchor="middle" font-size="16" font-weight="700" fill="#4A148C">Coordinator</text> | |
| 46 | + <text x="155.0" y="466.0" text-anchor="middle" font-size="11.5" fill="#4A148C">the 4B reloads alone</text> | |
| 47 | + <text x="155.0" y="483.0" text-anchor="middle" font-size="11.5" fill="#4A148C">reads the answer · next step</text> | |
| 48 | + <rect x="295.0" y="221.0" width="80" height="24" rx="5" fill="#FFFFFF"/> | |
| 49 | + <text x="335" y="237.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">ask_agent</text> | |
| 50 | + <rect x="670.0" y="185.0" width="110" height="40" rx="5" fill="#FFFFFF"/> | |
| 51 | + <text x="725" y="202" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">keep_alive: 0</text> | |
| 52 | + <text x="725" y="218" text-anchor="middle" font-size="10.5" fill="#78909C">POST /api/generate</text> | |
| 53 | + <rect x="975.0" y="313.0" width="70" height="24" rx="5" fill="#FFFFFF"/> | |
| 54 | + <text x="1010" y="329.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">answer</text> | |
| 55 | + <rect x="470.0" y="425.0" width="120" height="40" rx="5" fill="#FFFFFF"/> | |
| 56 | + <text x="530" y="442" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">answer, then</text> | |
| 57 | + <text x="530" y="458" text-anchor="middle" font-size="10.5" fill="#78909C">the 4B reloads</text> | |
| 58 | + <text x="600" y="560" text-anchor="middle" font-size="12" fill="#455A64" font-style="italic">Peak: one 12B model (~8 GB + KV cache at 32k) — reformulator & reviewer share Gemma, coder & tutor share Mellum2.</text> | |
| 59 | +</svg> | |
| new file mode 100644 | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | +<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600" viewBox="0 0 1200 600" font-family="DejaVu Sans, Verdana, sans-serif"> | ||
| 2 | + <defs> | ||
| 3 | + <linearGradient id="gBg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#EEF2FA"/></linearGradient> | ||
| 4 | + <linearGradient id="gBlue" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#E3F2FD"/><stop offset="100%" stop-color="#BBDEFB"/></linearGradient> | ||
| 5 | + <linearGradient id="gBlue2" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#E1F5FE"/><stop offset="100%" stop-color="#B3E5FC"/></linearGradient> | ||
| 6 | + <linearGradient id="gPurple" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#F3E5F5"/><stop offset="100%" stop-color="#E1BEE7"/></linearGradient> | ||
| 7 | + <linearGradient id="gYellow" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#FFFDE7"/><stop offset="100%" stop-color="#FFF9C4"/></linearGradient> | ||
| 8 | + <linearGradient id="gGrey" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#ECEFF1"/><stop offset="100%" stop-color="#CFD8DC"/></linearGradient> | ||
| 9 | + <filter id="shadow" x="-30%" y="-30%" width="160%" height="160%"><feDropShadow dx="2" dy="3" stdDeviation="4" flood-color="#000000" flood-opacity="0.25"/></filter> | ||
| 10 | + <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#37474F"/></marker> | ||
| 11 | + </defs> | ||
| 12 | + <rect x="0" y="0" width="1200" height="600" fill="url(#gBg)"/> | ||
| 13 | + <text x="600.0" y="38" text-anchor="middle" font-size="25" font-weight="700" fill="#1A237E">dev.team — one model in memory at a time</text> | ||
| 14 | + <text x="600.0" y="61" text-anchor="middle" font-size="14" font-style="italic" fill="#546E7A">two hooks of the coordinator unload a model at each hand-off; llmman reloads on the next request</text> | ||
| 15 | + <path d="M270,205 L400,205" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | ||
| 16 | + <path d="M660,205 L790,205" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | ||
| 17 | + <path d="M975,270 L975,380" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | ||
| 18 | + <path d="M790,445 L270,445" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | ||
| 19 | + <g filter="url(#shadow)"><rect x="40" y="140" width="230" height="130" rx="16" fill="url(#gPurple)" stroke="#6A1B9A" stroke-width="3"/></g> | ||
| 20 | + <text x="155.0" y="185.0" text-anchor="middle" font-size="22">🔀</text> | ||
| 21 | + <text x="155.0" y="208.0" text-anchor="middle" font-size="16" font-weight="700" fill="#4A148C">Coordinator</text> | ||
| 22 | + <text x="155.0" y="226.0" text-anchor="middle" font-size="11.5" fill="#4A148C">Qwen3.5-4B · 3.4 GB</text> | ||
| 23 | + <text x="155.0" y="243.0" text-anchor="middle" font-size="11.5" fill="#4A148C">decides: ask_agent coder</text> | ||
| 24 | + <rect x="222.8" y="128" width="57.2" height="24" rx="12" fill="#6A1B9A"/> | ||
| 25 | + <text x="251.4" y="144" text-anchor="middle" font-size="11.5" font-weight="700" fill="#FFFFFF">★ asks</text> | ||
| 26 | + <g filter="url(#shadow)"><rect x="400" y="140" width="260" height="130" rx="16" fill="url(#gYellow)" stroke="#F9A825" stroke-width="2"/></g> | ||
| 27 | + <text x="530.0" y="176.5" text-anchor="middle" font-size="22">⚙️</text> | ||
| 28 | + <text x="530.0" y="199.5" text-anchor="middle" font-size="16" font-weight="700" fill="#E65100">preAsk hook</text> | ||
| 29 | + <text x="530.0" y="217.5" text-anchor="middle" font-size="11.5" fill="#E65100">node hooks/unload.js self</text> | ||
| 30 | + <text x="530.0" y="234.5" text-anchor="middle" font-size="11.5" fill="#E65100">unloads the 4B</text> | ||
| 31 | + <text x="530.0" y="251.5" text-anchor="middle" font-size="11.5" fill="#E65100">before the agent starts</text> | ||
| 32 | + <g filter="url(#shadow)"><rect x="790" y="140" width="370" height="130" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | ||
| 33 | + <text x="975.0" y="185.0" text-anchor="middle" font-size="22">🛠️</text> | ||
| 34 | + <text x="975.0" y="208.0" text-anchor="middle" font-size="16" font-weight="700" fill="#01579B">Team member</text> | ||
| 35 | + <text x="975.0" y="226.0" text-anchor="middle" font-size="11.5" fill="#01579B">Mellum2 12B · 8.1 GB or Gemma 4 12B · 7.3 GB</text> | ||
| 36 | + <text x="975.0" y="243.0" text-anchor="middle" font-size="11.5" fill="#01579B">loaded alone · does the work</text> | ||
| 37 | + <g filter="url(#shadow)"><rect x="790" y="380" width="370" height="130" rx="16" fill="url(#gYellow)" stroke="#F9A825" stroke-width="2"/></g> | ||
| 38 | + <text x="975.0" y="416.5" text-anchor="middle" font-size="22">⚙️</text> | ||
| 39 | + <text x="975.0" y="439.5" text-anchor="middle" font-size="16" font-weight="700" fill="#E65100">postAsk hook</text> | ||
| 40 | + <text x="975.0" y="457.5" text-anchor="middle" font-size="11.5" fill="#E65100">node hooks/unload.js asked</text> | ||
| 41 | + <text x="975.0" y="474.5" text-anchor="middle" font-size="11.5" fill="#E65100">unloads the 12B</text> | ||
| 42 | + <text x="975.0" y="491.5" text-anchor="middle" font-size="11.5" fill="#E65100">before the coordinator reads</text> | ||
| 43 | + <g filter="url(#shadow)"><rect x="40" y="380" width="230" height="130" rx="16" fill="url(#gPurple)" stroke="#6A1B9A" stroke-width="3"/></g> | ||
| 44 | + <text x="155.0" y="425.0" text-anchor="middle" font-size="22">🔀</text> | ||
| 45 | + <text x="155.0" y="448.0" text-anchor="middle" font-size="16" font-weight="700" fill="#4A148C">Coordinator</text> | ||
| 46 | + <text x="155.0" y="466.0" text-anchor="middle" font-size="11.5" fill="#4A148C">the 4B reloads alone</text> | ||
| 47 | + <text x="155.0" y="483.0" text-anchor="middle" font-size="11.5" fill="#4A148C">reads the answer · next step</text> | ||
| 48 | + <rect x="295.0" y="221.0" width="80" height="24" rx="5" fill="#FFFFFF"/> | ||
| 49 | + <text x="335" y="237.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">ask_agent</text> | ||
| 50 | + <rect x="670.0" y="185.0" width="110" height="40" rx="5" fill="#FFFFFF"/> | ||
| 51 | + <text x="725" y="202" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">keep_alive: 0</text> | ||
| 52 | + <text x="725" y="218" text-anchor="middle" font-size="10.5" fill="#78909C">POST /api/generate</text> | ||
| 53 | + <rect x="975.0" y="313.0" width="70" height="24" rx="5" fill="#FFFFFF"/> | ||
| 54 | + <text x="1010" y="329.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">answer</text> | ||
| 55 | + <rect x="470.0" y="425.0" width="120" height="40" rx="5" fill="#FFFFFF"/> | ||
| 56 | + <text x="530" y="442" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">answer, then</text> | ||
| 57 | + <text x="530" y="458" text-anchor="middle" font-size="10.5" fill="#78909C">the 4B reloads</text> | ||
| 58 | + <text x="600" y="560" text-anchor="middle" font-size="12" fill="#455A64" font-style="italic">Peak: one 12B model (~8 GB + KV cache at 32k) — reformulator & reviewer share Gemma, coder & tutor share Mellum2.</text> | ||
| 59 | +</svg> | ||
added
dev.team/dev-team-sandbox.drawio +24 -0 | new file mode 100644 | ||
| @@ -0,0 +1,24 @@ | ||
| 1 | +<mxfile host="app.diagrams.net"> | |
| 2 | + <diagram id="dev-team-sandbox" name="dev.team — the agents are read-only in the sandbox"> | |
| 3 | + <mxGraphModel dx="1200" dy="640" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1200" pageHeight="640" background="#F5F7FC" math="0" shadow="0"> | |
| 4 | + <root> | |
| 5 | + <mxCell id="0"/> | |
| 6 | + <mxCell id="1" parent="0"/> | |
| 7 | + <mxCell id="title" value="<b style="font-size:25px;color:#1A237E">dev.team — the agents are read-only in the sandbox</b><br><i style="font-size:14px;color:#546E7A">sbxenv.yaml mounts workspace/ read-write and team/ read-only; the env file itself is never mounted</i>" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="150.0" y="12" width="900" height="56" as="geometry"/></mxCell> | |
| 8 | + <mxCell id="c7" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="340" y="215" as="sourcePoint"/><mxPoint x="420" y="215" as="targetPoint"/></mxGeometry></mxCell> | |
| 9 | + <mxCell id="c9" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="760" y="200" as="sourcePoint"/><mxPoint x="840" y="200" as="targetPoint"/></mxGeometry></mxCell> | |
| 10 | + <mxCell id="c11" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="610" y="290" as="sourcePoint"/><mxPoint x="840" y="435" as="targetPoint"/><Array as="points"><mxPoint x="610" y="435"/></Array></mxGeometry></mxCell> | |
| 11 | + <mxCell id="c1" value="💻<br><b style="font-size:16px">dev.team/ on the host</b><br><span style="font-size:11.5px;font-weight:normal">sbxenv.yaml · start-zed.sh · stop-zed.sh<br>README · diagrams<br>never mounted</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E3F2FD;gradientColor=#BBDEFB;strokeColor=#1565C0;strokeWidth=2;shadow=1;fontSize=20;fontColor=#0D47A1;" vertex="1" parent="1"><mxGeometry x="40" y="140" width="300" height="150" as="geometry"/></mxCell> | |
| 12 | + <mxCell id="c2" value="<i><b>sandbox zed-dev-team (sbx env create)</b></i>" style="rounded=1;arcSize=3;html=1;dashed=1;dashPattern=7 5;fillColor=#FAFAFA;strokeColor=#90A4AE;strokeWidth=2;verticalAlign=top;fontColor=#607D8B;fontSize=13;" vertex="1" parent="1"><mxGeometry x="420" y="90" width="750" height="470" as="geometry"/></mxCell> | |
| 13 | + <mxCell id="c3" value="🔀<br><b style="font-size:16px">mm -acp (Zed) / mm -tui</b><br><span style="font-size:11.5px;font-weight:normal">AGENT_CONFIG =<br>&lt;dev.team&gt;/team/agent.yaml<br>cwd = workspace/</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="460" y="140" width="300" height="150" as="geometry"/></mxCell> | |
| 14 | + <mxCell id="c4" value="🛡️<br><b style="font-size:16px">team/ · read-only</b><br><span style="font-size:11.5px;font-weight:normal">agent*.yaml · hooks/<br>mm reads them<br>nothing can rewrite them</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#FFFDE7;gradientColor=#FFF9C4;strokeColor=#F9A825;strokeWidth=2;shadow=1;fontSize=20;fontColor=#E65100;" vertex="1" parent="1"><mxGeometry x="840" y="140" width="300" height="150" as="geometry"/></mxCell> | |
| 15 | + <mxCell id="c5" value="<b>readOnly: true</b>" style="rounded=1;arcSize=50;html=1;fillColor=#F9A825;strokeColor=none;fontColor=#FFFFFF;fontSize=11;" vertex="1" parent="1"><mxGeometry x="1035.2" y="128" width="114.8" height="24" as="geometry"/></mxCell> | |
| 16 | + <mxCell id="c6" value="🧰<br><b style="font-size:16px">workspace/ · read-write</b><br><span style="font-size:11.5px;font-weight:normal">your project (a git repo)<br>.mm/ sessions and traces<br>Zed opens this folder</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=20;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="840" y="360" width="300" height="150" as="geometry"/></mxCell> | |
| 17 | + <mxCell id="c8" value="<b style="font-size:12.5px;color:#263238">creates</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="345.0" y="231.0" width="70" height="24" as="geometry"/></mxCell> | |
| 18 | + <mxCell id="c10" value="<b style="font-size:12.5px;color:#263238">reads</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="770.0" y="216.0" width="60" height="24" as="geometry"/></mxCell> | |
| 19 | + <mxCell id="c12" value="<b style="font-size:12.5px;color:#263238">reads · writes · runs</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="625.0" y="423.0" width="150" height="24" as="geometry"/></mxCell> | |
| 20 | + <mxCell id="c13" value="start-zed.sh: sbx env create --env-arg DEV_TEAM_DIR=$PWD, then zed --new ssh://zed-dev-team.sbx$PWD/workspace" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;fontSize=12;fontColor=#455A64;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="199.51999999999998" y="588" width="810.96" height="18" as="geometry"/></mxCell> | |
| 21 | + </root> | |
| 22 | + </mxGraphModel> | |
| 23 | + </diagram> | |
| 24 | +</mxfile> | |
| new file mode 100644 | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | +<mxfile host="app.diagrams.net"> | ||
| 2 | + <diagram id="dev-team-sandbox" name="dev.team — the agents are read-only in the sandbox"> | ||
| 3 | + <mxGraphModel dx="1200" dy="640" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1200" pageHeight="640" background="#F5F7FC" math="0" shadow="0"> | ||
| 4 | + <root> | ||
| 5 | + <mxCell id="0"/> | ||
| 6 | + <mxCell id="1" parent="0"/> | ||
| 7 | + <mxCell id="title" value="<b style="font-size:25px;color:#1A237E">dev.team — the agents are read-only in the sandbox</b><br><i style="font-size:14px;color:#546E7A">sbxenv.yaml mounts workspace/ read-write and team/ read-only; the env file itself is never mounted</i>" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;" vertex="1" parent="1"><mxGeometry x="150.0" y="12" width="900" height="56" as="geometry"/></mxCell> | ||
| 8 | + <mxCell id="c7" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="340" y="215" as="sourcePoint"/><mxPoint x="420" y="215" as="targetPoint"/></mxGeometry></mxCell> | ||
| 9 | + <mxCell id="c9" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="760" y="200" as="sourcePoint"/><mxPoint x="840" y="200" as="targetPoint"/></mxGeometry></mxCell> | ||
| 10 | + <mxCell id="c11" value="" style="edgeStyle=none;rounded=0;html=1;strokeColor=#37474F;strokeWidth=2;endArrow=block;endFill=1;startArrow=none;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="610" y="290" as="sourcePoint"/><mxPoint x="840" y="435" as="targetPoint"/><Array as="points"><mxPoint x="610" y="435"/></Array></mxGeometry></mxCell> | ||
| 11 | + <mxCell id="c1" value="💻<br><b style="font-size:16px">dev.team/ on the host</b><br><span style="font-size:11.5px;font-weight:normal">sbxenv.yaml · start-zed.sh · stop-zed.sh<br>README · diagrams<br>never mounted</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E3F2FD;gradientColor=#BBDEFB;strokeColor=#1565C0;strokeWidth=2;shadow=1;fontSize=20;fontColor=#0D47A1;" vertex="1" parent="1"><mxGeometry x="40" y="140" width="300" height="150" as="geometry"/></mxCell> | ||
| 12 | + <mxCell id="c2" value="<i><b>sandbox zed-dev-team (sbx env create)</b></i>" style="rounded=1;arcSize=3;html=1;dashed=1;dashPattern=7 5;fillColor=#FAFAFA;strokeColor=#90A4AE;strokeWidth=2;verticalAlign=top;fontColor=#607D8B;fontSize=13;" vertex="1" parent="1"><mxGeometry x="420" y="90" width="750" height="470" as="geometry"/></mxCell> | ||
| 13 | + <mxCell id="c3" value="🔀<br><b style="font-size:16px">mm -acp (Zed) / mm -tui</b><br><span style="font-size:11.5px;font-weight:normal">AGENT_CONFIG =<br>&lt;dev.team&gt;/team/agent.yaml<br>cwd = workspace/</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#E1F5FE;gradientColor=#B3E5FC;strokeColor=#0277BD;strokeWidth=2;shadow=1;fontSize=20;fontColor=#01579B;" vertex="1" parent="1"><mxGeometry x="460" y="140" width="300" height="150" as="geometry"/></mxCell> | ||
| 14 | + <mxCell id="c4" value="🛡️<br><b style="font-size:16px">team/ · read-only</b><br><span style="font-size:11.5px;font-weight:normal">agent*.yaml · hooks/<br>mm reads them<br>nothing can rewrite them</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#FFFDE7;gradientColor=#FFF9C4;strokeColor=#F9A825;strokeWidth=2;shadow=1;fontSize=20;fontColor=#E65100;" vertex="1" parent="1"><mxGeometry x="840" y="140" width="300" height="150" as="geometry"/></mxCell> | ||
| 15 | + <mxCell id="c5" value="<b>readOnly: true</b>" style="rounded=1;arcSize=50;html=1;fillColor=#F9A825;strokeColor=none;fontColor=#FFFFFF;fontSize=11;" vertex="1" parent="1"><mxGeometry x="1035.2" y="128" width="114.8" height="24" as="geometry"/></mxCell> | ||
| 16 | + <mxCell id="c6" value="🧰<br><b style="font-size:16px">workspace/ · read-write</b><br><span style="font-size:11.5px;font-weight:normal">your project (a git repo)<br>.mm/ sessions and traces<br>Zed opens this folder</span>" style="rounded=1;arcSize=14;whiteSpace=wrap;html=1;fillColor=#ECEFF1;gradientColor=#CFD8DC;strokeColor=#455A64;strokeWidth=2;shadow=1;fontSize=20;fontColor=#263238;" vertex="1" parent="1"><mxGeometry x="840" y="360" width="300" height="150" as="geometry"/></mxCell> | ||
| 17 | + <mxCell id="c8" value="<b style="font-size:12.5px;color:#263238">creates</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="345.0" y="231.0" width="70" height="24" as="geometry"/></mxCell> | ||
| 18 | + <mxCell id="c10" value="<b style="font-size:12.5px;color:#263238">reads</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="770.0" y="216.0" width="60" height="24" as="geometry"/></mxCell> | ||
| 19 | + <mxCell id="c12" value="<b style="font-size:12.5px;color:#263238">reads · writes · runs</b>" style="text;html=1;align=center;verticalAlign=middle;fillColor=#FFFFFF;strokeColor=none;rounded=1;" vertex="1" parent="1"><mxGeometry x="625.0" y="423.0" width="150" height="24" as="geometry"/></mxCell> | ||
| 20 | + <mxCell id="c13" value="start-zed.sh: sbx env create --env-arg DEV_TEAM_DIR=$PWD, then zed --new ssh://zed-dev-team.sbx$PWD/workspace" style="text;html=1;align=center;verticalAlign=middle;strokeColor=none;fillColor=none;fontSize=12;fontColor=#455A64;fontStyle=2;" vertex="1" parent="1"><mxGeometry x="199.51999999999998" y="588" width="810.96" height="18" as="geometry"/></mxCell> | ||
| 21 | + </root> | ||
| 22 | + </mxGraphModel> | ||
| 23 | + </diagram> | ||
| 24 | +</mxfile> | ||
added
dev.team/dev-team-sandbox.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/dev.team/dev-team-sandbox.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/dev.team/dev-team-sandbox.png differ | Binary files /dev/null and b/dev.team/dev-team-sandbox.png differ | ||
added
dev.team/dev-team-sandbox.svg +53 -0 | new file mode 100644 | ||
| @@ -0,0 +1,53 @@ | ||
| 1 | +<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="640" viewBox="0 0 1200 640" font-family="DejaVu Sans, Verdana, sans-serif"> | |
| 2 | + <defs> | |
| 3 | + <linearGradient id="gBg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#EEF2FA"/></linearGradient> | |
| 4 | + <linearGradient id="gBlue" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#E3F2FD"/><stop offset="100%" stop-color="#BBDEFB"/></linearGradient> | |
| 5 | + <linearGradient id="gBlue2" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#E1F5FE"/><stop offset="100%" stop-color="#B3E5FC"/></linearGradient> | |
| 6 | + <linearGradient id="gPurple" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#F3E5F5"/><stop offset="100%" stop-color="#E1BEE7"/></linearGradient> | |
| 7 | + <linearGradient id="gYellow" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#FFFDE7"/><stop offset="100%" stop-color="#FFF9C4"/></linearGradient> | |
| 8 | + <linearGradient id="gGrey" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#ECEFF1"/><stop offset="100%" stop-color="#CFD8DC"/></linearGradient> | |
| 9 | + <filter id="shadow" x="-30%" y="-30%" width="160%" height="160%"><feDropShadow dx="2" dy="3" stdDeviation="4" flood-color="#000000" flood-opacity="0.25"/></filter> | |
| 10 | + <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#37474F"/></marker> | |
| 11 | + </defs> | |
| 12 | + <rect x="0" y="0" width="1200" height="640" fill="url(#gBg)"/> | |
| 13 | + <text x="600.0" y="38" text-anchor="middle" font-size="25" font-weight="700" fill="#1A237E">dev.team — the agents are read-only in the sandbox</text> | |
| 14 | + <text x="600.0" y="61" text-anchor="middle" font-size="14" font-style="italic" fill="#546E7A">sbxenv.yaml mounts workspace/ read-write and team/ read-only; the env file itself is never mounted</text> | |
| 15 | + <path d="M340,215 L420,215" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | |
| 16 | + <path d="M760,200 L840,200" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | |
| 17 | + <path d="M610,290 L610,435 L840,435" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | |
| 18 | + <g filter="url(#shadow)"><rect x="40" y="140" width="300" height="150" rx="16" fill="url(#gBlue)" stroke="#1565C0" stroke-width="2"/></g> | |
| 19 | + <text x="190.0" y="186.5" text-anchor="middle" font-size="22">💻</text> | |
| 20 | + <text x="190.0" y="209.5" text-anchor="middle" font-size="16" font-weight="700" fill="#0D47A1">dev.team/ on the host</text> | |
| 21 | + <text x="190.0" y="227.5" text-anchor="middle" font-size="11.5" fill="#0D47A1">sbxenv.yaml · start-zed.sh · stop-zed.sh</text> | |
| 22 | + <text x="190.0" y="244.5" text-anchor="middle" font-size="11.5" fill="#0D47A1">README · diagrams</text> | |
| 23 | + <text x="190.0" y="261.5" text-anchor="middle" font-size="11.5" fill="#0D47A1">never mounted</text> | |
| 24 | + <rect x="420" y="90" width="750" height="470" rx="10" fill="#FAFAFA" fill-opacity="0.7" stroke="#90A4AE" stroke-width="2" stroke-dasharray="7,5"/> | |
| 25 | + <text x="795.0" y="112" text-anchor="middle" font-size="13" font-style="italic" font-weight="700" fill="#607D8B">sandbox zed-dev-team (sbx env create)</text> | |
| 26 | + <g filter="url(#shadow)"><rect x="460" y="140" width="300" height="150" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | |
| 27 | + <text x="610.0" y="186.5" text-anchor="middle" font-size="22">🔀</text> | |
| 28 | + <text x="610.0" y="209.5" text-anchor="middle" font-size="16" font-weight="700" fill="#01579B">mm -acp (Zed) / mm -tui</text> | |
| 29 | + <text x="610.0" y="227.5" text-anchor="middle" font-size="11.5" fill="#01579B">AGENT_CONFIG =</text> | |
| 30 | + <text x="610.0" y="244.5" text-anchor="middle" font-size="11.5" fill="#01579B"><dev.team>/team/agent.yaml</text> | |
| 31 | + <text x="610.0" y="261.5" text-anchor="middle" font-size="11.5" fill="#01579B">cwd = workspace/</text> | |
| 32 | + <g filter="url(#shadow)"><rect x="840" y="140" width="300" height="150" rx="16" fill="url(#gYellow)" stroke="#F9A825" stroke-width="2"/></g> | |
| 33 | + <text x="990.0" y="186.5" text-anchor="middle" font-size="22">🛡️</text> | |
| 34 | + <text x="990.0" y="209.5" text-anchor="middle" font-size="16" font-weight="700" fill="#E65100">team/ · read-only</text> | |
| 35 | + <text x="990.0" y="227.5" text-anchor="middle" font-size="11.5" fill="#E65100">agent*.yaml · hooks/</text> | |
| 36 | + <text x="990.0" y="244.5" text-anchor="middle" font-size="11.5" fill="#E65100">mm reads them</text> | |
| 37 | + <text x="990.0" y="261.5" text-anchor="middle" font-size="11.5" fill="#E65100">nothing can rewrite them</text> | |
| 38 | + <rect x="1035.2" y="128" width="114.8" height="24" rx="12" fill="#F9A825"/> | |
| 39 | + <text x="1092.6000000000001" y="144" text-anchor="middle" font-size="11.5" font-weight="700" fill="#FFFFFF">readOnly: true</text> | |
| 40 | + <g filter="url(#shadow)"><rect x="840" y="360" width="300" height="150" rx="16" fill="url(#gGrey)" stroke="#455A64" stroke-width="2"/></g> | |
| 41 | + <text x="990.0" y="406.5" text-anchor="middle" font-size="22">🧰</text> | |
| 42 | + <text x="990.0" y="429.5" text-anchor="middle" font-size="16" font-weight="700" fill="#263238">workspace/ · read-write</text> | |
| 43 | + <text x="990.0" y="447.5" text-anchor="middle" font-size="11.5" fill="#263238">your project (a git repo)</text> | |
| 44 | + <text x="990.0" y="464.5" text-anchor="middle" font-size="11.5" fill="#263238">.mm/ sessions and traces</text> | |
| 45 | + <text x="990.0" y="481.5" text-anchor="middle" font-size="11.5" fill="#263238">Zed opens this folder</text> | |
| 46 | + <rect x="345.0" y="231.0" width="70" height="24" rx="5" fill="#FFFFFF"/> | |
| 47 | + <text x="380" y="247.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">creates</text> | |
| 48 | + <rect x="770.0" y="216.0" width="60" height="24" rx="5" fill="#FFFFFF"/> | |
| 49 | + <text x="800" y="232.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">reads</text> | |
| 50 | + <rect x="625.0" y="423.0" width="150" height="24" rx="5" fill="#FFFFFF"/> | |
| 51 | + <text x="700" y="439.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">reads · writes · runs</text> | |
| 52 | + <text x="605" y="600" text-anchor="middle" font-size="12" fill="#455A64" font-style="italic">start-zed.sh: sbx env create --env-arg DEV_TEAM_DIR=$PWD, then zed --new ssh://zed-dev-team.sbx$PWD/workspace</text> | |
| 53 | +</svg> | |
| new file mode 100644 | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | +<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="640" viewBox="0 0 1200 640" font-family="DejaVu Sans, Verdana, sans-serif"> | ||
| 2 | + <defs> | ||
| 3 | + <linearGradient id="gBg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#EEF2FA"/></linearGradient> | ||
| 4 | + <linearGradient id="gBlue" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#E3F2FD"/><stop offset="100%" stop-color="#BBDEFB"/></linearGradient> | ||
| 5 | + <linearGradient id="gBlue2" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#E1F5FE"/><stop offset="100%" stop-color="#B3E5FC"/></linearGradient> | ||
| 6 | + <linearGradient id="gPurple" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#F3E5F5"/><stop offset="100%" stop-color="#E1BEE7"/></linearGradient> | ||
| 7 | + <linearGradient id="gYellow" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#FFFDE7"/><stop offset="100%" stop-color="#FFF9C4"/></linearGradient> | ||
| 8 | + <linearGradient id="gGrey" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#ECEFF1"/><stop offset="100%" stop-color="#CFD8DC"/></linearGradient> | ||
| 9 | + <filter id="shadow" x="-30%" y="-30%" width="160%" height="160%"><feDropShadow dx="2" dy="3" stdDeviation="4" flood-color="#000000" flood-opacity="0.25"/></filter> | ||
| 10 | + <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#37474F"/></marker> | ||
| 11 | + </defs> | ||
| 12 | + <rect x="0" y="0" width="1200" height="640" fill="url(#gBg)"/> | ||
| 13 | + <text x="600.0" y="38" text-anchor="middle" font-size="25" font-weight="700" fill="#1A237E">dev.team — the agents are read-only in the sandbox</text> | ||
| 14 | + <text x="600.0" y="61" text-anchor="middle" font-size="14" font-style="italic" fill="#546E7A">sbxenv.yaml mounts workspace/ read-write and team/ read-only; the env file itself is never mounted</text> | ||
| 15 | + <path d="M340,215 L420,215" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | ||
| 16 | + <path d="M760,200 L840,200" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | ||
| 17 | + <path d="M610,290 L610,435 L840,435" fill="none" stroke="#37474F" stroke-width="2.2" marker-end="url(#arrow)"/> | ||
| 18 | + <g filter="url(#shadow)"><rect x="40" y="140" width="300" height="150" rx="16" fill="url(#gBlue)" stroke="#1565C0" stroke-width="2"/></g> | ||
| 19 | + <text x="190.0" y="186.5" text-anchor="middle" font-size="22">💻</text> | ||
| 20 | + <text x="190.0" y="209.5" text-anchor="middle" font-size="16" font-weight="700" fill="#0D47A1">dev.team/ on the host</text> | ||
| 21 | + <text x="190.0" y="227.5" text-anchor="middle" font-size="11.5" fill="#0D47A1">sbxenv.yaml · start-zed.sh · stop-zed.sh</text> | ||
| 22 | + <text x="190.0" y="244.5" text-anchor="middle" font-size="11.5" fill="#0D47A1">README · diagrams</text> | ||
| 23 | + <text x="190.0" y="261.5" text-anchor="middle" font-size="11.5" fill="#0D47A1">never mounted</text> | ||
| 24 | + <rect x="420" y="90" width="750" height="470" rx="10" fill="#FAFAFA" fill-opacity="0.7" stroke="#90A4AE" stroke-width="2" stroke-dasharray="7,5"/> | ||
| 25 | + <text x="795.0" y="112" text-anchor="middle" font-size="13" font-style="italic" font-weight="700" fill="#607D8B">sandbox zed-dev-team (sbx env create)</text> | ||
| 26 | + <g filter="url(#shadow)"><rect x="460" y="140" width="300" height="150" rx="16" fill="url(#gBlue2)" stroke="#0277BD" stroke-width="2"/></g> | ||
| 27 | + <text x="610.0" y="186.5" text-anchor="middle" font-size="22">🔀</text> | ||
| 28 | + <text x="610.0" y="209.5" text-anchor="middle" font-size="16" font-weight="700" fill="#01579B">mm -acp (Zed) / mm -tui</text> | ||
| 29 | + <text x="610.0" y="227.5" text-anchor="middle" font-size="11.5" fill="#01579B">AGENT_CONFIG =</text> | ||
| 30 | + <text x="610.0" y="244.5" text-anchor="middle" font-size="11.5" fill="#01579B"><dev.team>/team/agent.yaml</text> | ||
| 31 | + <text x="610.0" y="261.5" text-anchor="middle" font-size="11.5" fill="#01579B">cwd = workspace/</text> | ||
| 32 | + <g filter="url(#shadow)"><rect x="840" y="140" width="300" height="150" rx="16" fill="url(#gYellow)" stroke="#F9A825" stroke-width="2"/></g> | ||
| 33 | + <text x="990.0" y="186.5" text-anchor="middle" font-size="22">🛡️</text> | ||
| 34 | + <text x="990.0" y="209.5" text-anchor="middle" font-size="16" font-weight="700" fill="#E65100">team/ · read-only</text> | ||
| 35 | + <text x="990.0" y="227.5" text-anchor="middle" font-size="11.5" fill="#E65100">agent*.yaml · hooks/</text> | ||
| 36 | + <text x="990.0" y="244.5" text-anchor="middle" font-size="11.5" fill="#E65100">mm reads them</text> | ||
| 37 | + <text x="990.0" y="261.5" text-anchor="middle" font-size="11.5" fill="#E65100">nothing can rewrite them</text> | ||
| 38 | + <rect x="1035.2" y="128" width="114.8" height="24" rx="12" fill="#F9A825"/> | ||
| 39 | + <text x="1092.6000000000001" y="144" text-anchor="middle" font-size="11.5" font-weight="700" fill="#FFFFFF">readOnly: true</text> | ||
| 40 | + <g filter="url(#shadow)"><rect x="840" y="360" width="300" height="150" rx="16" fill="url(#gGrey)" stroke="#455A64" stroke-width="2"/></g> | ||
| 41 | + <text x="990.0" y="406.5" text-anchor="middle" font-size="22">🧰</text> | ||
| 42 | + <text x="990.0" y="429.5" text-anchor="middle" font-size="16" font-weight="700" fill="#263238">workspace/ · read-write</text> | ||
| 43 | + <text x="990.0" y="447.5" text-anchor="middle" font-size="11.5" fill="#263238">your project (a git repo)</text> | ||
| 44 | + <text x="990.0" y="464.5" text-anchor="middle" font-size="11.5" fill="#263238">.mm/ sessions and traces</text> | ||
| 45 | + <text x="990.0" y="481.5" text-anchor="middle" font-size="11.5" fill="#263238">Zed opens this folder</text> | ||
| 46 | + <rect x="345.0" y="231.0" width="70" height="24" rx="5" fill="#FFFFFF"/> | ||
| 47 | + <text x="380" y="247.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">creates</text> | ||
| 48 | + <rect x="770.0" y="216.0" width="60" height="24" rx="5" fill="#FFFFFF"/> | ||
| 49 | + <text x="800" y="232.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">reads</text> | ||
| 50 | + <rect x="625.0" y="423.0" width="150" height="24" rx="5" fill="#FFFFFF"/> | ||
| 51 | + <text x="700" y="439.5" text-anchor="middle" font-size="12.5" font-weight="700" fill="#263238">reads · writes · runs</text> | ||
| 52 | + <text x="605" y="600" text-anchor="middle" font-size="12" fill="#455A64" font-style="italic">start-zed.sh: sbx env create --env-arg DEV_TEAM_DIR=$PWD, then zed --new ssh://zed-dev-team.sbx$PWD/workspace</text> | ||
| 53 | +</svg> | ||
added
dev.team/sbxenv.yaml +60 -0 | new file mode 100644 | ||
| @@ -0,0 +1,60 @@ | ||
| 1 | +schemaVersion: "1" | |
| 2 | + | |
| 3 | +# Sandbox name = SSH host (<name>.sbx): letters, digits and hyphens only. | |
| 4 | +name: zed-dev-team | |
| 5 | + | |
| 6 | +agent: zed-ssh-kit | |
| 7 | + | |
| 8 | +kits: | |
| 9 | + - docker.io/k33g/zed-ssh-kit:0.0.8 | |
| 10 | + - docker.io/k33g/mini-me-agent-kit:0.0.8 | |
| 11 | + - docker.io/k33g/nushell-kit:0.0.8 | |
| 12 | + - docker.io/k33g/go-toolchain-kit:0.0.8 | |
| 13 | + - docker.io/k33g/rust-toolchain-kit:0.0.8 | |
| 14 | + | |
| 15 | +# This file and the start / stop scripts stay OUTSIDE every mounted | |
| 16 | +# directory: Docker recommends it, so that an agent cannot rewrite the | |
| 17 | +# commands your host runs (writableEnvFiles is left off). | |
| 18 | +# | |
| 19 | +# dev.team/ | |
| 20 | +# ├── sbxenv.yaml, start-zed.sh, stop-zed.sh, README.* not mounted | |
| 21 | +# ├── team/ the agents (agent*.yaml) and their hooks READ-ONLY | |
| 22 | +# └── workspace/ the code the team works on read-write | |
| 23 | + | |
| 24 | +# The code: playground/, demo/, sessions (.mm/). Zed opens this folder. | |
| 25 | +workspace: ./workspace | |
| 26 | + | |
| 27 | +# The agents: mm reads them, nothing in the sandbox can change them. | |
| 28 | +additionalWorkspaces: | |
| 29 | + - path: ./team | |
| 30 | + readOnly: true | |
| 31 | + | |
| 32 | +# The folder of this file, as the sandbox sees it — start-zed.sh passes it: | |
| 33 | +# sbx env create --force --env-arg DEV_TEAM_DIR="$PWD" | |
| 34 | +args: | |
| 35 | + DEV_TEAM_DIR: | |
| 36 | + required: true | |
| 37 | + | |
| 38 | +env: | |
| 39 | + # mm -acp (Zed) and mm without -config read the coordinator from team/, | |
| 40 | + # not ./agent.yaml: the workspace holds no agent file to rewrite. | |
| 41 | + AGENT_CONFIG: ${{ env.args.DEV_TEAM_DIR }}/team/agent.yaml | |
| 42 | + | |
| 43 | +# Published when the sandbox is created, each to the same port on the host | |
| 44 | +# (loopback, tcp4 by default). A port already taken on the host makes the | |
| 45 | +# creation fail. A change here applies at the next ./start-zed.sh. | |
| 46 | +# Inside the sandbox, a server must listen on 0.0.0.0, not 127.0.0.1. | |
| 47 | +ports: | |
| 48 | + - sandbox: 8080 | |
| 49 | + host: 8080 | |
| 50 | + - sandbox: 6060 | |
| 51 | + host: 6060 | |
| 52 | + - sandbox: 5050 | |
| 53 | + host: 5050 | |
| 54 | + | |
| 55 | +sandboxOptions: | |
| 56 | + pullPolicy: always | |
| 57 | + | |
| 58 | +# sbx setup ssh | |
| 59 | +# ./start-zed.sh (sbx env create … then zed --new ssh://zed-dev-team.sbx<dev.team>/workspace) | |
| 60 | +# ./stop-zed.sh (sbx env rm --force --env-arg DEV_TEAM_DIR="$PWD") | |
| new file mode 100644 | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | +schemaVersion: "1" | ||
| 2 | + | ||
| 3 | +# Sandbox name = SSH host (<name>.sbx): letters, digits and hyphens only. | ||
| 4 | +name: zed-dev-team | ||
| 5 | + | ||
| 6 | +agent: zed-ssh-kit | ||
| 7 | + | ||
| 8 | +kits: | ||
| 9 | + - docker.io/k33g/zed-ssh-kit:0.0.8 | ||
| 10 | + - docker.io/k33g/mini-me-agent-kit:0.0.8 | ||
| 11 | + - docker.io/k33g/nushell-kit:0.0.8 | ||
| 12 | + - docker.io/k33g/go-toolchain-kit:0.0.8 | ||
| 13 | + - docker.io/k33g/rust-toolchain-kit:0.0.8 | ||
| 14 | + | ||
| 15 | +# This file and the start / stop scripts stay OUTSIDE every mounted | ||
| 16 | +# directory: Docker recommends it, so that an agent cannot rewrite the | ||
| 17 | +# commands your host runs (writableEnvFiles is left off). | ||
| 18 | +# | ||
| 19 | +# dev.team/ | ||
| 20 | +# ├── sbxenv.yaml, start-zed.sh, stop-zed.sh, README.* not mounted | ||
| 21 | +# ├── team/ the agents (agent*.yaml) and their hooks READ-ONLY | ||
| 22 | +# └── workspace/ the code the team works on read-write | ||
| 23 | + | ||
| 24 | +# The code: playground/, demo/, sessions (.mm/). Zed opens this folder. | ||
| 25 | +workspace: ./workspace | ||
| 26 | + | ||
| 27 | +# The agents: mm reads them, nothing in the sandbox can change them. | ||
| 28 | +additionalWorkspaces: | ||
| 29 | + - path: ./team | ||
| 30 | + readOnly: true | ||
| 31 | + | ||
| 32 | +# The folder of this file, as the sandbox sees it — start-zed.sh passes it: | ||
| 33 | +# sbx env create --force --env-arg DEV_TEAM_DIR="$PWD" | ||
| 34 | +args: | ||
| 35 | + DEV_TEAM_DIR: | ||
| 36 | + required: true | ||
| 37 | + | ||
| 38 | +env: | ||
| 39 | + # mm -acp (Zed) and mm without -config read the coordinator from team/, | ||
| 40 | + # not ./agent.yaml: the workspace holds no agent file to rewrite. | ||
| 41 | + AGENT_CONFIG: ${{ env.args.DEV_TEAM_DIR }}/team/agent.yaml | ||
| 42 | + | ||
| 43 | +# Published when the sandbox is created, each to the same port on the host | ||
| 44 | +# (loopback, tcp4 by default). A port already taken on the host makes the | ||
| 45 | +# creation fail. A change here applies at the next ./start-zed.sh. | ||
| 46 | +# Inside the sandbox, a server must listen on 0.0.0.0, not 127.0.0.1. | ||
| 47 | +ports: | ||
| 48 | + - sandbox: 8080 | ||
| 49 | + host: 8080 | ||
| 50 | + - sandbox: 6060 | ||
| 51 | + host: 6060 | ||
| 52 | + - sandbox: 5050 | ||
| 53 | + host: 5050 | ||
| 54 | + | ||
| 55 | +sandboxOptions: | ||
| 56 | + pullPolicy: always | ||
| 57 | + | ||
| 58 | +# sbx setup ssh | ||
| 59 | +# ./start-zed.sh (sbx env create … then zed --new ssh://zed-dev-team.sbx<dev.team>/workspace) | ||
| 60 | +# ./stop-zed.sh (sbx env rm --force --env-arg DEV_TEAM_DIR="$PWD") | ||
added
dev.team/start-zed.sh +8 -0 | new file mode 100755 | ||
| @@ -0,0 +1,8 @@ | ||
| 1 | +#!/usr/bin/env bash | |
| 2 | +# Creates the sandbox from sbxenv.yaml and opens workspace/ in Zed over SSH. | |
| 3 | +# Run it from dev.team/ (the folder of sbxenv.yaml). Once: sbx setup ssh | |
| 4 | +set -euo pipefail | |
| 5 | +cd "$(dirname "$0")" | |
| 6 | +# DEV_TEAM_DIR tells the sandbox where team/agent.yaml is (AGENT_CONFIG). | |
| 7 | +sbx env create --force --env-arg DEV_TEAM_DIR="$PWD" | |
| 8 | +zed --new "ssh://zed-dev-team.sbx$PWD/workspace" | |
| new file mode 100755 | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | +#!/usr/bin/env bash | ||
| 2 | +# Creates the sandbox from sbxenv.yaml and opens workspace/ in Zed over SSH. | ||
| 3 | +# Run it from dev.team/ (the folder of sbxenv.yaml). Once: sbx setup ssh | ||
| 4 | +set -euo pipefail | ||
| 5 | +cd "$(dirname "$0")" | ||
| 6 | +# DEV_TEAM_DIR tells the sandbox where team/agent.yaml is (AGENT_CONFIG). | ||
| 7 | +sbx env create --force --env-arg DEV_TEAM_DIR="$PWD" | ||
| 8 | +zed --new "ssh://zed-dev-team.sbx$PWD/workspace" | ||
added
dev.team/stop-zed.sh +7 -0 | new file mode 100755 | ||
| @@ -0,0 +1,7 @@ | ||
| 1 | +#!/usr/bin/env bash | |
| 2 | +# Removes the sandbox. workspace/ and team/ stay on the host as they are. | |
| 3 | +set -euo pipefail | |
| 4 | +cd "$(dirname "$0")" | |
| 5 | +# Every `sbx env` command reads sbxenv.yaml, whose DEV_TEAM_DIR argument is | |
| 6 | +# required: pass it here too, the same value as start-zed.sh. | |
| 7 | +sbx env rm --force --env-arg DEV_TEAM_DIR="$PWD" | |
| new file mode 100755 | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | +#!/usr/bin/env bash | ||
| 2 | +# Removes the sandbox. workspace/ and team/ stay on the host as they are. | ||
| 3 | +set -euo pipefail | ||
| 4 | +cd "$(dirname "$0")" | ||
| 5 | +# Every `sbx env` command reads sbxenv.yaml, whose DEV_TEAM_DIR argument is | ||
| 6 | +# required: pass it here too, the same value as start-zed.sh. | ||
| 7 | +sbx env rm --force --env-arg DEV_TEAM_DIR="$PWD" | ||
added
dev.team/team/agent.coder.ornith.yaml +140 -0 | new file mode 100644 | ||
| @@ -0,0 +1,140 @@ | ||
| 1 | +# Coder (Ornith variant) — the same coder on Ornith 1.5 9B with reasoning on: | |
| 2 | +# slower, steadier. To use it, point the coordinator's mmConfigs coder.path | |
| 3 | +# at this file. Measured alone on the "most frequent words" brief: 2 runs out | |
| 4 | +# of 2 correct and formatted, ~800 s each; Mellum2 (agent.coder.yaml): 2 out | |
| 5 | +# of 3, 130–640 s. See the README. | |
| 6 | +# | |
| 7 | +# Coder — writes and fixes code in the current project, then proves it with | |
| 8 | +# the project's own commands. Called by the coordinator (agent.yaml) with a | |
| 9 | +# task brief from the reformulator; also usable alone: | |
| 10 | +# | |
| 11 | +# cd dev.team/workspace && ../../mm -config ../team/agent.coder.ornith.yaml | |
| 12 | +# | |
| 13 | +# Model: Ornith 1.5 9B (a Qwen3.5 9B fine-tune), Q4_K_M, 6.7 GB. | |
| 14 | + | |
| 15 | +provider: llmman | |
| 16 | +model: hf.co/ornith-ai/Ornith-1.5-9B-GGUF:Q4_K_M | |
| 17 | +baseUrl: http://127.0.0.1:17434/v1 | |
| 18 | +fallback: http://host.docker.internal:17434/v1 | |
| 19 | + | |
| 20 | +# 32k is enough for a task brief, a few files and the test output, and keeps | |
| 21 | +# the KV cache small on a 32 GB machine. | |
| 22 | +contextWindow: 32768 | |
| 23 | + | |
| 24 | +sampling: | |
| 25 | + # Qwen3.5's thinking values (Ornith is a Qwen3.5 9B fine-tune), as in | |
| 26 | + # demos/team's coder. | |
| 27 | + temperature: 0.6 | |
| 28 | + top_p: 0.95 | |
| 29 | + top_k: 20 | |
| 30 | + # Reasoning on: room for the thoughts plus a whole file. | |
| 31 | + max_tokens: 8192 | |
| 32 | + parallel_tool_calls: false | |
| 33 | + # The template's default is on; set it anyway. | |
| 34 | + chat_template_kwargs: | |
| 35 | + enable_thinking: true | |
| 36 | + | |
| 37 | +firstTokenTimeout: 3m | |
| 38 | +# With bash on, the watchdog follows bashTimeout (settings guide, section 3). | |
| 39 | +watchdogTimeout: 2m | |
| 40 | +bashTimeout: 2m | |
| 41 | + | |
| 42 | +# Read, change, test, fix: a bug fix takes ~6 calls, a feature ~12. | |
| 43 | +maxTurns: 30 | |
| 44 | +maxOutput: 12000 | |
| 45 | +previewLines: 10 | |
| 46 | +displayCommands: true | |
| 47 | + | |
| 48 | +# ─── Tools ─────────────────────────────────────────────────────────────────── | |
| 49 | + | |
| 50 | +# The coordinator's mmConfigs entry decides (yolo: true there); alone, you | |
| 51 | +# approve each command and file change. | |
| 52 | +yolo: false | |
| 53 | +bashTool: true | |
| 54 | +editTools: true | |
| 55 | +# No plan tool: measured in the team run, Mellum2 called `plan update` in a | |
| 56 | +# loop (each call failed) until the coordinator gave up on the hand-off. The | |
| 57 | +# task brief is the plan. | |
| 58 | +planTool: false | |
| 59 | +# Questions go through the reformulator, before the coder starts. | |
| 60 | +askUserTool: false | |
| 61 | +fetchContentTool: false | |
| 62 | +saveAnswerTool: false | |
| 63 | +# The coordinator's hooks unload the models; no unload_model tool here. | |
| 64 | +unloadModels: false | |
| 65 | +skillsDir: no-skills | |
| 66 | + | |
| 67 | +agentsMd: | |
| 68 | + enabled: false | |
| 69 | + | |
| 70 | +context: | |
| 71 | + enabled: true | |
| 72 | + threshold: 70 | |
| 73 | + keepLastTurns: 2 | |
| 74 | + summaryMaxTokens: 1200 | |
| 75 | + | |
| 76 | +# Every Go file the coder writes is formatted: measured, Mellum2 skipped the | |
| 77 | +# prompt's gofmt step in 2 runs out of 2. A file gofmt cannot parse comes back | |
| 78 | +# to the model as context. | |
| 79 | +hooks: | |
| 80 | + postToolCall: | |
| 81 | + - matcher: ^(write_file|edit_file)$ | |
| 82 | + command: node "$MM_CONFIG_DIR/hooks/gofmt.js" | |
| 83 | + timeout: 10s | |
| 84 | + onError: warn | |
| 85 | + | |
| 86 | +# ─── Go language server ────────────────────────────────────────────────────── | |
| 87 | + | |
| 88 | +# The `lsp` tool, for .go files: definition, references, hover, symbols, | |
| 89 | +# diagnostics, rename. gopls must be on the PATH (go install | |
| 90 | +# golang.org/x/tools/gopls@latest); not found = a start-up warning, no tool. | |
| 91 | +lsp: | |
| 92 | + servers: | |
| 93 | + - name: gopls | |
| 94 | + command: gopls | |
| 95 | + extensions: [".go"] | |
| 96 | + | |
| 97 | +acp: | |
| 98 | + name: coder | |
| 99 | + title: 🛠️ Coder (Ornith) | |
| 100 | + | |
| 101 | +system: | | |
| 102 | + You are Coder, a software developer working in a terminal, in the current | |
| 103 | + directory. You get a task: a bug to fix, a feature to add, a change to make. | |
| 104 | + | |
| 105 | + TOOLS | |
| 106 | + - `bash` runs commands. Each call is a new shell started in the current | |
| 107 | + directory: begin with `cd <dir> &&` when the project is in a | |
| 108 | + sub-directory (cd playground && go test ./...). | |
| 109 | + - `lsp` (gopls, .go files): `references` before changing a function's | |
| 110 | + signature, to find every caller; `rename` to rename an identifier | |
| 111 | + everywhere (never edit_file for a rename) — every field filled, e.g. | |
| 112 | + {"action": "rename", "path": "playground/textstats.go", | |
| 113 | + "symbol": "LineCount", "new_name": "CountLines"}; | |
| 114 | + `diagnostics` on a file you changed; `definition` / `hover` to | |
| 115 | + understand code you did not write. After a rename, grep for the old AND | |
| 116 | + the new name to check the result before you report it. | |
| 117 | + - `read_file` reads a file; `edit_file` changes it — `old` copied exactly | |
| 118 | + from what read_file returned; `write_file` creates a file, ONE complete | |
| 119 | + file per call. | |
| 120 | + | |
| 121 | + HOW TO WORK | |
| 122 | + 1. Look before you change: list the files (ls), read the ones the task | |
| 123 | + names, find how the project is built and tested (go.mod, Makefile, | |
| 124 | + package.json, README). | |
| 125 | + 2. Make the smallest change that does the task. Keep the style of the | |
| 126 | + code around it. Add test cases for what you changed; keep the existing | |
| 127 | + ones (add, do not replace). | |
| 128 | + 3. Format what you changed (gofmt -w <file> for Go), then run the | |
| 129 | + project's tests (and its build or linter when it has one). | |
| 130 | + When a command fails, read the error, fix the file it names, run the | |
| 131 | + command again. | |
| 132 | + 4. Report: the files changed, the commands run and their result. | |
| 133 | + | |
| 134 | + RULES | |
| 135 | + - Facts come from tools: never say the code builds or the tests pass | |
| 136 | + without the command output in this answer. | |
| 137 | + - Write code with tools, never as code blocks in your answer. | |
| 138 | + - Never delete a test or a file to make an error go away. | |
| 139 | + - Never start a program that does not return (a server, a watcher). | |
| 140 | + - Answer in English, briefly. | |
| new file mode 100644 | |||
| @@ -0,0 +1,140 @@ | |||
| 1 | +# Coder (Ornith variant) — the same coder on Ornith 1.5 9B with reasoning on: | ||
| 2 | +# slower, steadier. To use it, point the coordinator's mmConfigs coder.path | ||
| 3 | +# at this file. Measured alone on the "most frequent words" brief: 2 runs out | ||
| 4 | +# of 2 correct and formatted, ~800 s each; Mellum2 (agent.coder.yaml): 2 out | ||
| 5 | +# of 3, 130–640 s. See the README. | ||
| 6 | +# | ||
| 7 | +# Coder — writes and fixes code in the current project, then proves it with | ||
| 8 | +# the project's own commands. Called by the coordinator (agent.yaml) with a | ||
| 9 | +# task brief from the reformulator; also usable alone: | ||
| 10 | +# | ||
| 11 | +# cd dev.team/workspace && ../../mm -config ../team/agent.coder.ornith.yaml | ||
| 12 | +# | ||
| 13 | +# Model: Ornith 1.5 9B (a Qwen3.5 9B fine-tune), Q4_K_M, 6.7 GB. | ||
| 14 | + | ||
| 15 | +provider: llmman | ||
| 16 | +model: hf.co/ornith-ai/Ornith-1.5-9B-GGUF:Q4_K_M | ||
| 17 | +baseUrl: http://127.0.0.1:17434/v1 | ||
| 18 | +fallback: http://host.docker.internal:17434/v1 | ||
| 19 | + | ||
| 20 | +# 32k is enough for a task brief, a few files and the test output, and keeps | ||
| 21 | +# the KV cache small on a 32 GB machine. | ||
| 22 | +contextWindow: 32768 | ||
| 23 | + | ||
| 24 | +sampling: | ||
| 25 | + # Qwen3.5's thinking values (Ornith is a Qwen3.5 9B fine-tune), as in | ||
| 26 | + # demos/team's coder. | ||
| 27 | + temperature: 0.6 | ||
| 28 | + top_p: 0.95 | ||
| 29 | + top_k: 20 | ||
| 30 | + # Reasoning on: room for the thoughts plus a whole file. | ||
| 31 | + max_tokens: 8192 | ||
| 32 | + parallel_tool_calls: false | ||
| 33 | + # The template's default is on; set it anyway. | ||
| 34 | + chat_template_kwargs: | ||
| 35 | + enable_thinking: true | ||
| 36 | + | ||
| 37 | +firstTokenTimeout: 3m | ||
| 38 | +# With bash on, the watchdog follows bashTimeout (settings guide, section 3). | ||
| 39 | +watchdogTimeout: 2m | ||
| 40 | +bashTimeout: 2m | ||
| 41 | + | ||
| 42 | +# Read, change, test, fix: a bug fix takes ~6 calls, a feature ~12. | ||
| 43 | +maxTurns: 30 | ||
| 44 | +maxOutput: 12000 | ||
| 45 | +previewLines: 10 | ||
| 46 | +displayCommands: true | ||
| 47 | + | ||
| 48 | +# ─── Tools ─────────────────────────────────────────────────────────────────── | ||
| 49 | + | ||
| 50 | +# The coordinator's mmConfigs entry decides (yolo: true there); alone, you | ||
| 51 | +# approve each command and file change. | ||
| 52 | +yolo: false | ||
| 53 | +bashTool: true | ||
| 54 | +editTools: true | ||
| 55 | +# No plan tool: measured in the team run, Mellum2 called `plan update` in a | ||
| 56 | +# loop (each call failed) until the coordinator gave up on the hand-off. The | ||
| 57 | +# task brief is the plan. | ||
| 58 | +planTool: false | ||
| 59 | +# Questions go through the reformulator, before the coder starts. | ||
| 60 | +askUserTool: false | ||
| 61 | +fetchContentTool: false | ||
| 62 | +saveAnswerTool: false | ||
| 63 | +# The coordinator's hooks unload the models; no unload_model tool here. | ||
| 64 | +unloadModels: false | ||
| 65 | +skillsDir: no-skills | ||
| 66 | + | ||
| 67 | +agentsMd: | ||
| 68 | + enabled: false | ||
| 69 | + | ||
| 70 | +context: | ||
| 71 | + enabled: true | ||
| 72 | + threshold: 70 | ||
| 73 | + keepLastTurns: 2 | ||
| 74 | + summaryMaxTokens: 1200 | ||
| 75 | + | ||
| 76 | +# Every Go file the coder writes is formatted: measured, Mellum2 skipped the | ||
| 77 | +# prompt's gofmt step in 2 runs out of 2. A file gofmt cannot parse comes back | ||
| 78 | +# to the model as context. | ||
| 79 | +hooks: | ||
| 80 | + postToolCall: | ||
| 81 | + - matcher: ^(write_file|edit_file)$ | ||
| 82 | + command: node "$MM_CONFIG_DIR/hooks/gofmt.js" | ||
| 83 | + timeout: 10s | ||
| 84 | + onError: warn | ||
| 85 | + | ||
| 86 | +# ─── Go language server ────────────────────────────────────────────────────── | ||
| 87 | + | ||
| 88 | +# The `lsp` tool, for .go files: definition, references, hover, symbols, | ||
| 89 | +# diagnostics, rename. gopls must be on the PATH (go install | ||
| 90 | +# golang.org/x/tools/gopls@latest); not found = a start-up warning, no tool. | ||
| 91 | +lsp: | ||
| 92 | + servers: | ||
| 93 | + - name: gopls | ||
| 94 | + command: gopls | ||
| 95 | + extensions: [".go"] | ||
| 96 | + | ||
| 97 | +acp: | ||
| 98 | + name: coder | ||
| 99 | + title: 🛠️ Coder (Ornith) | ||
| 100 | + | ||
| 101 | +system: | | ||
| 102 | + You are Coder, a software developer working in a terminal, in the current | ||
| 103 | + directory. You get a task: a bug to fix, a feature to add, a change to make. | ||
| 104 | + | ||
| 105 | + TOOLS | ||
| 106 | + - `bash` runs commands. Each call is a new shell started in the current | ||
| 107 | + directory: begin with `cd <dir> &&` when the project is in a | ||
| 108 | + sub-directory (cd playground && go test ./...). | ||
| 109 | + - `lsp` (gopls, .go files): `references` before changing a function's | ||
| 110 | + signature, to find every caller; `rename` to rename an identifier | ||
| 111 | + everywhere (never edit_file for a rename) — every field filled, e.g. | ||
| 112 | + {"action": "rename", "path": "playground/textstats.go", | ||
| 113 | + "symbol": "LineCount", "new_name": "CountLines"}; | ||
| 114 | + `diagnostics` on a file you changed; `definition` / `hover` to | ||
| 115 | + understand code you did not write. After a rename, grep for the old AND | ||
| 116 | + the new name to check the result before you report it. | ||
| 117 | + - `read_file` reads a file; `edit_file` changes it — `old` copied exactly | ||
| 118 | + from what read_file returned; `write_file` creates a file, ONE complete | ||
| 119 | + file per call. | ||
| 120 | + | ||
| 121 | + HOW TO WORK | ||
| 122 | + 1. Look before you change: list the files (ls), read the ones the task | ||
| 123 | + names, find how the project is built and tested (go.mod, Makefile, | ||
| 124 | + package.json, README). | ||
| 125 | + 2. Make the smallest change that does the task. Keep the style of the | ||
| 126 | + code around it. Add test cases for what you changed; keep the existing | ||
| 127 | + ones (add, do not replace). | ||
| 128 | + 3. Format what you changed (gofmt -w <file> for Go), then run the | ||
| 129 | + project's tests (and its build or linter when it has one). | ||
| 130 | + When a command fails, read the error, fix the file it names, run the | ||
| 131 | + command again. | ||
| 132 | + 4. Report: the files changed, the commands run and their result. | ||
| 133 | + | ||
| 134 | + RULES | ||
| 135 | + - Facts come from tools: never say the code builds or the tests pass | ||
| 136 | + without the command output in this answer. | ||
| 137 | + - Write code with tools, never as code blocks in your answer. | ||
| 138 | + - Never delete a test or a file to make an error go away. | ||
| 139 | + - Never start a program that does not return (a server, a watcher). | ||
| 140 | + - Answer in English, briefly. | ||
added
dev.team/team/agent.coder.yaml +136 -0 | new file mode 100644 | ||
| @@ -0,0 +1,136 @@ | ||
| 1 | +# Coder — writes and fixes code in the current project, then proves it with | |
| 2 | +# the project's own commands. Called by the coordinator (agent.yaml) with a | |
| 3 | +# task brief from the reformulator; also usable alone: | |
| 4 | +# | |
| 5 | +# cd dev.team/workspace && ../../mm -config ../team/agent.coder.yaml | |
| 6 | +# | |
| 7 | +# Model: Mellum2 12B-A2.5B Instruct (JetBrains), Q4_K_M, 8.1 GB — a code | |
| 8 | +# model, mixture of experts (2.5B active), so it answers fast for its size. | |
| 9 | +# The tutor uses the same model: going from one to the other reloads nothing. | |
| 10 | + | |
| 11 | +provider: llmman | |
| 12 | +model: hf.co/JetBrains/Mellum2-12B-A2.5B-Instruct-GGUF-Q4_K_M:Q4_K_M | |
| 13 | +baseUrl: http://127.0.0.1:17434/v1 | |
| 14 | +fallback: http://host.docker.internal:17434/v1 | |
| 15 | + | |
| 16 | +# 32k is enough for a task brief, a few files and the test output, and keeps | |
| 17 | +# the KV cache small on a 32 GB machine. | |
| 18 | +contextWindow: 32768 | |
| 19 | + | |
| 20 | +sampling: | |
| 21 | + # Mellum2 Instruct measured at 0.2 / 0.9 in demos/little-coder. The GGUF | |
| 22 | + # carries no sampling of its own. | |
| 23 | + temperature: 0.2 | |
| 24 | + top_p: 0.9 | |
| 25 | + # A whole file of this size fits. Measured: once, after a failed edit, | |
| 26 | + # Mellum2 wrote a tool call that never closed and ran to the limit (8192 | |
| 27 | + # tokens, minutes lost); 4096 halves what such a call costs. | |
| 28 | + max_tokens: 4096 | |
| 29 | + # One call per reply: run the tests AFTER the edit has landed. | |
| 30 | + parallel_tool_calls: false | |
| 31 | + # No chat_template_kwargs: the Instruct template has no reasoning switch. | |
| 32 | + | |
| 33 | +firstTokenTimeout: 3m | |
| 34 | +# With bash on, the watchdog follows bashTimeout (settings guide, section 3). | |
| 35 | +watchdogTimeout: 2m | |
| 36 | +bashTimeout: 2m | |
| 37 | + | |
| 38 | +# Read, change, test, fix: a bug fix takes ~6 calls, a feature ~12. | |
| 39 | +maxTurns: 30 | |
| 40 | +maxOutput: 12000 | |
| 41 | +previewLines: 10 | |
| 42 | +displayCommands: true | |
| 43 | + | |
| 44 | +# ─── Tools ─────────────────────────────────────────────────────────────────── | |
| 45 | + | |
| 46 | +# The coordinator's mmConfigs entry decides (yolo: true there); alone, you | |
| 47 | +# approve each command and file change. | |
| 48 | +yolo: false | |
| 49 | +bashTool: true | |
| 50 | +editTools: true | |
| 51 | +# No plan tool: measured in the team run, Mellum2 called `plan update` in a | |
| 52 | +# loop (each call failed) until the coordinator gave up on the hand-off. The | |
| 53 | +# task brief is the plan. | |
| 54 | +planTool: false | |
| 55 | +# Questions go through the reformulator, before the coder starts. | |
| 56 | +askUserTool: false | |
| 57 | +fetchContentTool: false | |
| 58 | +saveAnswerTool: false | |
| 59 | +# The coordinator's hooks unload the models; no unload_model tool here. | |
| 60 | +unloadModels: false | |
| 61 | +skillsDir: no-skills | |
| 62 | + | |
| 63 | +agentsMd: | |
| 64 | + enabled: false | |
| 65 | + | |
| 66 | +context: | |
| 67 | + enabled: true | |
| 68 | + threshold: 70 | |
| 69 | + keepLastTurns: 2 | |
| 70 | + summaryMaxTokens: 1200 | |
| 71 | + | |
| 72 | +# Every Go file the coder writes is formatted: measured, Mellum2 skipped the | |
| 73 | +# prompt's gofmt step in 2 runs out of 2. A file gofmt cannot parse comes back | |
| 74 | +# to the model as context. | |
| 75 | +hooks: | |
| 76 | + postToolCall: | |
| 77 | + - matcher: ^(write_file|edit_file)$ | |
| 78 | + command: node "$MM_CONFIG_DIR/hooks/gofmt.js" | |
| 79 | + timeout: 10s | |
| 80 | + onError: warn | |
| 81 | + | |
| 82 | +# ─── Go language server ────────────────────────────────────────────────────── | |
| 83 | + | |
| 84 | +# The `lsp` tool, for .go files: definition, references, hover, symbols, | |
| 85 | +# diagnostics, rename. gopls must be on the PATH (go install | |
| 86 | +# golang.org/x/tools/gopls@latest); not found = a start-up warning, no tool. | |
| 87 | +lsp: | |
| 88 | + servers: | |
| 89 | + - name: gopls | |
| 90 | + command: gopls | |
| 91 | + extensions: [".go"] | |
| 92 | + | |
| 93 | +acp: | |
| 94 | + name: coder | |
| 95 | + title: 🛠️ Coder | |
| 96 | + | |
| 97 | +system: | | |
| 98 | + You are Coder, a software developer working in a terminal, in the current | |
| 99 | + directory. You get a task: a bug to fix, a feature to add, a change to make. | |
| 100 | + | |
| 101 | + TOOLS | |
| 102 | + - `bash` runs commands. Each call is a new shell started in the current | |
| 103 | + directory: begin with `cd <dir> &&` when the project is in a | |
| 104 | + sub-directory (cd playground && go test ./...). | |
| 105 | + - `lsp` (gopls, .go files): `references` before changing a function's | |
| 106 | + signature, to find every caller; `rename` to rename an identifier | |
| 107 | + everywhere (never edit_file for a rename) — every field filled, e.g. | |
| 108 | + {"action": "rename", "path": "playground/textstats.go", | |
| 109 | + "symbol": "LineCount", "new_name": "CountLines"}; | |
| 110 | + `diagnostics` on a file you changed; `definition` / `hover` to | |
| 111 | + understand code you did not write. After a rename, grep for the old AND | |
| 112 | + the new name to check the result before you report it. | |
| 113 | + - `read_file` reads a file; `edit_file` changes it — `old` copied exactly | |
| 114 | + from what read_file returned; `write_file` creates a file, ONE complete | |
| 115 | + file per call. | |
| 116 | + | |
| 117 | + HOW TO WORK | |
| 118 | + 1. Look before you change: list the files (ls), read the ones the task | |
| 119 | + names, find how the project is built and tested (go.mod, Makefile, | |
| 120 | + package.json, README). | |
| 121 | + 2. Make the smallest change that does the task. Keep the style of the | |
| 122 | + code around it. Add test cases for what you changed; keep the existing | |
| 123 | + ones (add, do not replace). | |
| 124 | + 3. Format what you changed (gofmt -w <file> for Go), then run the | |
| 125 | + project's tests (and its build or linter when it has one). | |
| 126 | + When a command fails, read the error, fix the file it names, run the | |
| 127 | + command again. | |
| 128 | + 4. Report: the files changed, the commands run and their result. | |
| 129 | + | |
| 130 | + RULES | |
| 131 | + - Facts come from tools: never say the code builds or the tests pass | |
| 132 | + without the command output in this answer. | |
| 133 | + - Write code with tools, never as code blocks in your answer. | |
| 134 | + - Never delete a test or a file to make an error go away. | |
| 135 | + - Never start a program that does not return (a server, a watcher). | |
| 136 | + - Answer in English, briefly. | |
| new file mode 100644 | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | +# Coder — writes and fixes code in the current project, then proves it with | ||
| 2 | +# the project's own commands. Called by the coordinator (agent.yaml) with a | ||
| 3 | +# task brief from the reformulator; also usable alone: | ||
| 4 | +# | ||
| 5 | +# cd dev.team/workspace && ../../mm -config ../team/agent.coder.yaml | ||
| 6 | +# | ||
| 7 | +# Model: Mellum2 12B-A2.5B Instruct (JetBrains), Q4_K_M, 8.1 GB — a code | ||
| 8 | +# model, mixture of experts (2.5B active), so it answers fast for its size. | ||
| 9 | +# The tutor uses the same model: going from one to the other reloads nothing. | ||
| 10 | + | ||
| 11 | +provider: llmman | ||
| 12 | +model: hf.co/JetBrains/Mellum2-12B-A2.5B-Instruct-GGUF-Q4_K_M:Q4_K_M | ||
| 13 | +baseUrl: http://127.0.0.1:17434/v1 | ||
| 14 | +fallback: http://host.docker.internal:17434/v1 | ||
| 15 | + | ||
| 16 | +# 32k is enough for a task brief, a few files and the test output, and keeps | ||
| 17 | +# the KV cache small on a 32 GB machine. | ||
| 18 | +contextWindow: 32768 | ||
| 19 | + | ||
| 20 | +sampling: | ||
| 21 | + # Mellum2 Instruct measured at 0.2 / 0.9 in demos/little-coder. The GGUF | ||
| 22 | + # carries no sampling of its own. | ||
| 23 | + temperature: 0.2 | ||
| 24 | + top_p: 0.9 | ||
| 25 | + # A whole file of this size fits. Measured: once, after a failed edit, | ||
| 26 | + # Mellum2 wrote a tool call that never closed and ran to the limit (8192 | ||
| 27 | + # tokens, minutes lost); 4096 halves what such a call costs. | ||
| 28 | + max_tokens: 4096 | ||
| 29 | + # One call per reply: run the tests AFTER the edit has landed. | ||
| 30 | + parallel_tool_calls: false | ||
| 31 | + # No chat_template_kwargs: the Instruct template has no reasoning switch. | ||
| 32 | + | ||
| 33 | +firstTokenTimeout: 3m | ||
| 34 | +# With bash on, the watchdog follows bashTimeout (settings guide, section 3). | ||
| 35 | +watchdogTimeout: 2m | ||
| 36 | +bashTimeout: 2m | ||
| 37 | + | ||
| 38 | +# Read, change, test, fix: a bug fix takes ~6 calls, a feature ~12. | ||
| 39 | +maxTurns: 30 | ||
| 40 | +maxOutput: 12000 | ||
| 41 | +previewLines: 10 | ||
| 42 | +displayCommands: true | ||
| 43 | + | ||
| 44 | +# ─── Tools ─────────────────────────────────────────────────────────────────── | ||
| 45 | + | ||
| 46 | +# The coordinator's mmConfigs entry decides (yolo: true there); alone, you | ||
| 47 | +# approve each command and file change. | ||
| 48 | +yolo: false | ||
| 49 | +bashTool: true | ||
| 50 | +editTools: true | ||
| 51 | +# No plan tool: measured in the team run, Mellum2 called `plan update` in a | ||
| 52 | +# loop (each call failed) until the coordinator gave up on the hand-off. The | ||
| 53 | +# task brief is the plan. | ||
| 54 | +planTool: false | ||
| 55 | +# Questions go through the reformulator, before the coder starts. | ||
| 56 | +askUserTool: false | ||
| 57 | +fetchContentTool: false | ||
| 58 | +saveAnswerTool: false | ||
| 59 | +# The coordinator's hooks unload the models; no unload_model tool here. | ||
| 60 | +unloadModels: false | ||
| 61 | +skillsDir: no-skills | ||
| 62 | + | ||
| 63 | +agentsMd: | ||
| 64 | + enabled: false | ||
| 65 | + | ||
| 66 | +context: | ||
| 67 | + enabled: true | ||
| 68 | + threshold: 70 | ||
| 69 | + keepLastTurns: 2 | ||
| 70 | + summaryMaxTokens: 1200 | ||
| 71 | + | ||
| 72 | +# Every Go file the coder writes is formatted: measured, Mellum2 skipped the | ||
| 73 | +# prompt's gofmt step in 2 runs out of 2. A file gofmt cannot parse comes back | ||
| 74 | +# to the model as context. | ||
| 75 | +hooks: | ||
| 76 | + postToolCall: | ||
| 77 | + - matcher: ^(write_file|edit_file)$ | ||
| 78 | + command: node "$MM_CONFIG_DIR/hooks/gofmt.js" | ||
| 79 | + timeout: 10s | ||
| 80 | + onError: warn | ||
| 81 | + | ||
| 82 | +# ─── Go language server ────────────────────────────────────────────────────── | ||
| 83 | + | ||
| 84 | +# The `lsp` tool, for .go files: definition, references, hover, symbols, | ||
| 85 | +# diagnostics, rename. gopls must be on the PATH (go install | ||
| 86 | +# golang.org/x/tools/gopls@latest); not found = a start-up warning, no tool. | ||
| 87 | +lsp: | ||
| 88 | + servers: | ||
| 89 | + - name: gopls | ||
| 90 | + command: gopls | ||
| 91 | + extensions: [".go"] | ||
| 92 | + | ||
| 93 | +acp: | ||
| 94 | + name: coder | ||
| 95 | + title: 🛠️ Coder | ||
| 96 | + | ||
| 97 | +system: | | ||
| 98 | + You are Coder, a software developer working in a terminal, in the current | ||
| 99 | + directory. You get a task: a bug to fix, a feature to add, a change to make. | ||
| 100 | + | ||
| 101 | + TOOLS | ||
| 102 | + - `bash` runs commands. Each call is a new shell started in the current | ||
| 103 | + directory: begin with `cd <dir> &&` when the project is in a | ||
| 104 | + sub-directory (cd playground && go test ./...). | ||
| 105 | + - `lsp` (gopls, .go files): `references` before changing a function's | ||
| 106 | + signature, to find every caller; `rename` to rename an identifier | ||
| 107 | + everywhere (never edit_file for a rename) — every field filled, e.g. | ||
| 108 | + {"action": "rename", "path": "playground/textstats.go", | ||
| 109 | + "symbol": "LineCount", "new_name": "CountLines"}; | ||
| 110 | + `diagnostics` on a file you changed; `definition` / `hover` to | ||
| 111 | + understand code you did not write. After a rename, grep for the old AND | ||
| 112 | + the new name to check the result before you report it. | ||
| 113 | + - `read_file` reads a file; `edit_file` changes it — `old` copied exactly | ||
| 114 | + from what read_file returned; `write_file` creates a file, ONE complete | ||
| 115 | + file per call. | ||
| 116 | + | ||
| 117 | + HOW TO WORK | ||
| 118 | + 1. Look before you change: list the files (ls), read the ones the task | ||
| 119 | + names, find how the project is built and tested (go.mod, Makefile, | ||
| 120 | + package.json, README). | ||
| 121 | + 2. Make the smallest change that does the task. Keep the style of the | ||
| 122 | + code around it. Add test cases for what you changed; keep the existing | ||
| 123 | + ones (add, do not replace). | ||
| 124 | + 3. Format what you changed (gofmt -w <file> for Go), then run the | ||
| 125 | + project's tests (and its build or linter when it has one). | ||
| 126 | + When a command fails, read the error, fix the file it names, run the | ||
| 127 | + command again. | ||
| 128 | + 4. Report: the files changed, the commands run and their result. | ||
| 129 | + | ||
| 130 | + RULES | ||
| 131 | + - Facts come from tools: never say the code builds or the tests pass | ||
| 132 | + without the command output in this answer. | ||
| 133 | + - Write code with tools, never as code blocks in your answer. | ||
| 134 | + - Never delete a test or a file to make an error go away. | ||
| 135 | + - Never start a program that does not return (a server, a watcher). | ||
| 136 | + - Answer in English, briefly. | ||
added
dev.team/team/agent.reformulator.yaml +111 -0 | new file mode 100644 | ||
| @@ -0,0 +1,111 @@ | ||
| 1 | +# Reformulator — turns a request into a task brief the coder and the reviewer | |
| 2 | +# can act on: the goal, the files, what "done" means. When the request leaves | |
| 3 | +# out something only the user knows, it asks them (ask_user). It changes | |
| 4 | +# nothing. Called first by the coordinator (agent.yaml) for every code task; | |
| 5 | +# also usable alone: | |
| 6 | +# | |
| 7 | +# cd dev.team/workspace && ../../mm -config ../team/agent.reformulator.yaml | |
| 8 | +# | |
| 9 | +# Model: Gemma 4 12B it (unsloth), Q4_K_M, 7.3 GB — good at rewriting and at | |
| 10 | +# following a fixed output shape. Same model as the reviewer. | |
| 11 | + | |
| 12 | +provider: llmman | |
| 13 | +model: hf.co/unsloth/gemma-4-12b-it-GGUF:Q4_K_M | |
| 14 | +baseUrl: http://127.0.0.1:17434/v1 | |
| 15 | +fallback: http://host.docker.internal:17434/v1 | |
| 16 | + | |
| 17 | +contextWindow: 32768 | |
| 18 | + | |
| 19 | +sampling: | |
| 20 | + # Writing a brief, not code: a little freedom, still exact on file names. | |
| 21 | + temperature: 0.3 | |
| 22 | + top_p: 0.95 | |
| 23 | + top_k: 64 | |
| 24 | + max_tokens: 4096 | |
| 25 | + parallel_tool_calls: false | |
| 26 | + chat_template_kwargs: | |
| 27 | + enable_thinking: false | |
| 28 | + | |
| 29 | +firstTokenTimeout: 3m | |
| 30 | +# A question to the user may wait as long as they take: ask_user keeps the | |
| 31 | +# watchdog quiet while a human answers. | |
| 32 | +watchdogTimeout: 2m | |
| 33 | +bashTimeout: 30s | |
| 34 | + | |
| 35 | +# Look at a few files, maybe one question, then the brief. | |
| 36 | +maxTurns: 10 | |
| 37 | +maxOutput: 8000 | |
| 38 | +previewLines: 10 | |
| 39 | +displayCommands: true | |
| 40 | + | |
| 41 | +# ─── Tools ─────────────────────────────────────────────────────────────────── | |
| 42 | + | |
| 43 | +yolo: false | |
| 44 | +# Read-only use (ls, cat, grep, git log): to name the right files in the | |
| 45 | +# brief. The prompt forbids changing anything; no file tools are declared. | |
| 46 | +bashTool: true | |
| 47 | +editTools: false | |
| 48 | +planTool: false | |
| 49 | +# The point of this agent: ask what only the user knows. The coordinator's | |
| 50 | +# mmConfigs entry sets askUser: true so the questions come up to the user. | |
| 51 | +askUserTool: true | |
| 52 | +fetchContentTool: false | |
| 53 | +saveAnswerTool: false | |
| 54 | +# The coordinator's hooks unload the models; no unload_model tool here. | |
| 55 | +unloadModels: false | |
| 56 | +skillsDir: no-skills | |
| 57 | + | |
| 58 | +agentsMd: | |
| 59 | + enabled: false | |
| 60 | + | |
| 61 | +# ─── Go language server ────────────────────────────────────────────────────── | |
| 62 | + | |
| 63 | +# The `lsp` tool, for .go files: definition, references, hover, symbols, | |
| 64 | +# diagnostics, rename. gopls must be on the PATH (go install | |
| 65 | +# golang.org/x/tools/gopls@latest); not found = a start-up warning, no tool. | |
| 66 | +lsp: | |
| 67 | + servers: | |
| 68 | + - name: gopls | |
| 69 | + command: gopls | |
| 70 | + extensions: [".go"] | |
| 71 | + | |
| 72 | +acp: | |
| 73 | + name: reformulator | |
| 74 | + title: 📝 Reformulator | |
| 75 | + | |
| 76 | +system: | | |
| 77 | + You are Reformulator. You turn a request about code into a TASK BRIEF that | |
| 78 | + a developer and a reviewer can act on without asking anything. You never | |
| 79 | + write code and never change a file. | |
| 80 | + | |
| 81 | + HOW TO WORK | |
| 82 | + 1. Look at the project when the request names one: list its files and read | |
| 83 | + the ones that matter, with bash (ls, cat, grep, git log). Only commands | |
| 84 | + that read: never write, move or delete anything. | |
| 85 | + For Go code, `lsp` `references` and `symbols` show which files a change | |
| 86 | + touches; never `rename`, and no other action that changes a file. | |
| 87 | + 2. If the request leaves out something only the user can decide — how | |
| 88 | + many results, the order, case or punctuation handling, the name or the | |
| 89 | + signature of a new public function, what to do on bad input — call | |
| 90 | + ask_user ONCE, with up to 3 short questions, each with choices when there | |
| 91 | + are a few obvious answers. Do not ask what you can read in the files. | |
| 92 | + If the user cannot be asked, choose the simplest reading of the request, | |
| 93 | + and write each choice you made under ASSUMPTIONS. | |
| 94 | + 3. Answer with the brief, in English, in exactly this shape: | |
| 95 | + | |
| 96 | + TASK: one sentence — what to do. | |
| 97 | + CONTEXT: the project, its language, how it is built and tested | |
| 98 | + (the commands), the files concerned. | |
| 99 | + REQUIREMENTS: numbered, each one checkable. | |
| 100 | + ACCEPTANCE: the cases that must work, as concrete inputs and expected | |
| 101 | + outputs when possible. | |
| 102 | + OUT OF SCOPE: what must not be changed. | |
| 103 | + ASSUMPTIONS: each choice you made that the user did not state, or | |
| 104 | + "none". | |
| 105 | + | |
| 106 | + RULES | |
| 107 | + - Keep every detail the user gave; add none they did not imply. Never put | |
| 108 | + under OUT OF SCOPE something the request asks for (a request for "the | |
| 109 | + most frequent words" asks for an order and a limit). | |
| 110 | + - File names and commands must be ones you saw, not guesses. | |
| 111 | + - No code in the brief, except short inputs and outputs in ACCEPTANCE. | |
| new file mode 100644 | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | +# Reformulator — turns a request into a task brief the coder and the reviewer | ||
| 2 | +# can act on: the goal, the files, what "done" means. When the request leaves | ||
| 3 | +# out something only the user knows, it asks them (ask_user). It changes | ||
| 4 | +# nothing. Called first by the coordinator (agent.yaml) for every code task; | ||
| 5 | +# also usable alone: | ||
| 6 | +# | ||
| 7 | +# cd dev.team/workspace && ../../mm -config ../team/agent.reformulator.yaml | ||
| 8 | +# | ||
| 9 | +# Model: Gemma 4 12B it (unsloth), Q4_K_M, 7.3 GB — good at rewriting and at | ||
| 10 | +# following a fixed output shape. Same model as the reviewer. | ||
| 11 | + | ||
| 12 | +provider: llmman | ||
| 13 | +model: hf.co/unsloth/gemma-4-12b-it-GGUF:Q4_K_M | ||
| 14 | +baseUrl: http://127.0.0.1:17434/v1 | ||
| 15 | +fallback: http://host.docker.internal:17434/v1 | ||
| 16 | + | ||
| 17 | +contextWindow: 32768 | ||
| 18 | + | ||
| 19 | +sampling: | ||
| 20 | + # Writing a brief, not code: a little freedom, still exact on file names. | ||
| 21 | + temperature: 0.3 | ||
| 22 | + top_p: 0.95 | ||
| 23 | + top_k: 64 | ||
| 24 | + max_tokens: 4096 | ||
| 25 | + parallel_tool_calls: false | ||
| 26 | + chat_template_kwargs: | ||
| 27 | + enable_thinking: false | ||
| 28 | + | ||
| 29 | +firstTokenTimeout: 3m | ||
| 30 | +# A question to the user may wait as long as they take: ask_user keeps the | ||
| 31 | +# watchdog quiet while a human answers. | ||
| 32 | +watchdogTimeout: 2m | ||
| 33 | +bashTimeout: 30s | ||
| 34 | + | ||
| 35 | +# Look at a few files, maybe one question, then the brief. | ||
| 36 | +maxTurns: 10 | ||
| 37 | +maxOutput: 8000 | ||
| 38 | +previewLines: 10 | ||
| 39 | +displayCommands: true | ||
| 40 | + | ||
| 41 | +# ─── Tools ─────────────────────────────────────────────────────────────────── | ||
| 42 | + | ||
| 43 | +yolo: false | ||
| 44 | +# Read-only use (ls, cat, grep, git log): to name the right files in the | ||
| 45 | +# brief. The prompt forbids changing anything; no file tools are declared. | ||
| 46 | +bashTool: true | ||
| 47 | +editTools: false | ||
| 48 | +planTool: false | ||
| 49 | +# The point of this agent: ask what only the user knows. The coordinator's | ||
| 50 | +# mmConfigs entry sets askUser: true so the questions come up to the user. | ||
| 51 | +askUserTool: true | ||
| 52 | +fetchContentTool: false | ||
| 53 | +saveAnswerTool: false | ||
| 54 | +# The coordinator's hooks unload the models; no unload_model tool here. | ||
| 55 | +unloadModels: false | ||
| 56 | +skillsDir: no-skills | ||
| 57 | + | ||
| 58 | +agentsMd: | ||
| 59 | + enabled: false | ||
| 60 | + | ||
| 61 | +# ─── Go language server ────────────────────────────────────────────────────── | ||
| 62 | + | ||
| 63 | +# The `lsp` tool, for .go files: definition, references, hover, symbols, | ||
| 64 | +# diagnostics, rename. gopls must be on the PATH (go install | ||
| 65 | +# golang.org/x/tools/gopls@latest); not found = a start-up warning, no tool. | ||
| 66 | +lsp: | ||
| 67 | + servers: | ||
| 68 | + - name: gopls | ||
| 69 | + command: gopls | ||
| 70 | + extensions: [".go"] | ||
| 71 | + | ||
| 72 | +acp: | ||
| 73 | + name: reformulator | ||
| 74 | + title: 📝 Reformulator | ||
| 75 | + | ||
| 76 | +system: | | ||
| 77 | + You are Reformulator. You turn a request about code into a TASK BRIEF that | ||
| 78 | + a developer and a reviewer can act on without asking anything. You never | ||
| 79 | + write code and never change a file. | ||
| 80 | + | ||
| 81 | + HOW TO WORK | ||
| 82 | + 1. Look at the project when the request names one: list its files and read | ||
| 83 | + the ones that matter, with bash (ls, cat, grep, git log). Only commands | ||
| 84 | + that read: never write, move or delete anything. | ||
| 85 | + For Go code, `lsp` `references` and `symbols` show which files a change | ||
| 86 | + touches; never `rename`, and no other action that changes a file. | ||
| 87 | + 2. If the request leaves out something only the user can decide — how | ||
| 88 | + many results, the order, case or punctuation handling, the name or the | ||
| 89 | + signature of a new public function, what to do on bad input — call | ||
| 90 | + ask_user ONCE, with up to 3 short questions, each with choices when there | ||
| 91 | + are a few obvious answers. Do not ask what you can read in the files. | ||
| 92 | + If the user cannot be asked, choose the simplest reading of the request, | ||
| 93 | + and write each choice you made under ASSUMPTIONS. | ||
| 94 | + 3. Answer with the brief, in English, in exactly this shape: | ||
| 95 | + | ||
| 96 | + TASK: one sentence — what to do. | ||
| 97 | + CONTEXT: the project, its language, how it is built and tested | ||
| 98 | + (the commands), the files concerned. | ||
| 99 | + REQUIREMENTS: numbered, each one checkable. | ||
| 100 | + ACCEPTANCE: the cases that must work, as concrete inputs and expected | ||
| 101 | + outputs when possible. | ||
| 102 | + OUT OF SCOPE: what must not be changed. | ||
| 103 | + ASSUMPTIONS: each choice you made that the user did not state, or | ||
| 104 | + "none". | ||
| 105 | + | ||
| 106 | + RULES | ||
| 107 | + - Keep every detail the user gave; add none they did not imply. Never put | ||
| 108 | + under OUT OF SCOPE something the request asks for (a request for "the | ||
| 109 | + most frequent words" asks for an order and a limit). | ||
| 110 | + - File names and commands must be ones you saw, not guesses. | ||
| 111 | + - No code in the brief, except short inputs and outputs in ACCEPTANCE. | ||
added
dev.team/team/agent.reviewer.yaml +127 -0 | new file mode 100644 | ||
| @@ -0,0 +1,127 @@ | ||
| 1 | +# Reviewer — reviews a change and tests it: reads the diff and the code, runs | |
| 2 | +# the project's checks, writes tests that try the task's edge cases, and ends | |
| 3 | +# with a verdict. It never changes the application's code: the coder does. | |
| 4 | +# Called by the coordinator (agent.yaml); also usable alone: | |
| 5 | +# | |
| 6 | +# cd dev.team/workspace && ../../mm -config ../team/agent.reviewer.yaml | |
| 7 | +# | |
| 8 | +# Model: Gemma 4 12B it (unsloth), Q4_K_M, 7.3 GB. A different model from the | |
| 9 | +# coder's on purpose: a reviewer that shares the author's model shares its | |
| 10 | +# blind spots. The reformulator uses the same Gemma: no reload between them. | |
| 11 | + | |
| 12 | +provider: llmman | |
| 13 | +model: hf.co/unsloth/gemma-4-12b-it-GGUF:Q4_K_M | |
| 14 | +baseUrl: http://127.0.0.1:17434/v1 | |
| 15 | +fallback: http://host.docker.internal:17434/v1 | |
| 16 | + | |
| 17 | +contextWindow: 32768 | |
| 18 | + | |
| 19 | +sampling: | |
| 20 | + # The GGUF says 1.0 / 0.95 / 64 for free use; a reviewer runs tools and must | |
| 21 | + # quote exactly: 0.2, measured with Gemma 4 E4B in demos/hooks and guards. | |
| 22 | + temperature: 0.2 | |
| 23 | + top_p: 0.95 | |
| 24 | + top_k: 64 | |
| 25 | + max_tokens: 8192 | |
| 26 | + parallel_tool_calls: false | |
| 27 | + # The template's switch, default off. A review is reading and running, not | |
| 28 | + # long deliberation; off keeps it fast. | |
| 29 | + chat_template_kwargs: | |
| 30 | + enable_thinking: false | |
| 31 | + | |
| 32 | +firstTokenTimeout: 3m | |
| 33 | +watchdogTimeout: 2m | |
| 34 | +bashTimeout: 2m | |
| 35 | + | |
| 36 | +# diff, read, test, write a test, run it, verdict: a good review took 13 | |
| 37 | +# calls. Measured: 20 let a loop run (on a feature it rewrote its own test | |
| 38 | +# and re-read the same lines until the limit); 12 cut a normal review before | |
| 39 | +# its verdict. 16. | |
| 40 | +maxTurns: 16 | |
| 41 | +maxOutput: 12000 | |
| 42 | +previewLines: 10 | |
| 43 | +displayCommands: true | |
| 44 | + | |
| 45 | +# ─── Tools ─────────────────────────────────────────────────────────────────── | |
| 46 | + | |
| 47 | +yolo: false | |
| 48 | +# git diff, go test, go vet… | |
| 49 | +bashTool: true | |
| 50 | +# To write test files (the prompt forbids touching the application's code). | |
| 51 | +editTools: true | |
| 52 | +planTool: false | |
| 53 | +askUserTool: false | |
| 54 | +fetchContentTool: false | |
| 55 | +saveAnswerTool: false | |
| 56 | +# The coordinator's hooks unload the models; no unload_model tool here. | |
| 57 | +unloadModels: false | |
| 58 | +skillsDir: no-skills | |
| 59 | + | |
| 60 | +agentsMd: | |
| 61 | + enabled: false | |
| 62 | + | |
| 63 | +context: | |
| 64 | + enabled: true | |
| 65 | + threshold: 70 | |
| 66 | + keepLastTurns: 2 | |
| 67 | + summaryMaxTokens: 1200 | |
| 68 | + | |
| 69 | +# ─── Go language server ────────────────────────────────────────────────────── | |
| 70 | + | |
| 71 | +# The `lsp` tool, for .go files: definition, references, hover, symbols, | |
| 72 | +# diagnostics, rename. gopls must be on the PATH (go install | |
| 73 | +# golang.org/x/tools/gopls@latest); not found = a start-up warning, no tool. | |
| 74 | +lsp: | |
| 75 | + servers: | |
| 76 | + - name: gopls | |
| 77 | + command: gopls | |
| 78 | + extensions: [".go"] | |
| 79 | + | |
| 80 | +acp: | |
| 81 | + name: reviewer | |
| 82 | + title: 🔎 Reviewer | |
| 83 | + | |
| 84 | +system: | | |
| 85 | + You are Reviewer. You review and test a change in the project in the | |
| 86 | + current directory. You never change the application's code: you report, | |
| 87 | + and the coder fixes. | |
| 88 | + | |
| 89 | + TOOLS | |
| 90 | + - `bash`: each call is a new shell started in the current directory — | |
| 91 | + begin with `cd <dir> &&` when the project is in a sub-directory. | |
| 92 | + - `lsp` (gopls, .go files): `references` to find every caller of the | |
| 93 | + changed code, `diagnostics` on each changed file. Never `rename`: you | |
| 94 | + change no application code. | |
| 95 | + - `read_file` to read code; `write_file` / `edit_file` ONLY for test files | |
| 96 | + (names ending in _test.go, .test.js, test_*.py…). | |
| 97 | + | |
| 98 | + HOW TO REVIEW | |
| 99 | + 1. See what changed, INSIDE the project directory — the folder above is | |
| 100 | + another repository: `cd <dir> && git status && git diff`. When the | |
| 101 | + project is not a git repository, read the files the task names. | |
| 102 | + 2. For each Go function or type the diff touches: `lsp` `references` on | |
| 103 | + it (are all callers and tests still right?) and `lsp` `diagnostics` on | |
| 104 | + each changed file. | |
| 105 | + 3. Read the changed code. Look for: a bug, an edge case not handled | |
| 106 | + (empty input, several spaces, very large values…), a test that does not | |
| 107 | + test what it says. | |
| 108 | + 4. Run the project's tests and checks, ONCE: for Go, `gofmt -l .` (a file it | |
| 109 | + lists is not formatted: a finding), `go vet ./...`, `go test ./...`. | |
| 110 | + In the diff, an existing test case that was removed or changed is a | |
| 111 | + finding unless the task asked for it. | |
| 112 | + 5. Write ONE test file of your own, named review_test.go (or the | |
| 113 | + language's equivalent), with the edge cases of the task's ACCEPTANCE and | |
| 114 | + REQUIREMENTS — never a behaviour the brief does not ask for — and run it | |
| 115 | + once. A failing case of yours is a finding; do not rewrite the test | |
| 116 | + until it passes. | |
| 117 | + 6. Answer with: | |
| 118 | + FINDINGS: one line per problem — file:line, what is wrong, why. | |
| 119 | + "none" when there is none. | |
| 120 | + TESTS: the commands run and their result (pass / fail counts). | |
| 121 | + VERDICT: PASS or VERDICT: FAIL — FAIL when a test fails or a finding | |
| 122 | + is a bug. | |
| 123 | + | |
| 124 | + RULES | |
| 125 | + - Facts come from tools: quote the command output, never guess it. | |
| 126 | + - A finding names a file and a line you read in this answer. | |
| 127 | + - Answer in English. | |
| new file mode 100644 | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | +# Reviewer — reviews a change and tests it: reads the diff and the code, runs | ||
| 2 | +# the project's checks, writes tests that try the task's edge cases, and ends | ||
| 3 | +# with a verdict. It never changes the application's code: the coder does. | ||
| 4 | +# Called by the coordinator (agent.yaml); also usable alone: | ||
| 5 | +# | ||
| 6 | +# cd dev.team/workspace && ../../mm -config ../team/agent.reviewer.yaml | ||
| 7 | +# | ||
| 8 | +# Model: Gemma 4 12B it (unsloth), Q4_K_M, 7.3 GB. A different model from the | ||
| 9 | +# coder's on purpose: a reviewer that shares the author's model shares its | ||
| 10 | +# blind spots. The reformulator uses the same Gemma: no reload between them. | ||
| 11 | + | ||
| 12 | +provider: llmman | ||
| 13 | +model: hf.co/unsloth/gemma-4-12b-it-GGUF:Q4_K_M | ||
| 14 | +baseUrl: http://127.0.0.1:17434/v1 | ||
| 15 | +fallback: http://host.docker.internal:17434/v1 | ||
| 16 | + | ||
| 17 | +contextWindow: 32768 | ||
| 18 | + | ||
| 19 | +sampling: | ||
| 20 | + # The GGUF says 1.0 / 0.95 / 64 for free use; a reviewer runs tools and must | ||
| 21 | + # quote exactly: 0.2, measured with Gemma 4 E4B in demos/hooks and guards. | ||
| 22 | + temperature: 0.2 | ||
| 23 | + top_p: 0.95 | ||
| 24 | + top_k: 64 | ||
| 25 | + max_tokens: 8192 | ||
| 26 | + parallel_tool_calls: false | ||
| 27 | + # The template's switch, default off. A review is reading and running, not | ||
| 28 | + # long deliberation; off keeps it fast. | ||
| 29 | + chat_template_kwargs: | ||
| 30 | + enable_thinking: false | ||
| 31 | + | ||
| 32 | +firstTokenTimeout: 3m | ||
| 33 | +watchdogTimeout: 2m | ||
| 34 | +bashTimeout: 2m | ||
| 35 | + | ||
| 36 | +# diff, read, test, write a test, run it, verdict: a good review took 13 | ||
| 37 | +# calls. Measured: 20 let a loop run (on a feature it rewrote its own test | ||
| 38 | +# and re-read the same lines until the limit); 12 cut a normal review before | ||
| 39 | +# its verdict. 16. | ||
| 40 | +maxTurns: 16 | ||
| 41 | +maxOutput: 12000 | ||
| 42 | +previewLines: 10 | ||
| 43 | +displayCommands: true | ||
| 44 | + | ||
| 45 | +# ─── Tools ─────────────────────────────────────────────────────────────────── | ||
| 46 | + | ||
| 47 | +yolo: false | ||
| 48 | +# git diff, go test, go vet… | ||
| 49 | +bashTool: true | ||
| 50 | +# To write test files (the prompt forbids touching the application's code). | ||
| 51 | +editTools: true | ||
| 52 | +planTool: false | ||
| 53 | +askUserTool: false | ||
| 54 | +fetchContentTool: false | ||
| 55 | +saveAnswerTool: false | ||
| 56 | +# The coordinator's hooks unload the models; no unload_model tool here. | ||
| 57 | +unloadModels: false | ||
| 58 | +skillsDir: no-skills | ||
| 59 | + | ||
| 60 | +agentsMd: | ||
| 61 | + enabled: false | ||
| 62 | + | ||
| 63 | +context: | ||
| 64 | + enabled: true | ||
| 65 | + threshold: 70 | ||
| 66 | + keepLastTurns: 2 | ||
| 67 | + summaryMaxTokens: 1200 | ||
| 68 | + | ||
| 69 | +# ─── Go language server ────────────────────────────────────────────────────── | ||
| 70 | + | ||
| 71 | +# The `lsp` tool, for .go files: definition, references, hover, symbols, | ||
| 72 | +# diagnostics, rename. gopls must be on the PATH (go install | ||
| 73 | +# golang.org/x/tools/gopls@latest); not found = a start-up warning, no tool. | ||
| 74 | +lsp: | ||
| 75 | + servers: | ||
| 76 | + - name: gopls | ||
| 77 | + command: gopls | ||
| 78 | + extensions: [".go"] | ||
| 79 | + | ||
| 80 | +acp: | ||
| 81 | + name: reviewer | ||
| 82 | + title: 🔎 Reviewer | ||
| 83 | + | ||
| 84 | +system: | | ||
| 85 | + You are Reviewer. You review and test a change in the project in the | ||
| 86 | + current directory. You never change the application's code: you report, | ||
| 87 | + and the coder fixes. | ||
| 88 | + | ||
| 89 | + TOOLS | ||
| 90 | + - `bash`: each call is a new shell started in the current directory — | ||
| 91 | + begin with `cd <dir> &&` when the project is in a sub-directory. | ||
| 92 | + - `lsp` (gopls, .go files): `references` to find every caller of the | ||
| 93 | + changed code, `diagnostics` on each changed file. Never `rename`: you | ||
| 94 | + change no application code. | ||
| 95 | + - `read_file` to read code; `write_file` / `edit_file` ONLY for test files | ||
| 96 | + (names ending in _test.go, .test.js, test_*.py…). | ||
| 97 | + | ||
| 98 | + HOW TO REVIEW | ||
| 99 | + 1. See what changed, INSIDE the project directory — the folder above is | ||
| 100 | + another repository: `cd <dir> && git status && git diff`. When the | ||
| 101 | + project is not a git repository, read the files the task names. | ||
| 102 | + 2. For each Go function or type the diff touches: `lsp` `references` on | ||
| 103 | + it (are all callers and tests still right?) and `lsp` `diagnostics` on | ||
| 104 | + each changed file. | ||
| 105 | + 3. Read the changed code. Look for: a bug, an edge case not handled | ||
| 106 | + (empty input, several spaces, very large values…), a test that does not | ||
| 107 | + test what it says. | ||
| 108 | + 4. Run the project's tests and checks, ONCE: for Go, `gofmt -l .` (a file it | ||
| 109 | + lists is not formatted: a finding), `go vet ./...`, `go test ./...`. | ||
| 110 | + In the diff, an existing test case that was removed or changed is a | ||
| 111 | + finding unless the task asked for it. | ||
| 112 | + 5. Write ONE test file of your own, named review_test.go (or the | ||
| 113 | + language's equivalent), with the edge cases of the task's ACCEPTANCE and | ||
| 114 | + REQUIREMENTS — never a behaviour the brief does not ask for — and run it | ||
| 115 | + once. A failing case of yours is a finding; do not rewrite the test | ||
| 116 | + until it passes. | ||
| 117 | + 6. Answer with: | ||
| 118 | + FINDINGS: one line per problem — file:line, what is wrong, why. | ||
| 119 | + "none" when there is none. | ||
| 120 | + TESTS: the commands run and their result (pass / fail counts). | ||
| 121 | + VERDICT: PASS or VERDICT: FAIL — FAIL when a test fails or a finding | ||
| 122 | + is a bug. | ||
| 123 | + | ||
| 124 | + RULES | ||
| 125 | + - Facts come from tools: quote the command output, never guess it. | ||
| 126 | + - A finding names a file and a line you read in this answer. | ||
| 127 | + - Answer in English. | ||
added
dev.team/team/agent.tutor.yaml +122 -0 | new file mode 100644 | ||
| @@ -0,0 +1,122 @@ | ||
| 1 | +# Tutor — answers questions about languages, shells and developer tools with | |
| 2 | +# a MINI TUTORIAL; saves it to a file when asked. Built on the "prof" | |
| 3 | +# configuration of ticket 152 (comment 1), adapted to the team: | |
| 4 | +# - the Q4_K_M quantization the ticket asks for (8.1 GB instead of the | |
| 5 | +# Q8_0's 12.9 GB) — the same file as the coder's, loaded once for both; | |
| 6 | +# - no Rust lsp server and no docSearch over docs/: dev.team has no Rust | |
| 7 | +# code and no docs/ folder; fetch_content covers the documentation; | |
| 8 | +# - no sessions: an agent called through ask_agent runs with sessions off | |
| 9 | +# (AGENT_SESSIONS=off), the coordinator keeps the conversation. | |
| 10 | +# | |
| 11 | +# cd dev.team/workspace && ../../mm -config ../team/agent.tutor.yaml # alone, with sessions | |
| 12 | + | |
| 13 | +provider: llmman | |
| 14 | +model: hf.co/JetBrains/Mellum2-12B-A2.5B-Instruct-GGUF-Q4_K_M:Q4_K_M | |
| 15 | +baseUrl: http://127.0.0.1:17434/v1 | |
| 16 | +fallback: http://host.docker.internal:17434/v1 | |
| 17 | + | |
| 18 | +# mm's budget for compression; llmman served 131072 during the prof's | |
| 19 | +# measurements. | |
| 20 | +contextWindow: 32768 | |
| 21 | + | |
| 22 | +sampling: | |
| 23 | + # Explanations, not code edits: a little more freedom than a coder's 0.2. | |
| 24 | + temperature: 0.3 | |
| 25 | + top_p: 0.9 | |
| 26 | + # A long answer, maybe after one fetched page. | |
| 27 | + max_tokens: 16384 | |
| 28 | + parallel_tool_calls: false | |
| 29 | + # No chat_template_kwargs: the Instruct template has no reasoning switch | |
| 30 | + # (the prof's enable_thinking: false was for the Thinking model). | |
| 31 | + | |
| 32 | +firstTokenTimeout: 3m | |
| 33 | +watchdogTimeout: 2m | |
| 34 | +bashTimeout: 1m | |
| 35 | + | |
| 36 | +# A mini tutorial is one answer, maybe after one fetch, maybe one save. | |
| 37 | +maxTurns: 8 | |
| 38 | +maxOutput: 8000 | |
| 39 | +previewLines: 10 | |
| 40 | + | |
| 41 | +# ─── Tools: the documentation, trying a snippet, saving on request ─────────── | |
| 42 | + | |
| 43 | +yolo: true | |
| 44 | +# Kept from the prof (change of 2026-10-21): bash to try a snippet, files to | |
| 45 | +# read the user's code when a question is about it. | |
| 46 | +bashTool: true | |
| 47 | +editTools: true | |
| 48 | +planTool: false | |
| 49 | +askUserTool: false | |
| 50 | +fetchContentTool: true | |
| 51 | +saveAnswerTool: true | |
| 52 | +# The coordinator's hooks unload the models; no unload_model tool here. | |
| 53 | +unloadModels: false | |
| 54 | +skillsDir: no-skills | |
| 55 | + | |
| 56 | +agentsMd: | |
| 57 | + enabled: false | |
| 58 | + | |
| 59 | +sessions: | |
| 60 | + enabled: true | |
| 61 | + dir: .mm/sessions | |
| 62 | + | |
| 63 | +context: | |
| 64 | + enabled: true | |
| 65 | + threshold: 60 | |
| 66 | + keepLastTurns: 2 | |
| 67 | + summaryMaxTokens: 1200 | |
| 68 | + | |
| 69 | +# ─── Go language server ────────────────────────────────────────────────────── | |
| 70 | + | |
| 71 | +# The `lsp` tool, for .go files: definition, references, hover, symbols, | |
| 72 | +# diagnostics, rename. gopls must be on the PATH (go install | |
| 73 | +# golang.org/x/tools/gopls@latest); not found = a start-up warning, no tool. | |
| 74 | +lsp: | |
| 75 | + servers: | |
| 76 | + - name: gopls | |
| 77 | + command: gopls | |
| 78 | + extensions: [".go"] | |
| 79 | + | |
| 80 | +acp: | |
| 81 | + name: tutor | |
| 82 | + title: 📘 Tutor | |
| 83 | + | |
| 84 | +system: | | |
| 85 | + You are Tutor. You answer questions about programming languages, shells and | |
| 86 | + developer tools with a MINI TUTORIAL, in the language of the question. | |
| 87 | + | |
| 88 | + HOW TO ANSWER | |
| 89 | + 1. Decide whether you need the documentation. Fetch ONE page with | |
| 90 | + fetch_content only when the subject is a recent or niche tool (for | |
| 91 | + example Nushell, a young framework), when the user names a version, or | |
| 92 | + when you are not sure a command or an option exists. For well-known | |
| 93 | + topics (Go, Rust, Python, Kotlin, Java basics) answer from what you know. | |
| 94 | + 2. When the question names a file or code of the current directory, your | |
| 95 | + FIRST action is read_file on it — before writing any word of the | |
| 96 | + lesson. Then base the lesson on that real code and quote it as it is; | |
| 97 | + never show "a typical" version of a file you were asked about. | |
| 98 | + For a Go symbol of that code, `lsp` `hover` gives its signature and | |
| 99 | + documentation, `definition` where it is declared; never `rename`. | |
| 100 | + 3. Write the mini tutorial directly in your reply, in Markdown: | |
| 101 | + - a title (#) | |
| 102 | + - one sentence: what the reader will be able to do | |
| 103 | + - Prerequisites: a short list | |
| 104 | + - 3 to 6 numbered steps, each with a code block and, when it prints | |
| 105 | + something, the expected output | |
| 106 | + - Pitfalls: 2 or 3 short points | |
| 107 | + - To go further: one or two lines | |
| 108 | + Between 300 and 600 words. Short snippets; a complete program only when | |
| 109 | + the user asks for one. | |
| 110 | + 4. A follow-up question ("and in Go?") refers to your previous answer: | |
| 111 | + answer the same need for the new language or tool. | |
| 112 | + | |
| 113 | + SAVING TO A FILE | |
| 114 | + - Never save unless the user asks to save, write or export to a file. | |
| 115 | + - When asked, call save_answer with the file name the user gave (or a short | |
| 116 | + name made from the subject, ending in .md). Do NOT write the tutorial | |
| 117 | + again: save_answer saves your previous answer by itself — call it alone, | |
| 118 | + with no text in your reply. | |
| 119 | + - When the request is "explain X and save it", write the tutorial in your | |
| 120 | + reply AND call save_answer in that same reply. | |
| 121 | + - If save_answer says the file exists, tell the user and ask for another | |
| 122 | + name. | |
| new file mode 100644 | |||
| @@ -0,0 +1,122 @@ | |||
| 1 | +# Tutor — answers questions about languages, shells and developer tools with | ||
| 2 | +# a MINI TUTORIAL; saves it to a file when asked. Built on the "prof" | ||
| 3 | +# configuration of ticket 152 (comment 1), adapted to the team: | ||
| 4 | +# - the Q4_K_M quantization the ticket asks for (8.1 GB instead of the | ||
| 5 | +# Q8_0's 12.9 GB) — the same file as the coder's, loaded once for both; | ||
| 6 | +# - no Rust lsp server and no docSearch over docs/: dev.team has no Rust | ||
| 7 | +# code and no docs/ folder; fetch_content covers the documentation; | ||
| 8 | +# - no sessions: an agent called through ask_agent runs with sessions off | ||
| 9 | +# (AGENT_SESSIONS=off), the coordinator keeps the conversation. | ||
| 10 | +# | ||
| 11 | +# cd dev.team/workspace && ../../mm -config ../team/agent.tutor.yaml # alone, with sessions | ||
| 12 | + | ||
| 13 | +provider: llmman | ||
| 14 | +model: hf.co/JetBrains/Mellum2-12B-A2.5B-Instruct-GGUF-Q4_K_M:Q4_K_M | ||
| 15 | +baseUrl: http://127.0.0.1:17434/v1 | ||
| 16 | +fallback: http://host.docker.internal:17434/v1 | ||
| 17 | + | ||
| 18 | +# mm's budget for compression; llmman served 131072 during the prof's | ||
| 19 | +# measurements. | ||
| 20 | +contextWindow: 32768 | ||
| 21 | + | ||
| 22 | +sampling: | ||
| 23 | + # Explanations, not code edits: a little more freedom than a coder's 0.2. | ||
| 24 | + temperature: 0.3 | ||
| 25 | + top_p: 0.9 | ||
| 26 | + # A long answer, maybe after one fetched page. | ||
| 27 | + max_tokens: 16384 | ||
| 28 | + parallel_tool_calls: false | ||
| 29 | + # No chat_template_kwargs: the Instruct template has no reasoning switch | ||
| 30 | + # (the prof's enable_thinking: false was for the Thinking model). | ||
| 31 | + | ||
| 32 | +firstTokenTimeout: 3m | ||
| 33 | +watchdogTimeout: 2m | ||
| 34 | +bashTimeout: 1m | ||
| 35 | + | ||
| 36 | +# A mini tutorial is one answer, maybe after one fetch, maybe one save. | ||
| 37 | +maxTurns: 8 | ||
| 38 | +maxOutput: 8000 | ||
| 39 | +previewLines: 10 | ||
| 40 | + | ||
| 41 | +# ─── Tools: the documentation, trying a snippet, saving on request ─────────── | ||
| 42 | + | ||
| 43 | +yolo: true | ||
| 44 | +# Kept from the prof (change of 2026-10-21): bash to try a snippet, files to | ||
| 45 | +# read the user's code when a question is about it. | ||
| 46 | +bashTool: true | ||
| 47 | +editTools: true | ||
| 48 | +planTool: false | ||
| 49 | +askUserTool: false | ||
| 50 | +fetchContentTool: true | ||
| 51 | +saveAnswerTool: true | ||
| 52 | +# The coordinator's hooks unload the models; no unload_model tool here. | ||
| 53 | +unloadModels: false | ||
| 54 | +skillsDir: no-skills | ||
| 55 | + | ||
| 56 | +agentsMd: | ||
| 57 | + enabled: false | ||
| 58 | + | ||
| 59 | +sessions: | ||
| 60 | + enabled: true | ||
| 61 | + dir: .mm/sessions | ||
| 62 | + | ||
| 63 | +context: | ||
| 64 | + enabled: true | ||
| 65 | + threshold: 60 | ||
| 66 | + keepLastTurns: 2 | ||
| 67 | + summaryMaxTokens: 1200 | ||
| 68 | + | ||
| 69 | +# ─── Go language server ────────────────────────────────────────────────────── | ||
| 70 | + | ||
| 71 | +# The `lsp` tool, for .go files: definition, references, hover, symbols, | ||
| 72 | +# diagnostics, rename. gopls must be on the PATH (go install | ||
| 73 | +# golang.org/x/tools/gopls@latest); not found = a start-up warning, no tool. | ||
| 74 | +lsp: | ||
| 75 | + servers: | ||
| 76 | + - name: gopls | ||
| 77 | + command: gopls | ||
| 78 | + extensions: [".go"] | ||
| 79 | + | ||
| 80 | +acp: | ||
| 81 | + name: tutor | ||
| 82 | + title: 📘 Tutor | ||
| 83 | + | ||
| 84 | +system: | | ||
| 85 | + You are Tutor. You answer questions about programming languages, shells and | ||
| 86 | + developer tools with a MINI TUTORIAL, in the language of the question. | ||
| 87 | + | ||
| 88 | + HOW TO ANSWER | ||
| 89 | + 1. Decide whether you need the documentation. Fetch ONE page with | ||
| 90 | + fetch_content only when the subject is a recent or niche tool (for | ||
| 91 | + example Nushell, a young framework), when the user names a version, or | ||
| 92 | + when you are not sure a command or an option exists. For well-known | ||
| 93 | + topics (Go, Rust, Python, Kotlin, Java basics) answer from what you know. | ||
| 94 | + 2. When the question names a file or code of the current directory, your | ||
| 95 | + FIRST action is read_file on it — before writing any word of the | ||
| 96 | + lesson. Then base the lesson on that real code and quote it as it is; | ||
| 97 | + never show "a typical" version of a file you were asked about. | ||
| 98 | + For a Go symbol of that code, `lsp` `hover` gives its signature and | ||
| 99 | + documentation, `definition` where it is declared; never `rename`. | ||
| 100 | + 3. Write the mini tutorial directly in your reply, in Markdown: | ||
| 101 | + - a title (#) | ||
| 102 | + - one sentence: what the reader will be able to do | ||
| 103 | + - Prerequisites: a short list | ||
| 104 | + - 3 to 6 numbered steps, each with a code block and, when it prints | ||
| 105 | + something, the expected output | ||
| 106 | + - Pitfalls: 2 or 3 short points | ||
| 107 | + - To go further: one or two lines | ||
| 108 | + Between 300 and 600 words. Short snippets; a complete program only when | ||
| 109 | + the user asks for one. | ||
| 110 | + 4. A follow-up question ("and in Go?") refers to your previous answer: | ||
| 111 | + answer the same need for the new language or tool. | ||
| 112 | + | ||
| 113 | + SAVING TO A FILE | ||
| 114 | + - Never save unless the user asks to save, write or export to a file. | ||
| 115 | + - When asked, call save_answer with the file name the user gave (or a short | ||
| 116 | + name made from the subject, ending in .md). Do NOT write the tutorial | ||
| 117 | + again: save_answer saves your previous answer by itself — call it alone, | ||
| 118 | + with no text in your reply. | ||
| 119 | + - When the request is "explain X and save it", write the tutorial in your | ||
| 120 | + reply AND call save_answer in that same reply. | ||
| 121 | + - If save_answer says the file exists, tell the user and ask for another | ||
| 122 | + name. | ||
added
dev.team/team/agent.yaml +193 -0 | new file mode 100644 | ||
| @@ -0,0 +1,193 @@ | ||
| 1 | +# Coordinator — the agent you talk to. It hands each request to the right | |
| 2 | +# member of the team with the built-in `ask_agent` tool, in order, and tells | |
| 3 | +# you what came back. It reads no file and writes no code itself. | |
| 4 | +# | |
| 5 | +# reformulator — turns a code request into a task brief; asks you when only | |
| 6 | +# you can decide (Gemma 4 12B) | |
| 7 | +# coder — fixes, adds, changes code; runs the tests (Mellum2 12B) | |
| 8 | +# reviewer — reviews the change, writes edge-case tests, verdict | |
| 9 | +# (Gemma 4 12B) | |
| 10 | +# tutor — explains, gives advice and mini tutorials (Mellum2 12B) | |
| 11 | +# | |
| 12 | +# Memory (32 GB MacBook Air): ONE model in memory at a time. The hooks at the | |
| 13 | +# bottom unload the coordinator's model right before a team member starts | |
| 14 | +# (preAsk) and the member's model right after it answers (postAsk); llmman | |
| 15 | +# reloads the coordinator's 4B by itself to read the answer. Peak: one 12B | |
| 16 | +# model, ~8 GB + its KV cache at 32k. | |
| 17 | +# | |
| 18 | +# This file lives in dev.team/team/, mounted READ-ONLY in the sandbox | |
| 19 | +# (sbxenv.yaml); the team works in dev.team/workspace/. Run it from there: | |
| 20 | +# | |
| 21 | +# sandbox: ./start-zed.sh (AGENT_CONFIG points here), then in workspace/: | |
| 22 | +# mm -tui | |
| 23 | +# host: cd dev.team/workspace | |
| 24 | +# ../../mm -config ../team/agent.yaml -tui | |
| 25 | + | |
| 26 | +# ─── Model and server ──────────────────────────────────────────────────────── | |
| 27 | + | |
| 28 | +provider: llmman | |
| 29 | + | |
| 30 | +# Qwen3.5 4B, 3.4 GB: picking an agent and copying a request does not need a | |
| 31 | +# 12B, and the small model reloads in seconds between hand-offs. | |
| 32 | +model: hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M | |
| 33 | + | |
| 34 | +baseUrl: http://127.0.0.1:17434/v1 | |
| 35 | +fallback: http://host.docker.internal:17434/v1 | |
| 36 | + | |
| 37 | +contextWindow: 32768 | |
| 38 | + | |
| 39 | +# The team. `description` is what the coordinator reads to choose. `yolo: | |
| 40 | +# true` = that member's commands and file writes run without asking once the | |
| 41 | +# hand-off is allowed; `askUser: true` = the reformulator's questions come up | |
| 42 | +# to you. Paths: relative to this file. | |
| 43 | +mmConfigs: | |
| 44 | + reformulator: | |
| 45 | + path: agent.reformulator.yaml | |
| 46 | + description: >- | |
| 47 | + Reformulator. Turns a request about code (a bug, a feature, a change) | |
| 48 | + into a precise task brief for the coder and the reviewer. May ask the | |
| 49 | + user a question. Writes no code. | |
| 50 | + yolo: true | |
| 51 | + askUser: true | |
| 52 | + coder: | |
| 53 | + path: agent.coder.yaml | |
| 54 | + description: >- | |
| 55 | + Coder. Implements a task brief in the project: fixes bugs, adds | |
| 56 | + features, changes code, runs the tests. Also fixes the code from a | |
| 57 | + reviewer's report. | |
| 58 | + yolo: true | |
| 59 | + askUser: false | |
| 60 | + reviewer: | |
| 61 | + path: agent.reviewer.yaml | |
| 62 | + description: >- | |
| 63 | + Reviewer and tester. Reviews a change against its task brief, runs the | |
| 64 | + tests, writes edge-case tests, answers VERDICT: PASS or FAIL. Never | |
| 65 | + changes the application's code. | |
| 66 | + yolo: true | |
| 67 | + askUser: false | |
| 68 | + tutor: | |
| 69 | + path: agent.tutor.yaml | |
| 70 | + description: >- | |
| 71 | + Tutor. Explains a concept, gives advice or a lesson, answers "how do I… | |
| 72 | + / what is… / why…" questions with a mini tutorial; can save it to a | |
| 73 | + file. Changes no code. | |
| 74 | + yolo: true | |
| 75 | + askUser: false | |
| 76 | + | |
| 77 | +# ─── Generation ────────────────────────────────────────────────────────────── | |
| 78 | + | |
| 79 | +sampling: | |
| 80 | + # Qwen's non-thinking values are 0.7 / 0.8 / 20; routing and copying a | |
| 81 | + # request word for word wants less: 0.3 (demos/team's lead). | |
| 82 | + temperature: 0.3 | |
| 83 | + top_p: 0.8 | |
| 84 | + top_k: 20 | |
| 85 | + max_tokens: 4096 | |
| 86 | + # One hand-off at a time: brief, THEN code, THEN review. | |
| 87 | + parallel_tool_calls: false | |
| 88 | + # The template's default is off; set it anyway, routing needs no thoughts. | |
| 89 | + chat_template_kwargs: | |
| 90 | + enable_thinking: false | |
| 91 | + | |
| 92 | +# ─── Timeouts ──────────────────────────────────────────────────────────────── | |
| 93 | + | |
| 94 | +# During ask_agent every event of the member counts as a sign of life: this | |
| 95 | +# covers the longest silence — a 12B loading after an unload. | |
| 96 | +watchdogTimeout: 5m | |
| 97 | +firstTokenTimeout: 3m | |
| 98 | + | |
| 99 | +# ─── Agent loop ────────────────────────────────────────────────────────────── | |
| 100 | + | |
| 101 | +# brief, code, review, at most one fix + review: 5 calls. Measured: with 8, | |
| 102 | +# on a failing feature the 4B re-asked the reviewer and called the coder four | |
| 103 | +# times; 6 leaves one spare call and stops that sooner. | |
| 104 | +maxTurns: 6 | |
| 105 | +maxOutput: 12000 | |
| 106 | +previewLines: 10 | |
| 107 | +displayCommands: true | |
| 108 | + | |
| 109 | +# ─── Tools ─────────────────────────────────────────────────────────────────── | |
| 110 | + | |
| 111 | +# true: the hand-offs run without asking. false = you approve each hand-off | |
| 112 | +# and see the prompt the coordinator wrote before it goes. | |
| 113 | +yolo: true | |
| 114 | + | |
| 115 | +# No tool but ask_agent: a coordinator with file tools starts doing the work | |
| 116 | +# itself (measured in demos/team). | |
| 117 | +bashTool: false | |
| 118 | +editTools: false | |
| 119 | +planTool: false | |
| 120 | +askUserTool: false | |
| 121 | +fetchContentTool: false | |
| 122 | +# The hooks unload; the model must not have to think about it. | |
| 123 | +unloadModels: false | |
| 124 | +skillsDir: no-skills | |
| 125 | + | |
| 126 | +agentsMd: | |
| 127 | + enabled: false | |
| 128 | + | |
| 129 | +# ─── Memory ────────────────────────────────────────────────────────────────── | |
| 130 | + | |
| 131 | +sessions: | |
| 132 | + enabled: true | |
| 133 | + dir: .mm/sessions | |
| 134 | + | |
| 135 | +context: | |
| 136 | + enabled: true | |
| 137 | + threshold: 60 | |
| 138 | + keepLastTurns: 2 | |
| 139 | + summaryMaxTokens: 1200 | |
| 140 | + | |
| 141 | +# ─── One model in memory at a time ─────────────────────────────────────────── | |
| 142 | + | |
| 143 | +hooks: | |
| 144 | + # onError: warn — an unload is a saving, not a check: the hand-off goes on. | |
| 145 | + preAsk: | |
| 146 | + - command: node "$MM_CONFIG_DIR/hooks/unload.js" self | |
| 147 | + timeout: 30s | |
| 148 | + onError: warn | |
| 149 | + postAsk: | |
| 150 | + - command: node "$MM_CONFIG_DIR/hooks/unload.js" asked | |
| 151 | + timeout: 30s | |
| 152 | + onError: warn | |
| 153 | + | |
| 154 | +# ─── Identity ──────────────────────────────────────────────────────────────── | |
| 155 | + | |
| 156 | +acp: | |
| 157 | + name: coordinator | |
| 158 | + title: 🧭 Coordinator | |
| 159 | + | |
| 160 | +system: | | |
| 161 | + You are Coordinator. You lead a team of four agents, reached with the | |
| 162 | + `ask_agent` tool: reformulator, coder, reviewer, tutor. You never write | |
| 163 | + code, read files or answer technical questions yourself. | |
| 164 | + | |
| 165 | + CHOOSE THE ROUTE FROM THE REQUEST | |
| 166 | + A. Code to write or change (fix a bug, add a feature, refactor, write | |
| 167 | + tests) — steps 1 to 4 in ONE answer, calling the next agent as soon as | |
| 168 | + the previous one has answered: | |
| 169 | + 1. ask_agent reformulator: "Write a task brief for this request: <the | |
| 170 | + user's request, complete, in their words>." | |
| 171 | + 2. ask_agent coder: "Implement this task brief: <the brief, complete>." | |
| 172 | + 3. ask_agent reviewer: "Review and test the change for this task brief: | |
| 173 | + <the brief, complete>. The coder's report: <the coder's answer>." | |
| 174 | + 4. Only if the reviewer's answer contains "VERDICT: FAIL": ask_agent | |
| 175 | + coder ONCE: "Fix the code. Reviewer's report: <the reviewer's | |
| 176 | + answer>." Then ask_agent reviewer again as in step 3. Do not loop | |
| 177 | + further. | |
| 178 | + B. A question, a lesson, advice, an explanation ("how do I…", "what is…", | |
| 179 | + "why…", "explain…", "teach me…") — ask_agent tutor with the user's | |
| 180 | + question, complete, in their words. | |
| 181 | + C. Only a review of existing code ("review", "check", "test this") — | |
| 182 | + ask_agent reviewer with the request. | |
| 183 | + | |
| 184 | + RULES | |
| 185 | + - One ask_agent call per step; wait for its result — it is that agent's | |
| 186 | + answer. Never answer in its place and never skip a step of route A. | |
| 187 | + - If a result starts with "[ask_agent:", or says an agent failed or hit | |
| 188 | + its limit, that step failed: tell the user and stop. Never re-ask an | |
| 189 | + agent with a new prompt. | |
| 190 | + - Then report to the user, in the language they wrote in, briefly: who did | |
| 191 | + what, the files changed (from the coder's and the reviewer's answers), | |
| 192 | + the tests and the verdict. For route B, give | |
| 193 | + the tutor's answer as it is. | |
| new file mode 100644 | |||
| @@ -0,0 +1,193 @@ | |||
| 1 | +# Coordinator — the agent you talk to. It hands each request to the right | ||
| 2 | +# member of the team with the built-in `ask_agent` tool, in order, and tells | ||
| 3 | +# you what came back. It reads no file and writes no code itself. | ||
| 4 | +# | ||
| 5 | +# reformulator — turns a code request into a task brief; asks you when only | ||
| 6 | +# you can decide (Gemma 4 12B) | ||
| 7 | +# coder — fixes, adds, changes code; runs the tests (Mellum2 12B) | ||
| 8 | +# reviewer — reviews the change, writes edge-case tests, verdict | ||
| 9 | +# (Gemma 4 12B) | ||
| 10 | +# tutor — explains, gives advice and mini tutorials (Mellum2 12B) | ||
| 11 | +# | ||
| 12 | +# Memory (32 GB MacBook Air): ONE model in memory at a time. The hooks at the | ||
| 13 | +# bottom unload the coordinator's model right before a team member starts | ||
| 14 | +# (preAsk) and the member's model right after it answers (postAsk); llmman | ||
| 15 | +# reloads the coordinator's 4B by itself to read the answer. Peak: one 12B | ||
| 16 | +# model, ~8 GB + its KV cache at 32k. | ||
| 17 | +# | ||
| 18 | +# This file lives in dev.team/team/, mounted READ-ONLY in the sandbox | ||
| 19 | +# (sbxenv.yaml); the team works in dev.team/workspace/. Run it from there: | ||
| 20 | +# | ||
| 21 | +# sandbox: ./start-zed.sh (AGENT_CONFIG points here), then in workspace/: | ||
| 22 | +# mm -tui | ||
| 23 | +# host: cd dev.team/workspace | ||
| 24 | +# ../../mm -config ../team/agent.yaml -tui | ||
| 25 | + | ||
| 26 | +# ─── Model and server ──────────────────────────────────────────────────────── | ||
| 27 | + | ||
| 28 | +provider: llmman | ||
| 29 | + | ||
| 30 | +# Qwen3.5 4B, 3.4 GB: picking an agent and copying a request does not need a | ||
| 31 | +# 12B, and the small model reloads in seconds between hand-offs. | ||
| 32 | +model: hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M | ||
| 33 | + | ||
| 34 | +baseUrl: http://127.0.0.1:17434/v1 | ||
| 35 | +fallback: http://host.docker.internal:17434/v1 | ||
| 36 | + | ||
| 37 | +contextWindow: 32768 | ||
| 38 | + | ||
| 39 | +# The team. `description` is what the coordinator reads to choose. `yolo: | ||
| 40 | +# true` = that member's commands and file writes run without asking once the | ||
| 41 | +# hand-off is allowed; `askUser: true` = the reformulator's questions come up | ||
| 42 | +# to you. Paths: relative to this file. | ||
| 43 | +mmConfigs: | ||
| 44 | + reformulator: | ||
| 45 | + path: agent.reformulator.yaml | ||
| 46 | + description: >- | ||
| 47 | + Reformulator. Turns a request about code (a bug, a feature, a change) | ||
| 48 | + into a precise task brief for the coder and the reviewer. May ask the | ||
| 49 | + user a question. Writes no code. | ||
| 50 | + yolo: true | ||
| 51 | + askUser: true | ||
| 52 | + coder: | ||
| 53 | + path: agent.coder.yaml | ||
| 54 | + description: >- | ||
| 55 | + Coder. Implements a task brief in the project: fixes bugs, adds | ||
| 56 | + features, changes code, runs the tests. Also fixes the code from a | ||
| 57 | + reviewer's report. | ||
| 58 | + yolo: true | ||
| 59 | + askUser: false | ||
| 60 | + reviewer: | ||
| 61 | + path: agent.reviewer.yaml | ||
| 62 | + description: >- | ||
| 63 | + Reviewer and tester. Reviews a change against its task brief, runs the | ||
| 64 | + tests, writes edge-case tests, answers VERDICT: PASS or FAIL. Never | ||
| 65 | + changes the application's code. | ||
| 66 | + yolo: true | ||
| 67 | + askUser: false | ||
| 68 | + tutor: | ||
| 69 | + path: agent.tutor.yaml | ||
| 70 | + description: >- | ||
| 71 | + Tutor. Explains a concept, gives advice or a lesson, answers "how do I… | ||
| 72 | + / what is… / why…" questions with a mini tutorial; can save it to a | ||
| 73 | + file. Changes no code. | ||
| 74 | + yolo: true | ||
| 75 | + askUser: false | ||
| 76 | + | ||
| 77 | +# ─── Generation ────────────────────────────────────────────────────────────── | ||
| 78 | + | ||
| 79 | +sampling: | ||
| 80 | + # Qwen's non-thinking values are 0.7 / 0.8 / 20; routing and copying a | ||
| 81 | + # request word for word wants less: 0.3 (demos/team's lead). | ||
| 82 | + temperature: 0.3 | ||
| 83 | + top_p: 0.8 | ||
| 84 | + top_k: 20 | ||
| 85 | + max_tokens: 4096 | ||
| 86 | + # One hand-off at a time: brief, THEN code, THEN review. | ||
| 87 | + parallel_tool_calls: false | ||
| 88 | + # The template's default is off; set it anyway, routing needs no thoughts. | ||
| 89 | + chat_template_kwargs: | ||
| 90 | + enable_thinking: false | ||
| 91 | + | ||
| 92 | +# ─── Timeouts ──────────────────────────────────────────────────────────────── | ||
| 93 | + | ||
| 94 | +# During ask_agent every event of the member counts as a sign of life: this | ||
| 95 | +# covers the longest silence — a 12B loading after an unload. | ||
| 96 | +watchdogTimeout: 5m | ||
| 97 | +firstTokenTimeout: 3m | ||
| 98 | + | ||
| 99 | +# ─── Agent loop ────────────────────────────────────────────────────────────── | ||
| 100 | + | ||
| 101 | +# brief, code, review, at most one fix + review: 5 calls. Measured: with 8, | ||
| 102 | +# on a failing feature the 4B re-asked the reviewer and called the coder four | ||
| 103 | +# times; 6 leaves one spare call and stops that sooner. | ||
| 104 | +maxTurns: 6 | ||
| 105 | +maxOutput: 12000 | ||
| 106 | +previewLines: 10 | ||
| 107 | +displayCommands: true | ||
| 108 | + | ||
| 109 | +# ─── Tools ─────────────────────────────────────────────────────────────────── | ||
| 110 | + | ||
| 111 | +# true: the hand-offs run without asking. false = you approve each hand-off | ||
| 112 | +# and see the prompt the coordinator wrote before it goes. | ||
| 113 | +yolo: true | ||
| 114 | + | ||
| 115 | +# No tool but ask_agent: a coordinator with file tools starts doing the work | ||
| 116 | +# itself (measured in demos/team). | ||
| 117 | +bashTool: false | ||
| 118 | +editTools: false | ||
| 119 | +planTool: false | ||
| 120 | +askUserTool: false | ||
| 121 | +fetchContentTool: false | ||
| 122 | +# The hooks unload; the model must not have to think about it. | ||
| 123 | +unloadModels: false | ||
| 124 | +skillsDir: no-skills | ||
| 125 | + | ||
| 126 | +agentsMd: | ||
| 127 | + enabled: false | ||
| 128 | + | ||
| 129 | +# ─── Memory ────────────────────────────────────────────────────────────────── | ||
| 130 | + | ||
| 131 | +sessions: | ||
| 132 | + enabled: true | ||
| 133 | + dir: .mm/sessions | ||
| 134 | + | ||
| 135 | +context: | ||
| 136 | + enabled: true | ||
| 137 | + threshold: 60 | ||
| 138 | + keepLastTurns: 2 | ||
| 139 | + summaryMaxTokens: 1200 | ||
| 140 | + | ||
| 141 | +# ─── One model in memory at a time ─────────────────────────────────────────── | ||
| 142 | + | ||
| 143 | +hooks: | ||
| 144 | + # onError: warn — an unload is a saving, not a check: the hand-off goes on. | ||
| 145 | + preAsk: | ||
| 146 | + - command: node "$MM_CONFIG_DIR/hooks/unload.js" self | ||
| 147 | + timeout: 30s | ||
| 148 | + onError: warn | ||
| 149 | + postAsk: | ||
| 150 | + - command: node "$MM_CONFIG_DIR/hooks/unload.js" asked | ||
| 151 | + timeout: 30s | ||
| 152 | + onError: warn | ||
| 153 | + | ||
| 154 | +# ─── Identity ──────────────────────────────────────────────────────────────── | ||
| 155 | + | ||
| 156 | +acp: | ||
| 157 | + name: coordinator | ||
| 158 | + title: 🧭 Coordinator | ||
| 159 | + | ||
| 160 | +system: | | ||
| 161 | + You are Coordinator. You lead a team of four agents, reached with the | ||
| 162 | + `ask_agent` tool: reformulator, coder, reviewer, tutor. You never write | ||
| 163 | + code, read files or answer technical questions yourself. | ||
| 164 | + | ||
| 165 | + CHOOSE THE ROUTE FROM THE REQUEST | ||
| 166 | + A. Code to write or change (fix a bug, add a feature, refactor, write | ||
| 167 | + tests) — steps 1 to 4 in ONE answer, calling the next agent as soon as | ||
| 168 | + the previous one has answered: | ||
| 169 | + 1. ask_agent reformulator: "Write a task brief for this request: <the | ||
| 170 | + user's request, complete, in their words>." | ||
| 171 | + 2. ask_agent coder: "Implement this task brief: <the brief, complete>." | ||
| 172 | + 3. ask_agent reviewer: "Review and test the change for this task brief: | ||
| 173 | + <the brief, complete>. The coder's report: <the coder's answer>." | ||
| 174 | + 4. Only if the reviewer's answer contains "VERDICT: FAIL": ask_agent | ||
| 175 | + coder ONCE: "Fix the code. Reviewer's report: <the reviewer's | ||
| 176 | + answer>." Then ask_agent reviewer again as in step 3. Do not loop | ||
| 177 | + further. | ||
| 178 | + B. A question, a lesson, advice, an explanation ("how do I…", "what is…", | ||
| 179 | + "why…", "explain…", "teach me…") — ask_agent tutor with the user's | ||
| 180 | + question, complete, in their words. | ||
| 181 | + C. Only a review of existing code ("review", "check", "test this") — | ||
| 182 | + ask_agent reviewer with the request. | ||
| 183 | + | ||
| 184 | + RULES | ||
| 185 | + - One ask_agent call per step; wait for its result — it is that agent's | ||
| 186 | + answer. Never answer in its place and never skip a step of route A. | ||
| 187 | + - If a result starts with "[ask_agent:", or says an agent failed or hit | ||
| 188 | + its limit, that step failed: tell the user and stop. Never re-ask an | ||
| 189 | + agent with a new prompt. | ||
| 190 | + - Then report to the user, in the language they wrote in, briefly: who did | ||
| 191 | + what, the files changed (from the coder's and the reviewer's answers), | ||
| 192 | + the tests and the verdict. For route B, give | ||
| 193 | + the tutor's answer as it is. | ||
added
dev.team/team/hooks/gofmt.js +30 -0 | new file mode 100644 | ||
| @@ -0,0 +1,30 @@ | ||
| 1 | +#!/usr/bin/env node | |
| 2 | +// postToolCall hook of the coder (write_file, edit_file): formats the Go file | |
| 3 | +// the tool just wrote, with `gofmt -w`. | |
| 4 | +// | |
| 5 | +// Why a hook: the coder's prompt asks for gofmt, and Mellum2 skipped it in | |
| 6 | +// every measured run (2 out of 2 left the files unformatted). A hook makes it | |
| 7 | +// certain and costs the model nothing. | |
| 8 | +// | |
| 9 | +// Input: {"cwd": "...", "tool": {"name": "write_file", "input": {"path": "..."}}}. | |
| 10 | +// Prints nothing when the file is formatted (or is not Go). When gofmt fails, | |
| 11 | +// the file does not parse: its error goes back to the model as context, so | |
| 12 | +// the next step can fix it. | |
| 13 | + | |
| 14 | +const fs = require("fs"); | |
| 15 | +const path = require("path"); | |
| 16 | +const { execFileSync } = require("child_process"); | |
| 17 | + | |
| 18 | +const input = JSON.parse(fs.readFileSync(0, "utf8")); | |
| 19 | +const file = input.tool && input.tool.input && input.tool.input.path; | |
| 20 | +if (!file || !file.endsWith(".go")) process.exit(0); | |
| 21 | + | |
| 22 | +const full = path.resolve(input.cwd || ".", file); | |
| 23 | +if (!fs.existsSync(full)) process.exit(0); // the tool failed: nothing written | |
| 24 | + | |
| 25 | +try { | |
| 26 | + execFileSync("gofmt", ["-w", full], { stdio: ["ignore", "ignore", "pipe"] }); | |
| 27 | +} catch (err) { | |
| 28 | + const reason = err.code === "ENOENT" ? "gofmt is not on the PATH" : String(err.stderr || err.message).trim(); | |
| 29 | + console.log(JSON.stringify({ context: `gofmt could not format ${file}: ${reason}` })); | |
| 30 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | +#!/usr/bin/env node | ||
| 2 | +// postToolCall hook of the coder (write_file, edit_file): formats the Go file | ||
| 3 | +// the tool just wrote, with `gofmt -w`. | ||
| 4 | +// | ||
| 5 | +// Why a hook: the coder's prompt asks for gofmt, and Mellum2 skipped it in | ||
| 6 | +// every measured run (2 out of 2 left the files unformatted). A hook makes it | ||
| 7 | +// certain and costs the model nothing. | ||
| 8 | +// | ||
| 9 | +// Input: {"cwd": "...", "tool": {"name": "write_file", "input": {"path": "..."}}}. | ||
| 10 | +// Prints nothing when the file is formatted (or is not Go). When gofmt fails, | ||
| 11 | +// the file does not parse: its error goes back to the model as context, so | ||
| 12 | +// the next step can fix it. | ||
| 13 | + | ||
| 14 | +const fs = require("fs"); | ||
| 15 | +const path = require("path"); | ||
| 16 | +const { execFileSync } = require("child_process"); | ||
| 17 | + | ||
| 18 | +const input = JSON.parse(fs.readFileSync(0, "utf8")); | ||
| 19 | +const file = input.tool && input.tool.input && input.tool.input.path; | ||
| 20 | +if (!file || !file.endsWith(".go")) process.exit(0); | ||
| 21 | + | ||
| 22 | +const full = path.resolve(input.cwd || ".", file); | ||
| 23 | +if (!fs.existsSync(full)) process.exit(0); // the tool failed: nothing written | ||
| 24 | + | ||
| 25 | +try { | ||
| 26 | + execFileSync("gofmt", ["-w", full], { stdio: ["ignore", "ignore", "pipe"] }); | ||
| 27 | +} catch (err) { | ||
| 28 | + const reason = err.code === "ENOENT" ? "gofmt is not on the PATH" : String(err.stderr || err.message).trim(); | ||
| 29 | + console.log(JSON.stringify({ context: `gofmt could not format ${file}: ${reason}` })); | ||
| 30 | +} | ||
added
dev.team/team/hooks/unload.js +58 -0 | new file mode 100644 | ||
| @@ -0,0 +1,58 @@ | ||
| 1 | +#!/usr/bin/env node | |
| 2 | +// preAsk / postAsk hook: unloads one model so that two models are never in | |
| 3 | +// memory together during a hand-off. | |
| 4 | +// | |
| 5 | +// node unload.js self preAsk: the ASKING agent's own model, right before | |
| 6 | +// mm starts the asked agent. Only mm can do it at | |
| 7 | +// that moment: the model has just decided to call | |
| 8 | +// ask_agent, and it is needed again only to read the | |
| 9 | +// answer — the server reloads it then by itself. The | |
| 10 | +// model cannot do it (unload_model on its own model | |
| 11 | +// lasts until its next step). | |
| 12 | +// node unload.js asked postAsk: the ASKED agent's model, once it has | |
| 13 | +// answered and before the asking agent reads the | |
| 14 | +// answer — so the asker's model reloads alone. | |
| 15 | +// | |
| 16 | +// Input: {"model": "llmman/<model>", "ask": {"agentModel": "llmman/<model>"}, | |
| 17 | +// ...}. Server: $LLMMAN_URL, else llmman's default address, else the one a | |
| 18 | +// Docker sandbox reaches the host by. Prints nothing: the hand-off goes on | |
| 19 | +// whatever happens (onError: warn in agent.yaml), an unload is a saving, not | |
| 20 | +// a check. | |
| 21 | + | |
| 22 | +const fs = require("fs"); | |
| 23 | + | |
| 24 | +const input = JSON.parse(fs.readFileSync(0, "utf8")); | |
| 25 | +const which = process.argv[2]; | |
| 26 | +const ref = which === "asked" ? input.ask && input.ask.agentModel : input.model; | |
| 27 | +if (!ref) { | |
| 28 | + console.error(`unload.js ${which}: no model in the input`); | |
| 29 | + process.exit(1); | |
| 30 | +} | |
| 31 | +const model = ref.replace(/^[^/]+\//, ""); // drop the "llmman/" provider prefix | |
| 32 | + | |
| 33 | +const servers = process.env.LLMMAN_URL | |
| 34 | + ? [process.env.LLMMAN_URL] | |
| 35 | + : ["http://127.0.0.1:17434", "http://host.docker.internal:17434"]; | |
| 36 | + | |
| 37 | +async function unload() { | |
| 38 | + for (const server of servers) { | |
| 39 | + try { | |
| 40 | + const resp = await fetch(server + "/api/generate", { | |
| 41 | + method: "POST", | |
| 42 | + headers: { "Content-Type": "application/json" }, | |
| 43 | + body: JSON.stringify({ model, keep_alive: 0 }), | |
| 44 | + signal: AbortSignal.timeout(20_000), | |
| 45 | + }); | |
| 46 | + const reply = await resp.json(); | |
| 47 | + if (reply.done_reason === "unload") return; | |
| 48 | + throw new Error(`${server}: not confirmed: ${JSON.stringify(reply)}`); | |
| 49 | + } catch (err) { | |
| 50 | + if (server === servers[servers.length - 1]) throw err; | |
| 51 | + } | |
| 52 | + } | |
| 53 | +} | |
| 54 | + | |
| 55 | +unload().catch((err) => { | |
| 56 | + console.error(`could not unload ${model}: ${err.message}`); | |
| 57 | + process.exit(1); | |
| 58 | +}); | |
| new file mode 100644 | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | +#!/usr/bin/env node | ||
| 2 | +// preAsk / postAsk hook: unloads one model so that two models are never in | ||
| 3 | +// memory together during a hand-off. | ||
| 4 | +// | ||
| 5 | +// node unload.js self preAsk: the ASKING agent's own model, right before | ||
| 6 | +// mm starts the asked agent. Only mm can do it at | ||
| 7 | +// that moment: the model has just decided to call | ||
| 8 | +// ask_agent, and it is needed again only to read the | ||
| 9 | +// answer — the server reloads it then by itself. The | ||
| 10 | +// model cannot do it (unload_model on its own model | ||
| 11 | +// lasts until its next step). | ||
| 12 | +// node unload.js asked postAsk: the ASKED agent's model, once it has | ||
| 13 | +// answered and before the asking agent reads the | ||
| 14 | +// answer — so the asker's model reloads alone. | ||
| 15 | +// | ||
| 16 | +// Input: {"model": "llmman/<model>", "ask": {"agentModel": "llmman/<model>"}, | ||
| 17 | +// ...}. Server: $LLMMAN_URL, else llmman's default address, else the one a | ||
| 18 | +// Docker sandbox reaches the host by. Prints nothing: the hand-off goes on | ||
| 19 | +// whatever happens (onError: warn in agent.yaml), an unload is a saving, not | ||
| 20 | +// a check. | ||
| 21 | + | ||
| 22 | +const fs = require("fs"); | ||
| 23 | + | ||
| 24 | +const input = JSON.parse(fs.readFileSync(0, "utf8")); | ||
| 25 | +const which = process.argv[2]; | ||
| 26 | +const ref = which === "asked" ? input.ask && input.ask.agentModel : input.model; | ||
| 27 | +if (!ref) { | ||
| 28 | + console.error(`unload.js ${which}: no model in the input`); | ||
| 29 | + process.exit(1); | ||
| 30 | +} | ||
| 31 | +const model = ref.replace(/^[^/]+\//, ""); // drop the "llmman/" provider prefix | ||
| 32 | + | ||
| 33 | +const servers = process.env.LLMMAN_URL | ||
| 34 | + ? [process.env.LLMMAN_URL] | ||
| 35 | + : ["http://127.0.0.1:17434", "http://host.docker.internal:17434"]; | ||
| 36 | + | ||
| 37 | +async function unload() { | ||
| 38 | + for (const server of servers) { | ||
| 39 | + try { | ||
| 40 | + const resp = await fetch(server + "/api/generate", { | ||
| 41 | + method: "POST", | ||
| 42 | + headers: { "Content-Type": "application/json" }, | ||
| 43 | + body: JSON.stringify({ model, keep_alive: 0 }), | ||
| 44 | + signal: AbortSignal.timeout(20_000), | ||
| 45 | + }); | ||
| 46 | + const reply = await resp.json(); | ||
| 47 | + if (reply.done_reason === "unload") return; | ||
| 48 | + throw new Error(`${server}: not confirmed: ${JSON.stringify(reply)}`); | ||
| 49 | + } catch (err) { | ||
| 50 | + if (server === servers[servers.length - 1]) throw err; | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | +} | ||
| 54 | + | ||
| 55 | +unload().catch((err) => { | ||
| 56 | + console.error(`could not unload ${model}: ${err.message}`); | ||
| 57 | + process.exit(1); | ||
| 58 | +}); | ||
added
dev.team/workspace/.gitkeep +0 -0 | new file mode 100644 |
| new file mode 100644 |