2bfa58f440
Outil local sanctionné chlova.propose_asset : l'agent propose un asset → write+commit+version+doc → need-review (privilégié = BLOQUÉ). Notion ToolSpec.sanctioned (autorisé par gatekeeper, audité). Flag CHLOVA_AUTOEXT_ENABLED (off défaut) + CHLOVA_REPO_ROOT. Prompt impose un palier honnête. 75 tests, 0 vuln, compose OK. Palier de risque : privilégié (l'agent écrit+commit) — derrière flag + Phase 2 ; l'asset produit n'est jamais exécuté, il reste sous review. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
orchestrator — backend CHLOVA
Le cerveau : LLM en boucle tool-calling. Phase 1 = lecture seule. Seule
surface exposée de la stack (voir ../CLAUDE.md, ../docs/architecture.md).
Stack
Node 22, TypeScript (ESM, NodeNext, strict), Fastify, MCP SDK officiel, pino
(audit), zod (config), Vitest (tests). Toutes deps épinglées ; npm audit
doit rester à 0 vuln.
Démarrage (dev)
cp ../.env.example ../.env # renseigner les secrets (jamais commités)
npm install
npm run dev # tsx watch
npm run typecheck
npm test
Modules
| Fichier | Rôle |
|---|---|
src/config.ts |
Config fail-closed (zod). Refuse de démarrer si secret manquant. assertReadOnlyPhase() verrouille la lecture seule P1. redactedConfig() masque les secrets. |
src/audit/log.ts |
Logger pino + journal d'audit des exécutions d'outils. |
src/index.ts |
Bootstrap : config → verrou RO → logger → (P1) MCP + agent + Telegram. Healthcheck interne. |
src/llm/, src/agent/ |
Client Ollama + boucle agent + prompt phase-aware. |
src/mcp/ |
Registry MCP (listReadOnlyTools P1 / listAllTools P2) + readonly-filter. |
src/gatekeeper/ |
Paliers de risque, table assets SQLite (repository), Gatekeeper+GatekeeperGuard, ReviewService + cron (review). |
src/surfaces/ |
Surface Telegram + commandes de review owner (commands). |
Phases
CHLOVA_PHASE=1(défaut) : lecture seule,ReadOnlyGuard, aucun outil mutant.CHLOVA_PHASE=2: écriture sous gatekeeper + cycle need-review (cron + commandes/pending,/approve,/refuse). Voir../docs/need-review.md.
Sécurité
- Secrets par référence uniquement, jamais loggés (
redactedConfig+ redact pino). - Phase 1 :
PORTAINER_READ_ONLY=falsefait échouer le démarrage. - Aucun port publié (Telegram long-polling) ; Fastify n'écoute qu'en interne.
Palier de risque
reversible (lecture seule). Aucune capacité d'écriture branchée en Phase 1.