Composition root
La composition root assemble toutes les dépendances d’arka-deck en un graphe vivant. Elle instancie les adapters, les use-cases, les addons, et les câble via injection de dépendances manuelle.
Source de vérité : composition/core-container.ts, composition/web-container.ts.
Deux containers
Section intitulée « Deux containers »| Container | Rôle |
|---|---|
createCoreContainer(deps) | Instancie le cœur : event bus, adapters outbound (stores, clients), use-cases inbound, addons first-party |
createWebContainer(coreContainer, deps) | Instancie la couche serveur web : Fastify, routes, état UI courant (workspace + projet) |
Le coreContainer est utilisable sans serveur web (par exemple en CLI ou en tests). Le webContainer ajoute la couche transport HTTP.
Ordre d’instanciation (simplifié)
Section intitulée « Ordre d’instanciation (simplifié) »1. Adapters infrastructure ├── Clock (FsClock) ├── IdGenerator (UuidIdGenerator) ├── Filesystem (FsFilesystem avec allowlist) ├── ArkaHome (~/.arka-deck/ ou ARKA_DECK_HOME) └── SecretCipher (AesSecretCipher)
2. Event bus └── InMemoryEventBus
3. Stores prod ├── FsProjectStore, FsProjectIndexStore, FsWorkspaceStore ├── SqliteChatSessionStore ├── SqliteArkadocStore, SqliteArkadocManifestStore └── SqliteConnectorInstallationStore, etc.
4. Clients HTTP Cortex ├── HttpCatalogueClient, HttpCatalogueBlocsClient ├── HttpArkadocCortexClient, HttpAtomsClient └── HttpCortexLiteRuntimeContextClient
5. Provider hub └── HttpProviderHub (registre + lifecycle providers LLM)
6. Use-cases inbound ├── buildForProjects, buildForWorkspaces ├── buildForChat, buildForCatalogue ├── buildForArkadoc, buildForSquads, buildForMissionGuardian └── ... (tous les for-*.ts implémentés)
7. Addons first-party (chemin canonique : `composition/addons/first-party-runtime.ts`) ├── registerFirstPartyRuntimeAddons (point d'entrée unique) │ ├── runtime cortex-actions (encore construit directement par le core-container — déviation SPEC-05) │ ├── runtime memory-local (encore construit directement par le core-container — déviation SPEC-05) │ └── squad-orchestration (Addon, construit par le registre à partir des deps) ├── Cortex Lite (sidecar HTTP, pas in-process — cf. addons-firstparty/cortex-lite/) ├── Câblage runtime Mission Guardian (runtime core, pas un addon in-process) ├── registerSquadLeaderAddon └── registerNotionConnectAddon
8. Materializers ├── ClaudeAgentWorkspaceMaterializer ├── HookWorkspaceMaterializer └── SkillWorkspaceMaterializerRègles d’import du composition root
Section intitulée « Règles d’import du composition root »composition/ est le seul dossier autorisé à importer simultanément depuis :
core/(ports, use-cases, domain)adapters/(outbound + inbound)addons/(registers)providers/(runtimes)
Les autres dossiers respectent strictement les frontières (cf. ADR 0001).
Câblage d’un addon (chemin canonique — SPEC-05, décision B)
Section intitulée « Câblage d’un addon (chemin canonique — SPEC-05, décision B) »Le chemin canonique pour ajouter un addon first-party ne requiert PAS d’éditer composition/core-container.ts :
- Déposer le module addon sous
addons/<name>/avec son manifest etregister<Name>Addon(deps)(ou un runtime construit par la composition pourRegisteredRuntimeAddon). - Ajouter le manifest dans
composition/addons/index.ts→FIRST_PARTY_RUNTIME_ADDON_MANIFESTS(ou dans le tableauADDONSpour unAddonauto-enregistré). - Câbler via le point d’entrée unique
composition/addons/first-party-runtime.ts→registerFirstPartyRuntimeAddons(deps). Le composition root appelle cette fonction une fois et récupère chaque runtime viaaddonRegistry.require<TRuntime>('<id>'). - Routes HTTP optionnelles dans
composition/addons/<name>-routes.ts, montées depuiscomposition/web-container.ts.
// composition/addons/first-party-runtime.ts (chemin canonique)
import { squadOrchestrationAddon } from '../../addons/squad-orchestration/src/index.js';import type { CortexActionsAddonRuntime } from '../../addons/cortex-actions/src/index.js';import type { LocalMemoryAddonRuntime } from '../../addons/memory-local/src/index.js';// ...
export function registerFirstPartyRuntimeAddons(deps: { // ... ports partagés + runtimes déjà construits pour les entrées RegisteredRuntimeAddon}): { addonRegistry: AddonRegistry; squadOrchestrationRuntime: SquadOrchestrationRuntime } { const addonRegistry = new AddonRegistry(); addonRegistry.registerAll( [ registeredRuntimeAddon('cortex-actions', deps.cortexActionsRuntime), registeredRuntimeAddon('memory-local', deps.memoryRuntime), squadOrchestrationAddon, ], deps, ); return { addonRegistry, squadOrchestrationRuntime: addonRegistry.require('squad-orchestration') };}Déviations actuelles (tracées dans ROADMAP.md → Chantiers de split tracés SPEC-05) : core-container.ts appelle encore directement registerCortexActionsAddon et registerLocalMemoryAddon parce que leurs builders dépendent de stores/clients locaux au container. La cible est de pousser ces appels dans des helpers factory dédiés composition/addons/<name>-factory.ts pour que le composition root n’invoque plus que registerFirstPartyRuntimeAddons.
Cycle de vie
Section intitulée « Cycle de vie »| Phase | Action |
|---|---|
| Boot | createCoreContainer instancie le graphe, démarre les abonnements bus |
| Run | Les routes consomment les use-cases via le container |
| Shutdown | coreContainer.dispose() appelle les unsubscribe() des addons et ferme les ressources (SQLite, sidecars) |
Voir aussi
Section intitulée « Voir aussi »- Vue d’ensemble : ./overview
- Ports inbound : ./ports-inbound
- Ports outbound : ./ports-outbound
- Materializers : ./materializers