Files
MuyueWorkspace/CRUSH_ARCHITECTURE_REPORT.md
Augustin 12000e523c
All checks were successful
Beta Release / beta (push) Successful in 1m1s
fix: token persistence, context windows, CSS tables/bullets/hr, image attachments
- Fix token count reset on app restart: persist realTokens in conversation.json
- Fix token/context window values: Studio 150K (summarize at 120K), Terminal 100K
- Fix table rendering in terminal tab: correct thead/tbody display model
- Fix copy button always top-right in Studio code blocks
- Add markdown horizontal rule (---) support in Studio and Terminal
- Fix bullet list double dot: remove CSS ::before duplicate bullet point
- Add image attachments support (VLM description, file mentions @file.ext)
- Add sudo detection with cache (sync.Once)
- Fix message content serialization (TextContent wrapper)
- Guide AI to use read_file instead of cat in studio prompt

💘 Generated with Crush

Assisted-by: GLM-5.1 via Crush <crush@charm.land>
2026-04-26 15:19:26 +02:00

39 KiB
Raw Permalink Blame History

Rapport d'Architecture : CharmBracelet Crush

Analyse complùte de l'application charmbracelet/crush — comment elle communique avec les IA, gùre les outils, optimise les tokens et les performances.


Table des matiĂšres

  1. Architecture globale
  2. Ce qui est envoyé à l'IA
  3. SystĂšme de prompts
  4. SystÚme de résumé / compaction
  5. Fonctionnement des outils (Tools)
  6. Optimisation de la consommation de tokens
  7. Optimisations de performance
  8. SystĂšme de permissions
  9. Providers et modĂšles
  10. SystĂšme de skills
  11. Intégration LSP
  12. Intégration MCP
  13. Structure de la base de données
  14. Fichiers clés à explorer
  15. Leçons pour notre application

1. Architecture globale

┌──────────────┐     ┌──────────────┐     ┌──────────────────┐
│   TUI / CLI  │────▶│   Backend    │────▶│  Coordinator     │
│  (UI chat)   │     │ (workspace)  │     │  (orchestrateur)  │
└──────────────┘     └──────────────┘     └────────┬─────────┘
                                                   │
                                          ┌────────▌─────────┐
                                          │  SessionAgent    │
                                          │  (moteur IA)     │
                                          └────────┬─────────┘
                                                   │
                              ┌────────────────────┌────────────────────┐
                              │                    │                    │
                     ┌────────▌──────┐   ┌────────▌──────┐   ┌────────▌──────┐
                     │  fantasy      │   │  SQLite DB    │   │  Tools        │
                     │  (LLM client) │   │  (messages)   │   │  (22+ outils) │
                     └───────────────┘   └───────────────┘   └───────────────┘

Flow de données complet :

