Aller au contenu

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.


ContainerRô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.


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
└── SkillWorkspaceMaterializer

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 :

  1. Déposer le module addon sous addons/<name>/ avec son manifest et register<Name>Addon(deps) (ou un runtime construit par la composition pour RegisteredRuntimeAddon).
  2. Ajouter le manifest dans composition/addons/index.tsFIRST_PARTY_RUNTIME_ADDON_MANIFESTS (ou dans le tableau ADDONS pour un Addon auto-enregistré).
  3. Câbler via le point d’entrée unique composition/addons/first-party-runtime.tsregisterFirstPartyRuntimeAddons(deps). Le composition root appelle cette fonction une fois et récupère chaque runtime via addonRegistry.require<TRuntime>('<id>').
  4. Routes HTTP optionnelles dans composition/addons/<name>-routes.ts, montées depuis composition/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.


PhaseAction
BootcreateCoreContainer instancie le graphe, démarre les abonnements bus
RunLes routes consomment les use-cases via le container
ShutdowncoreContainer.dispose() appelle les unsubscribe() des addons et ferme les ressources (SQLite, sidecars)