Architecture — vue d'ensemble
Guide pour développeurs qui veulent comprendre l’organisation du code, les règles de dépendance et les clusters fonctionnels d’arka-deck.
Vue d’ensemble
Section intitulée « Vue d’ensemble »arka-deck est une application hexagonale TypeScript/Node.js. Le cœur ne dépend de rien d’externe — toutes les dépendances pointent vers lui, jamais l’inverse.
┌─────────────────────────────────────────────────────────────┐│ adapters/ ││ ┌──────────────────┐ ┌──────────────────────────┐ ││ │ inbound/ │ │ outbound/ │ ││ │ cli/ │ │ filesystem/ │ ││ │ web/ │ │ http/ │ ││ │ server/ │ │ chat/ │ ││ │ ui/ (React) │ │ providers/ │ ││ └──────────────────┘ │ events/ │ ││ │ process/ │ ││ │ secrets/ │ ││ │ system/ │ ││ └──────────────────────────┘ ││ ┌─────────────────────────────────────────┐ ││ │ composition/ │ ││ │ core-container.ts web-container.ts │ ││ └─────────────────────────────────────────┘ ││ ┌─────────────────────────────────────────┐ ││ │ core/ │ ││ │ domain/ ports/ use-cases/ │ ││ │ orchestration/ │ ││ └─────────────────────────────────────────┘ ││ ┌─────────────┐ ┌──────────────────────┐ ││ │ addons/ │ │ providers/ │ ││ │ workers/ │ │ claude_code/ │ ││ └─────────────┘ │ codex_cli/ │ ││ │ google-genai/ │ ││ └──────────────────────┘ │└─────────────────────────────────────────────────────────────┘Dossiers racine
Section intitulée « Dossiers racine »| Dossier | Rôle |
|---|---|
core/ | Domaine pur — ports, use-cases, types domain, orchestration |
adapters/inbound/ | Points d’entrée — CLI et serveur web (Fastify + UI React/Vite) |
adapters/outbound/ | Implémentations I/O — filesystem, HTTP, chat, providers, secrets, système |
composition/ | Assemblage des dépendances — DI manuel, containers |
addons/ | Modules autonomes event-driven — addons préinstallés first-party |
providers/ | Implémentations runtime LLM — claude_code, codex_cli, google-genai |
workers/ | Workers headless 1-shot — manifest + prompt |
bin/ | Binaire CLI arka-deck |
scripts/ | Scripts utilitaires (release, prepare-dist, gates CI) |
e2e/ | Tests end-to-end Playwright |
Le cœur hexagonal. Aucune dépendance vers adapters/, addons/, composition/ ou providers/.
core/├── domain/ # Types et règles métier pures│ ├── chat/ # Transcript, StreamEvent, sessions│ ├── catalogue/ # Profils, installs, agents│ ├── events/ # ArkaEvent — union discriminée de tous les events bus│ ├── project/ # Projet, workspace│ ├── providers/ # Manifests provider│ ├── squad/ # Composition d'équipe│ └── workers/ # Manifests worker├── ports/│ ├── inbound/ # Contrats use-cases (for-chat.ts, for-projects.ts…)│ └── outbound/ # Contrats I/O (event-bus.ts, filesystem.ts, clock.ts…)├── use-cases/ # Logique applicative — implémente les ports inbound└── orchestration/ # Orchestration multi-agents (LangGraph)Ports inbound
Section intitulée « Ports inbound »Les ports inbound (core/ports/inbound/for-*.ts) définissent les contrats que les use-cases exposent aux adapters :
for-chat.ts— lancer, reprendre, envoyer un tourfor-projects.ts— CRUD projets et workspacesfor-catalogue.ts— charger et installer des agents depuis le Cortexfor-workers.ts— déclencher un workerfor-preferences.ts— lire et écrire les préférences- et plusieurs autres — la liste exhaustive est dans
ports-inbound.md(à venir).
Ports outbound
Section intitulée « Ports outbound »Les ports outbound (core/ports/outbound/*.ts) définissent les contrats que les adapters implémentent :
event-bus.ts— bus d’événements typé in-processfilesystem.ts— lecture/écriture fichiers (avec allowlist)chat-runtime.ts— exécution d’un tour LLMbefore-turn-augmenter.ts— injection de contexte avant un tourclock.ts,id-generator.ts— utilitaires
Règles d’import (ESLint enforced)
Section intitulée « Règles d’import (ESLint enforced) »Les frontières sont vérifiées mécaniquement par ESLint à chaque lint :
| Source | Interdit d’importer |
|---|---|
core/** | adapters/**, composition/**, addons/**, providers/** |
core/domain/** | core/use-cases/** |
adapters/inbound/** | adapters/outbound/** |
adapters/** | addons/** |
La composition (composition/) est le seul endroit autorisé à assembler tout ensemble.
composition/
Section intitulée « composition/ »Le container de composition instancie tous les adapters, les use-cases et les addons, puis les câble via injection de dépendances manuelle.
core-container.ts— instancie le cœur (event bus, stores, use-cases)web-container.ts— ajoute le serveur Fastify, les routes et l’UI
C’est le seul fichier autorisé à importer depuis addons/, providers/ et adapters/ simultanément.
Event bus
Section intitulée « Event bus »Le bus est un module cœur (core/ports/outbound/event-bus.ts), instancié une fois au boot dans core-container.ts. Il transporte des events typés in-process entre tous les modules.
interface EventBus { publish(event: ArkaEvent): Promise<void>; // attend tous les handlers publishAsync(event: ArkaEvent): void; // non-bloquant subscribe<T extends ArkaEventType>( type: T, handler: EventHandler<T>, ): Unsubscribe;}La liste complète des events est dans core/domain/events/arka-event.ts (source de vérité). Convention de nommage : <domain>.<entity>.<action> kebab-case. Voir event-bus pour la documentation complète.
Chaque addon est un module autonome dans son propre sous-dossier :
addons/<name>/├── manifest.json # métadonnées déclaratives└── src/ ├── index.ts # fonction register + re-exports publics ├── domain/ # types domain locaux à l'addon ├── ports/ │ ├── for-<name>.ts # port inbound propre à l'addon │ └── *.ts # ports outbound (stores, clients HTTP) ├── adapters/ # implémentations des ports outbound └── use-cases/ # logique applicative de l'addonLes addons peuvent importer depuis core/ (ports outbound, types domain) mais pas depuis adapters/ ni depuis d’autres addons.
Pour créer un addon, voir le tutoriel ../extension/ecrire-un-addon.md (à venir).
providers/
Section intitulée « providers/ »Les providers implémentent le port outbound chat-runtime.ts pour un LLM donné :
providers/├── claude_code/ # SDK @anthropic-ai/claude-agent-sdk├── codex_cli/ # Codex CLI└── google-genai/ # Google GeminiChaque provider expose un runtime.ts qui satisfait le contrat ChatRuntime et un manifest.json ou équivalent qui déclare ses métadonnées (modèles disponibles, capacités).
workers/
Section intitulée « workers/ »Les workers sont des processus LLM headless déclarés par manifest.json. Ils ne sont pas exécutés directement — c’est le système de workers d’arka-deck qui les invoque via le port for-workers.ts.
workers/<name>/├── manifest.json # déclaration (input, output, runtime, prompt_source)├── prompt.json # prompt local (optionnel — sinon via Cortex)└──Pour concevoir un worker, voir ../extension/ecrire-un-worker.md (à venir).
Décisions d’architecture (ADR)
Section intitulée « Décisions d’architecture (ADR) »Les décisions structurantes sont documentées dans ../../adr/ :
| ADR | Sujet |
|---|---|
| 0001 | Architecture hexagonale |
| 0002 | Contrat addon |
| 0003 | Pattern Materializer |
| 0004 | Distribution GitHub uniquement |
| 0005 | Secrets AES-GCM local |
| 0006 | Protection anti-SSRF providers |
Stack technique
Section intitulée « Stack technique »| Couche | Technologie |
|---|---|
| Runtime | Node.js ≥ 20.19.0, TypeScript (strict) |
| Serveur HTTP | Fastify 5.8.5 |
| UI | React 18, Vite, Tailwind CSS, React Query |
| Stockage local | SQLite (better-sqlite3), fichiers JSON |
| Secrets | AES-256-GCM dans ~/.arka-deck/ |
| Validation | Zod |
| SDK Claude | @anthropic-ai/claude-agent-sdk 0.2.129 |
| Orchestration | LangChain / LangGraph |
| Tests | Vitest (unit), Playwright (E2E) |
| Linting | ESLint (max-warnings=0), Prettier |