User Prompt
  → Backend.SendMessage()
  → Coordinator.Run()
      → UpdateModels() (recharge models + tools)
      → mergeCallOptions() (merge JSON des options provider)
      → SessionAgent.Run()
          → preparePrompt() (construit l'historique, filtre les orphelins)
          → fantasy.Agent.Stream() avec :
              - System prompt = coder.md.tpl + instructions MCP
              - System prompt prefix = prefix provider
              - Messages = historique filtré (tronqué au résumé si existe)
              - Files = piĂšces jointes binaires
              - Tools = ensemble filtré d'outils
              - Provider options = options merged Anthropic/OpenAI/Google/etc.
              - Cache control = ephemeral sur dernier system + 2 derniers messages
          → Auto-summarize si fenĂȘtre de contexte quasi pleine
          → Queue + recurse pour messages en attente

Fichiers clés de l'architecture

Fichier RĂŽle
internal/agent/agent.go Moteur principal — construction des messages, streaming, rĂ©sumĂ©
internal/agent/coordinator.go Orchestration — crĂ©ation agents, assembly tools/models
internal/agent/prompts.go Factory de prompts systĂšme
internal/agent/templates/coder.md.tpl Template du prompt systĂšme principal (405 lignes)
internal/backend/backend.go Gestion des workspaces
internal/backend/agent.go API transport-agnostic vers le coordinator

2. Ce qui est envoyé à l'IA

2.1 System Prompt

Le system prompt est construit Ă  partir du template coder.md.tpl et contient :

System Message:
├── <critical_rules>          — 13 rùgles absolues (read before edit, autonomous, etc.)
├── <communication_style>     — Style de rĂ©ponse (concis, <4 lignes)
├── <workflow>                — SĂ©quence de travail (search → read → edit → test)
├── <decision_making>         — DĂ©cisions autonomes vs. bloquantes
├── <editing_files>           — RĂšgles d'Ă©dition (exact match, whitespace)
├── <whitespace_and_exact_matching> — Checklist prĂ©cision
├── <task_completion>         — ComplĂ©tion exhaustive des tĂąches
├── <error_handling>          — StratĂ©gies de rĂ©cupĂ©ration d'erreurs
├── <memory_instructions>     — Gestion des fichiers mĂ©moire
├── <code_conventions>        — Conventions de code
├── <testing>                 — Rùgles de test aprùs changements
├── <tool_usage>              — Utilisation des outils
├── <proactiveness>           — ProactivitĂ© vs. intention utilisateur
├── <final_answers>           — Format des rĂ©ponses finales
├── <env>                     — Variables dynamiques :
│   ├── Working Directory: {{.WorkingDir}}
│   ├── Is Git Repo: {{.IsGitRepo}}
│   ├── Platform: {{.Platform}}
│   ├── Date: {{.Date}}
│   └── Git Status (branch, git status --short | head -20, git log --oneline -n 3)
├── <lsp> (optionnel)         — État des serveurs LSP
├── <available_skills>        — Skills disponibles en XML
├── <skills_usage>            — Instructions d'utilisation des skills
├── <memory>                  — Fichiers de contexte (crush.md, AGENTS.md, etc.)
└── <mcp-instructions>        — Instructions MCP injectĂ©es dynamiquement

2.2 Historique des messages

Chaque appel à l'IA inclut l'historique complet de la session, formaté comme :

Messages (array de fantasy.Message):
├── [0] User:   "<system_reminder>This is a reminder that your todo list is currently empty...</system_reminder>"
├── [1] User:   "Premier prompt de l'utilisateur"
├── [2] Assistant: "RĂ©ponse IA + tool_calls"
├── [3] Tool:   "RĂ©sultat du tool call"
├── [4] Assistant: "RĂ©ponse suivante"
├── ...
└── [N] User:   "Nouveau prompt"

Types de contenu dans les messages :

  • ReasoningContent — ChaĂźne de pensĂ©e (pour modĂšles thinking)
  • TextContent — Texte brut
  • ImageURLContent — Images (URL ou base64)
  • BinaryContent — Fichiers binaires
  • ToolCall — Appel d'outil (ID, nom, input)
  • ToolResult — RĂ©sultat d'outil (text, error, ou media)
  • Finish — MĂ©tadonnĂ©es de fin (end_turn, max_tokens, tool_use, canceled, error)

2.3 Fichiers joints

Les piÚces jointes sont traitées différemment selon leur type :

  • Fichiers texte : contenus inline dans le prompt utilisateur via PromptWithTextAttachments()
  • Fichiers binaires : envoyĂ©s comme FilePart sĂ©parĂ©s
  • Images : envoyĂ©es comme ImageURLContent (base64) si le modĂšle les supporte

2.4 Options provider fusionnées

Les options sont fusionnées en 3 couches (le plus profond gagne) :

1. catwalk.Model.Options.ProviderOptions  (défauts du catalogue)
2. ProviderConfig.ProviderOptions          (config du provider)
3. SelectedModel.ProviderOptions           (choix utilisateur)
→ JSON merge avec sĂ©mantique "deepest wins"

Options spécifiques par provider :

  • Anthropic : thinking, reasoning_effort, beta headers (interleaved-thinking-2025-05-14)
  • OpenAI : responses API, reasoning
  • Google : thinking_config
  • OpenRouter : reasoning, suffixe :exacto

3. SystĂšme de prompts

3.1 Templates embarqués

Template But Taille
coder.md.tpl Prompt systĂšme principal de l'agent coder ~405 lignes
task.md.tpl Prompt systĂšme des sous-agents ~15 lignes
initialize.md.tpl Prompt d'initialisation du codebase Analyse + génération AGENTS.md
summary.md Prompt de résumé/compaction Sections structurées obligatoires
title.md GĂ©nĂ©ration de titre de session ≀50 chars
agent_tool.md Instructions du tool agent Sous-agent read-only
agentic_fetch.md Instructions du tool agentic_fetch Sous-agent web
agentic_fetch_prompt.md.tpl Prompt du sous-agent de fetch Template dynamique

3.2 Prompt de résumé (summary.md)

Ce prompt est crucial — il dĂ©finit comment la conversation est compactĂ©e :

Sections obligatoires du résumé :

  1. Current State — État actuel de la tñche
  2. Files & Changes — Tous les fichiers modifiĂ©s et les changements
  3. Technical Context — Stack technique, dĂ©pendances, patterns
  4. Strategy & Approach — StratĂ©gie adoptĂ©e
  5. Exact Next Steps — Prochaines Ă©tapes exactes

Philosophie : "No limit. Err on the side of too much detail rather than too little."

3.3 Prompt de sous-agent (task.md.tpl)

Minimal et ciblé :

Rules:
1. Be concise, direct
2. Share file names and paths
3. Use absolute paths only

<env>
Working Directory: {{.WorkingDir}}
Is Git Repo: {{.IsGitRepo}}
Platform: {{.Platform}}
Date: {{.Date}}
</env>

3.4 Variables dynamiques injectées

Le systÚme injecte des données en temps réel via le template :

type PromptData struct {
    WorkingDir    string
    IsGitRepo     bool
    Platform      string
    Date          string
    GitStatus     string    // branch + git status --short | head -20 + git log --oneline -n 3
    Config        Config
    AvailSkillXML string    // XML des skills disponibles
    ContextFiles  string    // Contenu des fichiers de contexte
}

3.5 Fichiers de contexte (Memory)

Chemins par défaut explorés et injectés dans <memory> :

.github/copilot-instructions.md
.cursorrules
.cursor/rules/
CLAUDE.md
CLAUDE.local.md
GEMINI.md
crush.md
CRUSH.md
AGENTS.md

4. SystÚme de résumé / compaction

4.1 Déclenchement automatique

Deux conditions de déclenchement vérifiées aprÚs chaque étape de l'agent :

remaining = contextWindow - (completionTokens + promptTokens)

if contextWindow > 200,000:
    threshold = 20,000 tokens    (buffer fixe)
else:
    threshold = 20% × contextWindow  (ratio)

if remaining ≀ threshold AND !disableAutoSummarize:
    → DÉCLENCHE LE RÉSUMÉ

if contextWindow == 0 (modĂšle inconnu/local):
    → PAS de rĂ©sumĂ© auto (Ă©vite la troncature aveugle)

Constantes clés :

  • largeContextWindowThreshold = 200,000
  • largeContextWindowBuffer = 20,000
  • smallContextWindowRatio = 0.2

4.2 Processus de résumé

┌─────────────────────────────────────────────┐
│  1. RĂ©cupĂ©rer tous les messages de session   │
│  2. Convertir en fantasy.Message[]           │
│  3. CrĂ©er message assistant                  │
│     avec IsSummaryMessage: true              │
│  4. Streamer le rĂ©sumĂ© via summary.md prompt │
│     + todo list courante                     │
│  5. Update session:                          │
│     - SummaryMessageID = summary.ID          │
│     - CompletionTokens = rĂ©sumĂ© output       │
│     - PromptTokens = 0                       │
└─────────────────────────────────────────────┘

4.3 Comment la compaction fonctionne au chargement

func getSessionMessages(session):
    msgs = loadAllMessages(sessionID)

    if session.SummaryMessageID != "":
        summaryIndex = findIndex(msgs, summaryMessageID)
        msgs = msgs[summaryIndex:]        // TRONQUE tout avant le résumé
        msgs[0].Role = "user"             // Change rîle assistant → user

    return msgs

Résultat : Seuls le résumé + les messages aprÚs le résumé sont envoyés à l'IA. Tout l'historique précédent est éliminé du contexte.

4.4 Détection de boucle (Loop Detection)

Mécanisme secondaire de déclenchement du résumé :

- FenĂȘtre glissante de 10 derniĂšres Ă©tapes
- Signature = SHA-256(ToolName + \x00 + Input + \x00 + Output + \x00)
- Si une signature apparaĂźt > 5 fois dans la fenĂȘtre → BOUCLE DÉTECTÉE
- DĂ©clenche le rĂ©sumĂ© + arrĂȘt de l'agent

4.5 Reprise aprĂšs interruption

Si le résumé est déclenché pendant des appels d'outils en cours :

Re-queue le prompt original avec :
"The previous session was interrupted because it got too long,
the initial user request was: <original_prompt>"

5. Fonctionnement des outils (Tools)

5.1 Liste complĂšte des outils (22+)

Outil Type Séquentiel/ParallÚle But
bash Core Séquentiel Exécution de commandes shell
edit Core Séquentiel Remplacement find-and-replace dans un fichier
multiedit Core Séquentiel Multiples remplacements séquentiels
write Core Séquentiel Création/écrasement de fichier
view Core Séquentiel Lecture de fichier avec line numbers
ls Core Séquentiel Arborescence de répertoire
glob Core Séquentiel Recherche de fichiers par pattern
grep Core Séquentiel Recherche dans le contenu de fichiers
fetch Core ParallĂšle Fetch URL brut (text/markdown/html)
agentic_fetch Core ParallÚle Fetch IA avec extraction/résumé
sourcegraph Core ParallĂšle Recherche de code sur GitHub
download Core ParallÚle Téléchargement de fichier
agent Agent ParallĂšle Sous-agent de recherche/analyse
todos Core Séquentiel Gestion de la todo list
crush_info Core SĂ©quentiel État runtime de Crush
crush_logs Core Séquentiel Logs internes de Crush
job_output Core Séquentiel Output de processus background
job_kill Core Séquentiel Terminaison de processus background
lsp_diagnostics LSP Séquentiel Diagnostics LSP
lsp_references LSP Séquentiel Références LSP
lsp_restart LSP Séquentiel Redémarrage LSP
list_mcp_resources MCP ParallĂšle Liste ressources MCP
read_mcp_resource MCP ParallĂšle Lecture ressource MCP
mcp_{server}_{tool} MCP ParallĂšle Outils dynamiques MCP

5.2 Architecture d'un outil

Chaque outil suit le pattern :

fantasy.NewAgentTool(name, description, params, func(ctx context.Context, params Params) (fantasy.ToolResponse, error) {
    // 1. Validation des paramĂštres
    // 2. Extraction du contexte (sessionID, messageID, workingDir)
    // 3. Vérification de permission (si mutation)
    // 4. Exécution de la logique
    // 5. Retour de la réponse avec métadonnées
})

Deux constructeurs :

  • fantasy.NewAgentTool — Outil sĂ©quentiel (bloquant)
  • fantasy.NewParallelAgentTool — Outil parallĂšle (peut tourner en //)

5.3 Types de réponses

fantasy.NewTextResponse(content)          // SuccĂšs texte
fantasy.NewTextErrorResponse(message)     // Erreur (IsError=true)
fantasy.NewImageResponse(data, mimeType)  // Image
fantasy.NewMediaResponse(data, mimeType)  // Autre média
fantasy.WithResponseMetadata(resp, meta)  // Attache métadonnées typées

5.4 Détails des outils clés

bash — ExĂ©cution de commandes

ParamĂštres: {Description, Command, WorkingDir, RunInBackground, AutoBackgroundAfter}

Sécurité:
├── safeCommands: ls, cat, head, tail, pwd, echo, which, env, git status/diff/log
│   → Pas de permission requise (read-only)
├── Banned: curl, wget, sudo, apt, npm, etc.
│   → BloquĂ© au niveau shell
├── Background: si RunInBackground=true ou > AutoBackgroundAfter (60s)
│   → Retourne ShellID pour suivi
└── Output: tronquĂ© Ă  30,000 chars (dĂ©but + fin + compte lignes tronquĂ©es)

view — Lecture de fichiers

ParamĂštres: {FilePath, Offset, Limit}

Comportement:
├── crush: prefix → lecture depuis FS embarquĂ© (skills builtins)
├── Chemins relatifs → rĂ©solus via SmartJoin(workingDir, ...)
├── Permission requise si hors workingDir
├── Max fichier: 100KB, dĂ©faut 2000 lignes
├── Images JPG/PNG/GIF/WebP → NewImageResponse
├── Ajoute numĂ©ros de ligne (padding 6 chars)
├── LSP: ouvre fichier, attend 300ms pour diagnostics
├── Enregistre lecture via filetracker.RecordRead()
└── Suggestions si fichier non trouvĂ©

edit — Édition de fichiers

ParamĂštres: {FilePath, OldString, NewString, ReplaceAll}

3 modes:
├── OldString="" → CrĂ©er nouveau fichier
├── NewString="" → Supprimer contenu
└── Les deux → Remplacer contenu

Sécurité:
├── Doit avoir lu le fichier avant (filetracker check)
├── Fichier non modifiĂ© depuis la lecture (ModTime check)
├── OldString unique (sauf ReplaceAll=true)
├── Permission "write" avec diff affichĂ©
├── Gestion CRLF automatique
└── LSP notifiĂ© aprĂšs Ă©criture

grep — Recherche de contenu

ParamĂštres: {Pattern, Path, Include, LiteralText}

Optimisations:
├── ripgrep (rg --json) en prioritĂ©, fallback Go regex
├── Respecte .gitignore et .crushignore
├── Cache de regex compilĂ©s (csync.Map thread-safe)
├── RĂ©sultats triĂ©s par date de modification (plus rĂ©cent d'abord)
├── Max 100 rĂ©sultats
├── Lignes tronquĂ©es Ă  500 chars
└── Timeout configurable

5.5 Outils spéciaux

agent — Sous-agent

Flow:
1. Valide params.Prompt non vide
2. Crée une session enfant (CreateTaskSession)
3. Lance un SessionAgent séparé (NonInteractive: true)
4. Outils du sous-agent: glob, grep, ls, sourcegraph, view (READ-ONLY)
5. Propage le coĂ»t de la session enfant → session parent

agentic_fetch — Fetch intelligent

Flow:
1. Mode URL: fetch + convert (HTML→MD)
   → Si contenu > 50KB: sauve en temp file, dit au sous-agent d'utiliser view/grep
2. Mode Search: construit prompt pour web_search + web_fetch
3. Sous-agent avec petit modĂšle + outils restreints
4. Auto-approve des permissions pour le sous-agent

6. Optimisation de la consommation de tokens

6.1 Résumé automatique (Auto-Summarization)

La plus grande optimisation. Voir Section 4.

Quand la fenĂȘtre de contexte approche sa limite, toute la conversation est remplacĂ©e par un rĂ©sumĂ© dĂ©taillĂ©. Ce rĂ©sumĂ© devient le nouveau point de dĂ©part.

6.2 Anthropic Prompt Caching

Marqueurs ephemeral ajoutés automatiquement :

// Cache control placement:
├── Dernier message systùme     → ephemeral
├── Avant-dernier message       → ephemeral
└── AntĂ©pĂ©nultiĂšme message      → ephemeral

Cela permet à Anthropic de mettre en cache ces messages et de réduire les tokens d'input sur les tours suivants.

6.3 Filtrage des orphelins de tool calls

// Avant d'envoyer Ă  l'IA:
filterOrphanedToolResults()           // Supprime tool results sans tool call correspondant
syntheticToolResultsForOrphanedCalls() // Injecte erreurs synthétiques pour tool calls orphelins

Cela nettoie l'historique des messages inutiles qui consomment des tokens.

6.4 Deux modĂšles (Large/Small)

├── Large Model: tĂąches principales (coder, rĂ©sumĂ©)
└── Small Model: titre de session, agentic_fetch
    → Économise les tokens de haute qualitĂ© pour les tĂąches simples

6.5 Limitations de taille des outils

Outil Limite Impact token
bash output 30,000 chars Tronque les longues sorties
view 100KB max, 2000 lignes Limite les gros fichiers
grep 100 résultats, 500 chars/ligne Limite les recherches larges
glob 100 fichiers Limite les résultats
ls 1000 fichiers Limite les répertoires massifs
fetch 100KB Limite les pages web
sourcegraph 20 résultats max Limite les recherches code
description tools FirstLineDescription() N'envoie que la 1Ăšre ligne de description

6.6 Short Tool Descriptions

// Par défaut: seul le premier ligne non-vide de la description est envoyé
FirstLineDescription(fullMarkdownDescription)

// Désactivable via: CRUSH_SHORT_TOOL_DESCRIPTIONS=0

Chaque outil a une description markdown complĂšte, mais seule la premiĂšre ligne est envoyĂ©e Ă  l'IA — Ă©conomie significative sur 22+ outils.

6.7 Workaround média par provider

Pour les providers non-Anthropic/Bedrock, les images dans les tool results sont converties en messages utilisateur sĂ©parĂ©s avec piĂšces jointes — Ă©vitant les erreurs API et les tokens gaspillĂ©s.

6.8 Injection system_reminder minimale

Seul un rappel minimal est injecté comme premier message utilisateur :

"<system_reminder>This is a reminder that your todo list is currently empty.
DO NOT mention this to the user explicitly...</system_reminder>"

Ce message est court et sert de garde-fou sans consommer beaucoup de tokens.

6.9 Estimation de tokens

ApproxTokenCount(text) = len(text) / 4  // Heuristique 4 chars = 1 token

Utilisé pour le logging et les métriques, pas pour le contrÎle strict.


7. Optimisations de performance

7.1 Concurrence

├── sync.WaitGroup pour chargement providers (Catwalk + Hyper en //)
├── sync.OnceValue pour cache Hyper (computed once)
├── fastwalk pour dĂ©couverte des skills (concurent, suit symlinks)
├── errgroup.Group pour readiness des agents (system prompt + tools en //)
├── csync.Map pour maps concurrent-safe (providers, regex cache)
├── sync.RWMutex pour skill tracker
└── Shell mutex sĂ©rialise les commandes par instance shell

7.2 File d'attente de messages (Message Queue)

Si agent occupĂ© → message en queue
↓
Dans PrepareStep → injecte messages en queue comme user messages supplĂ©mentaires
↓
Pas de perte de messages, traitement séquentiel garanti

7.3 Cache providers

├── Cache JSON: $XDG_DATA_HOME/crush/providers.json
├── ETag support pour revalidation HTTP
├── Fallback: frais → cache → embarquĂ©
└── Chargement concurrent Catwalk + Hyper

7.4 CGO et GC

├── CGO_ENABLED=0 (pas de CGO overhead)
└── GOEXPERIMENT=greenteagc (GC optimisĂ©)

7.5 Base de données SQLite

├── SQLC pour code SQL type-safe gĂ©nĂ©rĂ©
├── Transactions avec retry (3 tentatives) pour conflits UNIQUE
├── Atomic SQL increment pour token usage (Ă©vite race conditions)
└── Index sur (session_id, created_at) pour requĂȘtes messages rapides

7.6 Pub/Sub

├── SystĂšme d'Ă©vĂ©nements dĂ©couplĂ©
├── Canal d'Ă©vĂ©nements par workspace
└── Pas de polling — push-based

8. SystĂšme de permissions

8.1 Actions

Action Quand Outils concernés
"read" Lecture hors workingDir view, ls
"write" Modification de fichiers edit, multiedit, write
"execute" Commande shell non-safe bash
"fetch" RequĂȘte rĂ©seau fetch, agentic_fetch
"download" Téléchargement download
"list" Liste ressources MCP list_mcp_resources
"read" Lecture ressource MCP read_mcp_resource

8.2 Auto-approbations

  • Commandes bash safeCommands (ls, cat, pwd, git status, etc.) → pas de permission
  • Docker MCP tools whitelistĂ©s (mcp_docker_mcp-find, etc.) → auto-approuvĂ©
  • Sous-agents (agent, agentic_fetch) → auto-approuvĂ©

8.3 Sécurité shell

Banned commands: alias, aria2c, axel, chrome, curl, curlie, firefox,
http-prompt, httpie, links, lynx, nc, safari, scp, ssh, telnet, w3m,
wget, xh, doas, su, sudo, apk, apt, apt-cache, apt-get, dnf, dpkg,
emerge, home-manager, makepkg, opkg, pacman, paru, pkg, pkg_add,
pkg_delete, portage, rpm, yay, yum, zypper, at, batch, chkconfig,
crontab, fdisk, mkfs, mount, parted, service, systemctl, umount,
firewall-cmd, ifconfig, ip, iptables, netstat, pfctl, route, ufw

9. Providers et modĂšles

9.1 Types de providers supportés

├── OpenAI
├── Anthropic
├── OpenRouter (suffixe :exacto pour modĂšles supportĂ©s)
├── Vercel
├── Azure
├── AWS Bedrock
├── Google (Gemini)
├── Google Vertex AI
├── OpenAI-compatible (gĂ©nĂ©rique)
└── Hyper (Charm's meta-provider)

9.2 Hyper Provider

├── Endpoint: https://hyper.charm.land/api/v1/fantasy
├── Activation: HYPER, HYPERCRUSH, HYPER_ENABLE, HYPER_ENABLED env vars
├── Modùles: GLM-5, GLM-5.1, gpt-oss-120b, Kimi K2.5, Kimi K2.6
├── Routage: Anthropic/OpenAI/Google/OpenAI-compat selon model ID
└── Header: x-crush-id pour identification

9.3 Construction du provider

buildProvider(config) → fantasy.Provider:
    1. Parse le type de provider
    2. Configure base URL, API key, headers
    3. Ajoute beta headers si thinking model (Anthropic)
    4. Pour Hyper: route vers le bon provider selon model ID
    5. Pour OpenRouter: ajoute :exacto si supporté

10. SystĂšme de skills

10.1 Standard Agent Skills

Crush implémente le standard ouvert agentskills.io.

10.2 Découverte

Chemins explorés:
├── $CRUSH_SKILLS_DIR
├── ~/.config/agents/skills/
├── ~/.config/crush/skills/
├── .agents/skills/
├── .crush/skills/
├── .claude/skills/
├── .cursor/skills/
└── Custom via options.skills_paths

Recherche:
├── fastwalk (concurent, suit symlinks)
├── Cherche fichiers SKILL.md
├── Parse YAML frontmatter (entre ---)
├── Validation: nom alphanum-hyphens ≀64 chars, description ≀1024 chars
└── DĂ©duplication: dernier occurence gagne (user > builtin)

10.3 Injection dans le prompt

<available_skills>
  <skill>
    <name>skill-name</name>
    <description>Description courte</description>
    <location>/path/to/SKILL.md</location>
    <type>builtin</type>
  </skill>
</available_skills>

<skills_usage>
  When a user task matches a skill's description, read the skill's SKILL.md file...
</skills_usage>

Important : Seules les mĂ©tadonnĂ©es (nom, description, chemin) sont injectĂ©es dans le system prompt. Les instructions complĂštes ne sont lues que quand l'agent dĂ©cide d'activer le skill — Ă©conomie de tokens.

10.4 Skill Tracker

type Tracker struct {
    active map[string]bool  // Skills actifs (post-dedup, post-filter)
    loaded map[string]bool  // Skills dont les instructions ont été lues
    mu     sync.RWMutex
}

MarkLoaded(name)   // Marque un skill comme lu (uniquement si dans active set)
IsLoaded(name)     // Vérifie si déjà chargé
LoadedNames()      // Liste des skills chargés

11. Intégration LSP

11.1 Configuration

lsp:
  - command: "gopls"
    args: ["serve"]
    env: {}
    file_types: [".go"]
    root_markers: ["go.mod"]
    init_options: {}

11.2 Outils LSP

  • lsp_diagnostics — Diagnostics par fichier ou projet entier (max 10 fichiers, 5s wait)
  • lsp_references — Recherche de rĂ©fĂ©rences symboliques (grep + LSP FindReferences)
  • lsp_restart — RedĂ©marrage d'un ou tous les clients LSP

11.3 Intégration dans les outils

view   → openInLSPs + wait 300ms pour diagnostics
edit   → notifyLSPs + wait 5s pour diagnostics
write  → notifyLSPs + wait 5s pour diagnostics

Les diagnostics sont appendés dans les réponses des outils via des tags XML :

<file_diagnostics>...</file_diagnostics>
<project_diagnostics>...</project_diagnostics>
<diagnostic_summary>errors: N, warnings: M</diagnostic_summary>

12. Intégration MCP

12.1 Configuration

mcp:
  - name: "my-server"
    command: "npx"        # Mode stdio
    args: ["-y", "my-mcp"]
    env: {}
    url: ""               # OU mode HTTP/SSE
    timeout: 30s
    disabled_tools: []

12.2 Outils MCP dynamiques

  • Outils nommĂ©s mcp_{server}_{tool}
  • SchĂ©ma extrait de InputSchema MCP
  • Permission requise (sauf whitelist Docker)
  • Support image/mĂ©dia dans les rĂ©sultats

12.3 Instructions MCP injectées

Les instructions des serveurs MCP connectés sont injectées dans le system prompt via <mcp-instructions>.


13. Structure de la base de données

13.1 Tables principales

-- Sessions
sessions (
    id, title, prompt_tokens, completion_tokens,
    summary_message_id,          -- ID du message résumé (NULL si pas de résumé)
    cost, todos,                  -- Coût et todo list
    created_at, updated_at
)

-- Messages
messages (
    id, session_id, role,         -- user/assistant/system/tool
    parts,                        -- JSON array de {type, data}
    model, provider,
    is_summary_message,           -- Flag de compaction
    created_at, finished_at
)

-- Fichiers (version history)
files (
    id, session_id, path,
    content, version,             -- Auto-incrémenté par path
    is_new,
    created_at
)

-- Fichiers lus (read tracking)
read_files (
    path, session_id,
    last_read_time                -- Pour "read before edit"
)

13.2 RequĂȘtes clĂ©s

-- Messages d'une session (chronologique)
SELECT * FROM messages WHERE session_id = ? ORDER BY created_at ASC;

-- Update atomique des tokens (évite race conditions)
UPDATE sessions SET
    prompt_tokens = prompt_tokens + ?,
    completion_tokens = completion_tokens + ?,
    cost = cost + ?
WHERE id = ?;

-- Derniers fichiers par path (version max)
SELECT f.* FROM files f
INNER JOIN (
    SELECT path, MAX(version) as max_ver
    FROM files WHERE session_id = ?
    GROUP BY path
) latest ON f.path = latest.path AND f.version = latest.max_ver;

-- Stats: utilisation des outils via JSON
SELECT json_extract(part.data, '$.name') as tool_name, COUNT(*)
FROM messages, json_each(messages.parts) as part
WHERE json_extract(part.value, '$.type') = 'tool_call'
GROUP BY tool_name;

14. Fichiers clés à explorer

Architecture et flow principal

Fichier Ce qu'il contient
internal/agent/agent.go Moteur IA — construction messages, streaming, rĂ©sumĂ©, queue
internal/agent/coordinator.go Orchestration — crĂ©ation agents, tools, models, provider options
internal/agent/prompts.go Factory de prompts systĂšme
internal/agent/loop_detection.go Détection de boucles (SHA-256 signatures)

Templates (ce qui est envoyé à l'IA)

Fichier Ce qu'il contient
internal/agent/templates/coder.md.tpl System prompt principal (405 lignes)
internal/agent/templates/task.md.tpl Prompt sous-agent
internal/agent/templates/summary.md Prompt de résumé/compaction
internal/agent/templates/title.md Prompt de génération de titre
internal/agent/templates/agent_tool.md Instructions tool agent
internal/agent/templates/agentic_fetch_prompt.md.tpl Prompt sous-agent fetch

Outils

Fichier Ce qu'il contient
internal/agent/agent_tool.go Tool agent (sous-agent spawner)
internal/agent/agentic_fetch_tool.go Tool agentic_fetch
internal/agent/tools/bash.go Tool bash
internal/agent/tools/edit.go Tool edit
internal/agent/tools/multiedit.go Tool multiedit
internal/agent/tools/write.go Tool write
internal/agent/tools/view.go Tool view
internal/agent/tools/glob.go Tool glob
internal/agent/tools/grep.go Tool grep
internal/agent/tools/ls.go Tool ls
internal/agent/tools/fetch.go Tool fetch
internal/agent/tools/sourcegraph.go Tool sourcegraph
internal/agent/tools/web_search.go Tool web_search (DuckDuckGo)
internal/agent/tools/web_fetch.go Tool web_fetch
internal/agent/tools/download.go Tool download
internal/agent/tools/todos.go Tool todos
internal/agent/tools/diagnostics.go Tool LSP diagnostics + helpers
internal/agent/tools/references.go Tool LSP references
internal/agent/tools/lsp_restart.go Tool LSP restart
internal/agent/tools/crush_info.go Tool crush_info
internal/agent/tools/crush_logs.go Tool crush_logs
internal/agent/tools/mcp-tools.go Outils MCP dynamiques

Messages et données

Fichier Ce qu'il contient
internal/message/message.go Service de messages (CRUD + events)
internal/message/content.go Types de contenu + conversion fantasy.Message
internal/message/attachment.go PiĂšces jointes
internal/history/file.go Historique de versions fichiers
internal/db/sql/sessions.sql RequĂȘtes SQL sessions
internal/db/sql/messages.sql RequĂȘtes SQL messages
internal/db/sql/files.sql RequĂȘtes SQL fichiers
internal/db/sql/stats.sql RequĂȘtes SQL statistiques

Configuration et providers

Fichier Ce qu'il contient
internal/config/config.go Structures de config (models, providers, tools, agents)
internal/config/provider.go Chargement des providers (Catwalk + Hyper + cache)
internal/backend/config.go API config backend
internal/agent/hyper/provider.go Provider Hyper
internal/agent/hyper/provider.json Définition des modÚles Hyper

Infrastructure

Fichier Ce qu'il contient
internal/shell/shell.go Shell POSIX cross-platform (mvdan/sh)
internal/diff/diff.go Génération de diffs unifiés
internal/skills/skills.go SystÚme de skills (découverte, injection)
internal/skills/tracker.go Suivi des skills chargés
internal/lsp/manager.go Gestionnaire LSP
internal/filetracker/service.go Suivi des fichiers lus

15. Leçons pour notre application

15.1 Patterns Ă  adopter

Pattern Pourquoi Comment Crush le fait
RĂ©sumĂ© automatique adaptatif GĂšre les longues conversations sans perte Seuil 20K tokens (fenĂȘtres >200K) ou 20% (fenĂȘtres <200K), skip si fenĂȘtre inconnue
Deux niveaux de modĂšle Économise les tokens coĂ»teux Large pour coder, Small pour titres et fetch
Skills avec lazy loading N'injecte que les métadonnées, charge les instructions à la demande Métadonnées dans system prompt, instructions lues via view
Short tool descriptions Économise des tokens sur 22+ outils FirstLineDescription() par dĂ©faut
Anthropic prompt caching Réduit les tokens d'input sur les tours suivants ephemeral sur dernier system + 2 derniers messages
Filetracker read-before-edit Sécurité + contexte pour l'IA Enregistre chaque lecture, vérifie avant édition
Loop detection ArrĂȘte les boucles infinies coĂ»teuses SHA-256 signature sur fenĂȘtre de 10 Ă©tapes, max 5 rĂ©pĂ©titions
Orphan filtering Nettoie l'historique des messages inutiles Supprime tool results orphelins, injecte erreurs synthétiques
Atomic SQL increments Pas de race conditions sur les compteurs prompt_tokens = prompt_tokens + ? au lieu de read-modify-write
Message queue Pas de perte de messages Queue + injection dans PrepareStep

15.2 Optimisations token spécifiques

  1. Troncature de sortie — bash (30K), grep (500 chars/ligne), view (2000 lignes)
  2. Limites de rĂ©sultats — glob (100), grep (100), ls (1000), sourcegraph (20)
  3. Premiùre ligne de description — Seulement la 1ùre ligne des descriptions markdown d'outils
  4. Estimation heuristique — len(text) / 4 pour logging sans appel API
  5. RĂ©sumĂ© dĂ©taillĂ© structurĂ© — Sections obligatoires assurent pas de perte d'information critique
  6. Reset des compteurs aprĂšs rĂ©sumĂ© — PromptTokens=0, CompletionTokens=rĂ©sumĂ© seulement

15.3 Points d'attention

  • Le system prompt fait ~405 lignes — C'est Ă©norme mais structurĂ© en sections XML claires
  • Pas de troncature du system prompt — Les skills et context files sont injectĂ©s en entier
  • Le rĂ©sumĂ© n'a pas de limite — "Err on the side of too much detail"
  • La dĂ©tection de boucle est basique — SHA-256 sur ToolName+Input+Output, mais ne dĂ©tecte pas les boucles sĂ©mantiques
  • Pas de token counting prĂ©cis — Heuristique 4 chars/token, pas de tiktoken
  • Le file history persiste — Les versions de fichiers survivent au rĂ©sumĂ© (pas dans le contexte LLM mais disponibles dans l'UI)

15.4 Architecture recommandée

Pour notre app, inspirons-nous de:

1. Coordinator Pattern
   └── Orchestrateur central qui assemble models + tools + prompts
   └── Agents par session avec state isolĂ©

2. Summary/Compaction Pipeline
   └── Seuils adaptatifs (fenĂȘtre large vs small)
   └── RĂ©sumĂ© structurĂ© avec sections obligatoires
   └── Reset des compteurs aprùs compaction

3. Tool Architecture
   └── Interface uniforme (params, execute, response)
   └── Permission system par action
   └── Output truncation systĂ©matique
   └── Metadata sur chaque rĂ©ponse

4. Provider Layer
   └── JSON merge en 3 couches pour options
   └── Support multi-provider avec routage
   └── Cache avec ETag + fallback

5. Lazy Skill Loading
   └── MĂ©tadonnĂ©es dans system prompt
   └── Instructions complùtes à la demande
   └── Tracker pour Ă©viter les rechargements

Annexe : Schéma de dépendances

main.go
  └── internal/cmd/ (CLI commands)
       └── internal/backend/ (workspace management)
            └── internal/app/ (application logic)
                 └── internal/agent/coordinator.go (orchestration)
                      ├── internal/agent/agent.go (moteur IA)
                      │    ├── internal/agent/templates/ (prompts)
                      │    ├── internal/agent/prompt/ (prompt builder)
                      │    ├── internal/message/ (message types)
                      │    └── internal/agent/loop_detection.go
                      ├── internal/agent/tools/ (22+ outils)
                      ├── internal/skills/ (skill discovery)
                      ├── internal/config/ (configuration)
                      ├── internal/lsp/ (LSP management)
                      ├── internal/shell/ (shell execution)
                      ├── internal/db/ (SQLite persistence)
                      ├── internal/filetracker/ (read tracking)
                      └── internal/diff/ (diff generation)

Rapport gĂ©nĂ©rĂ© le 26 avril 2026 — BasĂ© sur l'analyse du commit HEAD de charmbracelet/crush