-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
🇬🇧 English · 🇮🇹 Italiano
Generated from docs/architecture.md — edit that file in the repository, not this page.
Leggi in 🇮🇹 Italiano
This document describes the technical architecture, design principles, and modular structure of the TSUKA framework (v0.8.0). For codebase contribution guidelines, see
AGENTS.md; for completed and upcoming task backlogs, seeTASKS.md.📊 System Metrics: 30 native tools · 20 REPL commands · 21 roles · 9 traits · 24 characters (agents) · 10 preconfigured teams · 89 automated test suites · Dual CLI & TUI interfaces.
TSUKA is built on the ReAct (Reason + Act) paradigm, governed by a deterministic code infrastructure that tightly controls context, tools, and resource budgets allocated to the Large Language Model.
┌────────────────────────────┐
│ User Input / Objective │
└─────────────┬──────────────┘
│
▼
┌────────────────────────────┐
│ Dynamic Prompt Assembly │
│ (Identity + Memory + │
│ Allowed Tier Tools) │
└─────────────┬──────────────┘
│
┌───────────────────────▼────────────────────────┐
│ LLM Invocation (HTTP Stream) │◄─────────────┐
└───────────────────────┬────────────────────────┘ │
│ │
[ Model Output ] │
│ │
Contains │ │
tool calls? ├────────── No ──────────┐ │
│ │ │
Yes ▼ │
│ ┌───────────┐ │
▼ │ Final │ │
┌──────────────────────┐ │ Response │ │
│ Argument Validation │ └─────┬─────┘ │
│ & Permission Check │ │ │
└──────────┬───────────┘ │ │
│ │ │
▼ │ │
┌──────────────────────┐ │ │
│ Tool Execution & │ │ │
│ Context Truncation │ │ │
└──────────┬───────────┘ │ │
│ │ │
▼ │ │
┌──────────────────────┐ │ │
│ Inject Result into │ │ │
│ Chat History │────────────┘ │
└──────────┬───────────┘ │
└───────────────────────────────────────┘
With local LLMs (especially under 30B parameters), reliability increases the more control logic is owned by code rather than delegated to the model:
- The model decides content: synthesizing text, reasoning on tasks, formulating structured tool arguments.
-
The harness governs workflow: selecting visible tools by capability tier, capping excessive outputs, enforcing permissions, and breaking infinite loops with hard limits (
Agent.DEFAULT_MAX_TOOL_ROUNDS = 15).
The codebase is organized into four independent layers with clear separation of concerns:
┌─────────────────────────────────────────────────────────────────────────┐
│ 1. CLI & UI (src/cli/) │
│ REPL · Slash Commands · Live ANSI Rendering · Interactive Menus │
└────────────────────────────────────┬────────────────────────────────────┘
│ User Input / Events
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ 2. CORE ENGINE (src/core/) │
│ ReAct Loop (Agent) · LLM Provider · Persistent Memory · Context │
└───────────────────┬─────────────────────────────────┬───────────────────┘
│ Tool Invocations │ Permission Queries
▼ ▼
┌─────────────────────────────────────┐ ┌───────────────────────────────┐
│ 3. TOOL REGISTRY (src/tools/) │ │ 4. SAFETY (src/safety/) │
│ Auto-discovery · JSON Schema · Impl │ │ Permission Manager · Sandbox │
└─────────────────────────────────────┘ └───────────────────────────────┘
| Layer | Directory | Architectural Responsibility |
|---|---|---|
| Core | src/core/ |
Manages the ReAct cycle (Agent), LLM client (LLMProvider), persistent storage (MemoryStore), context budget, and run blackboard. Fully decoupled from Node TTY and the terminal. |
| Tools | src/tools/ |
Hosts the dynamic auto-discovery registry (ToolRegistry), JSON Schema contracts, and 30 native tool implementations. Zero UI dependencies. |
| Safety | src/safety/ |
Defines risk tiers (SAFE, RESTRICTED, DANGEROUS), manages async permission queues, and enforces workspace path sandboxing. |
| CLI | src/cli/ |
Implements the REPL loop, slash command router, animated statusline, and ANSI/Markdown stream renderer. Operates as one possible client to the core engine. |
The core engine never writes directly to console.log or TTY streams:
- Agent runs broadcast life-cycle updates through event contracts (
onChunk,onStats,onEvent,AbortSignalinagentEvents.ts). - Internal service modules (
MemoryStore,ConfigManager,ToolRegistry) emit diagnostics through an injectable log sink (src/core/logSink.ts), paving the way for headless servers or web UIs without core refactoring. -
PermissionManagerowns policy and queue serialization, not terminal rendering: CLI and TUI inject aPermissionPromptHandler. Without a renderer, non-SAFErequests fail closed. Workflow escalation tools likewise depend on the narrowWorkflowDispatchercontract instead of importing CLI command handlers.
Every user iteration in the REPL or within a workflow follows six deterministic stages:
-
Dynamic Prompt Assembly (
loadSystemPrompt,src/core/personas.ts): Concatenates character identity, role system prompt, trait stylistic directives, semantically relevant memory facts, and the textual tool catalog (omitted if the model has verified native function calling). The persona catalog belongs to core;src/cli/shared.tsremains only as a compatibility barrel. -
Adaptive Tool Filtering (
registry.listForLLM): Applies a dual-filter: tools must belong to the active role'sallowedToolslist and satisfy the model's capability tier at the current reasoning effort level. -
Token-Driven History Pruning (
pruneHistory): Verifies that total history tokens fit withinmaxHistoryTokens. Removes older messages while strictly maintaining integrity betweentool_callandtoolresponse pairs. -
Streaming LLM Invocation (
provider.chatWithTools): Sends payload to the OpenAI-compatible backend, parsing<think>reasoning chunks separately from visiblecontent. -
Tool Validation & Execution: Tool calls are validated against their JSON Schema contracts.
PermissionManagerprompts the user if necessary. Tool outputs are safely truncated to context bounds (capForContext). -
Re-injection & Continuation: Results are appended with role
tool, re-triggering the loop until the model outputs text or exhausts rounds.
All agent personalities and skills are purely configured in JSON files outside the application source:
┌─────────────────────────┐ ┌────────────────────────┐
│ ROLE (roles/) │ × │ TRAIT (traits/) │ ──► CHARACTER / AGENT
│(Capabilities & Tool set)│ │(Tone & Communication) │ (e.g. @geordi, @worf, @pike)
└─────────────────────────┘ └────────────────────────┘
| Component | Directory | Function & Purpose |
|---|---|---|
| Role | roles/*.json |
Technical capability: system instructions (systemPrompt), authorized tools (allowedTools), and default reasoningEffort. |
| Trait | traits/*.json |
Behavioral stance and style (e.g. professional, creative, grumpy, uncompromising). |
| Character (Agent) | characters/*.json |
Named agent preset linking an identifier (aiName), functional description, one or more roles (roles: [...] with activeRole), and a trait. |
| Team | teams/*.json |
Multi-agent collaboration config defining members, strategy (mode), orchestrator, and acceptance criteria (acceptance). |
In the goal orchestrator (/goal), the planning LLM selects agents primarily based on the description field in characters/*.json. Accurate descriptions allow the orchestrator to dynamically choose agents based on their craft rather than fixed names.
The harness includes 30 native tools built on schema-execution separation:
-
JSON Schema (
tools_schemas/<name>.json): defines name, description, parameters, risk tier (riskLevel), and required model tier (requiredTier). -
Implementation (
src/tools/impl/<name>.ts): pure TypeScript execution logic adhering to theToolinterface.
┌──────────────────────────────┐
│ 30 Native Tools │
└──────────────┬───────────────┘
│
Filter 1: Role ▼
┌─────────────────────────────────────────────────┐
│ Role allowedTools list (roles/*.json) │
└────────────────────────┬────────────────────────┘
│
Filter 2: Tier ▼
┌─────────────────────────────────────────────────┐
│ Model Tier (SMALL / MEDIUM / LARGE) │
│ from /benchmark Fingerprint or Name Heuristic │
└────────────────────────┬────────────────────────┘
│
▼
┌──────────────────────────────┐
│ Tools presented to LLM in │
│ current turn │
└──────────────────────────────┘
-
Filesystem:
read_file,write_file(unbounded complete writes plus resumable transactional chunks with UTF-8 byte offsets and atomic commit),edit_file,delete_file,list_dir,grep_search. -
System:
execute_command(shell runner with graduated risk classification, dynamic timeout, and abortable process-tree ownership),get_ps_info(process & system metrics). -
Web & Network:
web_search,browse_url(with Reader View extraction),download_file. -
Memory:
save_memory,recall_memory,update_memory,forget_memory. -
Coordination:
report_status,route_next,cast_vote,post_note,read_notes,send_message. -
Agent Extension:
spawn_agent,switch_skill,create_role,create_tool,load_tools,request_goal,request_team,request_call. -
Security:
audit_code(OWASP vulnerability and secret scanner).
TSUKA implements three distinct state layers:
┌─────────────────────────────────────────────────────────────────────────────┐
│ 1. TURN HISTORY (RAM) │
│ Scope: single agent in active turn │
│ Content: raw message exchanges & tool outputs │
│ Lifecycle: volatile (pruned upon turn completion or context limit) │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ 2. RUN BLACKBOARD (AsyncLocalStorage / blackboard.ts) │
│ Scope: shared across all members of a single /team or /goal run │
│ Content: intermediate decisions, notes, and session artifacts │
│ Lifecycle: lives only for the run duration; embedded in JSON log report │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ 3. LONG-TERM PERSISTENT MEMORY (memory/memory.json) │
│ Scope: persistent across all sessions and agents │
│ Content: project conventions, architectural decisions, learned lessons │
│ Lifecycle: permanent on disk, managed via score-based eviction │
└─────────────────────────────────────────────────────────────────────────────┘
-
Scoping: facts are tagged by workspace root or marked
globale. -
Kind & Eviction: facts have kinds (
fact,decision,lesson,run). When capacity is reached (memoryMaxFacts, default 200), transientrunentries are evicted first, whilepinnedfacts are never removed. - Semantic Retrieval: prompt injection uses weighted OR keyword scoring with morphological stemming.
TSUKA uses three progressive defenses against context saturation:
-
Tool Result Capping (
capForContext): Tool outputs exceedingmaxToolResultTokens(default 4,000) are truncated with head/tail preservation and instructions on how to paginate (e.g.offset/limitinread_file). -
Token-Driven Pruning (
pruneHistory): History truncation operates on estimated token count (maxHistoryTokens), auto-calibrated dynamically against realusage.prompt_tokens. -
Server Window Auto-Detection: At startup, TSUKA detects real context limits from server endpoints (llama-server
/props, Ollama/api/show, OpenRoutercontext_length).
For reasoning models (e.g. DeepSeek R1), reasoning_effort (none, low, medium, xhigh) is resolved through a 5-tier cascade:
Global Pin (/effort) ──► Caller Override ──► Character ──► Role ──► Config Default
-
Tier-Effort Coupling:
/benchmarkprofiles models at all effort levels. Changing effort via/effortupdates the active tier and adjusts visible tools accordingly. -
Dual Timeout Protection:
FIRST_TOKEN_TIMEOUT_MSprotects against stalled servers, whileMAX_GENERATION_MS(llmTimeoutMs) sets an absolute generation ceiling.
┌─────────────────────────────────────────────────────────────────────────────┐
│ EXECUTION MODES │
├─────────────────┬─────────────────┬─────────────────┬───────────────────────┤
│ 1. Single Chat │ 2. Conference │ 3. Team │ 4. Goal Orchestrator │
│ (/agent) │ (/call) │ (/team) │ (/goal) │
│ │ │ │ │
│ Interactive │ Multi-agent │ Fixed squad │ Dynamic planning with │
│ turn with role │ debate without │ with 4 workflow │ all characters and │
│ tools │ tools │ strategies │ PARALLEL blocks │
├─────────────────┴─────────────────┴─────────────────┴───────────────────────┤
│ 5. Autonomous Sub-Agent (spawn_agent): isolated subtask delegation │
└─────────────────────────────────────────────────────────────────────────────┘
-
Team Strategies:
orchestrated(supervisor routes each turn viaroute_next),round-robin(fixed cycle),pipeline(assembly line with acceptance loop inloop.ts),hybrid(discussion and voting). -
Parallel Workspace Isolation:
PARALLELOblocks execute concurrently viaPromise.allin isolated staging folders (AsyncLocalStorage), followed by safe conflict-detecting file merges.
A unified client using the OpenAI SDK interfaces with local and remote endpoints:
-
Server auto-discovery (
discovery.ts): probes configured endpoints on launch with a 2.5s timeout. -
RAM/VRAM Priority: automatically attaches to the model already loaded in memory (
/api/psin Ollama,loadedin Unsloth/LM Studio) to avoid redundant weights reloading. -
Data-driven provider catalogue (
providers.json): endpoint, display name, default model,LOCAL/CLOUDclass, API-key environment variable, and optional capabilities are data. Core policy consumes only the class and capability contracts. The active provider and per-install model/endpoint overrides remain intsuka.config.json. -
Declarative capabilities: a provider can expose a free-model filter through
capabilities.freeModels(aliases, suffixes, and zero-price metadata). Providers without that capability do not show the option; no provider name is checked in core, CLI, or TUI policy.
| Module / Subsystem | Source Path | Architectural Responsibility |
|---|---|---|
| Agent | src/core/agent.ts |
ReAct loop, token pruning, compression, deferred tool resolution, and event orchestration. |
| Provider Client | src/core/provider/ |
OpenAI HTTP client (llmProvider.ts), protocol contracts (types.ts), timeouts & interactive renewal (timeouts.ts), inference telemetry sink (telemetry.ts), and sampling profiles (sampling.ts). |
| Memory Engine | src/core/memory/ |
Pluggable MemoryBackend contract (types.ts), pure BM25 scoring (bm25.ts), half-life decay & retention (retention.ts), JsonMemoryBackend (jsonBackend.ts), backend registry (registry.ts), and MemoryStore facade. |
| Configuration | src/core/config/ |
Application configuration types (types.ts), model sampling sanitizer (sampling.ts), and ConfigManager (manager.ts). |
| Provider Catalogue |
providers.json, src/core/providerCatalog.ts
|
Provider definitions, validation, LOCAL/CLOUD classification, API-key indirection, and optional provider capabilities. |
| Constants Registry | src/core/constants.ts |
Single source of built-in tunable defaults (LLM_DEFAULTS, MEMORY_DEFAULTS, AGENT_DEFAULTS, TUI_DEFAULTS, TOOLS_DEFAULTS, CLI_DEFAULTS). |
| Blackboard | src/core/blackboard.ts |
Session blackboard scoped per workflow via AsyncLocalStorage. |
| Context Budget | src/core/contextBudget.ts |
Dynamic token estimation, runtime calibration, and capForContext. |
| Model Profile | src/core/modelProfile.ts |
Capability fingerprinting profiles and model tier management. |
| Discovery | src/core/discovery.ts |
Server discovery, loaded model detection, and context window probes. |
| Parallel Workspace | src/core/parallelWorkspace.ts |
Staging directories and conflict-aware file merge engine. |
| Loop Controller | src/core/loop.ts |
Iterative execution and objective acceptance verification (acceptance). |
| Log Sink | src/core/logSink.ts |
Injectable logging abstraction decoupling core from terminal TTY. |
| App Home | src/core/apphome.ts |
Hierarchical path resolution (global app home vs local workspace). |
| Platform | src/core/platform.ts |
Cross-platform shell execution (PowerShell on Windows, /bin/sh on Unix). |
| Command Safety | src/safety/commandRisk.ts |
Graduated risk classifier for shell commands (classifyRisk). |
TSUKA features a zero-flicker, Component-Driven terminal user interface:
┌──────────────────────────────┐
│ TuiScreen (Double-Buffer) │
└──────────────┬───────────────┘
│
┌───────────────▼───────────────┐
│ TuiStore (Flux/State) │
└───────┬───────────────▲───────┘
│ │
┌──────────────────┴──┐ ┌──┴──────────────────┐
│ Pure View Layer │ │ TuiBridge Adapter │
│ (Header, Sidebar, │ │ (Subscribes to Core │
│ Files, Chat, etc.)│ │ AgentEvents) │
└─────────────────────┘ └─────────────────────┘
-
TuiScreen(screen.ts): Low-level ANSI double-buffering line renderer with differential updates (0ms latency, zero flicker) and robust ANSI slicing viaslice-ansiandstring-width. -
TuiStore(store.ts): Reactive state container managing active tabs, conversation feed, reasoning streaming chunks, files tree, token meters, and modal queues. -
TuiBridge(bridge.ts): Decouples the Core Engine (AgentEvents,PermissionManager) from the UI. -
Layout Composer (
layoutComposer.ts): Pure deterministic one-frame composition functioncomposeFrame(state, width, height, tab, layout)with zero side-effects. -
Interaction Layer (
src/tui/interaction/): Decoupled user input handling:-
geometry.ts: Single source of truth for panel bounding boxes and dimensions. -
keyHandlers.ts: Focused keyboard routing per pane (input, chat, sidebar, files, tools). -
mouseRouter.ts: SGR 1006 mouse event routing (tabs, scroll wheel, panel focus, file selection, reasoning expansion).
-
-
View Hierarchy (
src/tui/views/): Pure functional renderers receiving(state, width, height) => string[]:-
HeaderView: Top navigation tabs & token budget progress meter. -
SidebarView: Active persona, role, trait, and token analytics. -
FilesView: Workspace directory scanner with file-type icons, scrollbar, and click-to-insert. -
ChatView: Formatted markdown, syntax highlighting, and<think>reasoning containers. -
ToolsView: Dynamic tool catalog & execution history. -
InputView: Text buffer, multi-line cursor, and working status spinner. -
ModalView: Universal overlay for safety permissions, model picker, and REPL cheatsheets. Each modal type contributes only its own box (BOX_BUILDERS); centering and compositing are shared.
-
-
Data-Driven Dispatch Tables: behaviour lives in lists, not in conditional chains, so extending the TUI means adding a row.
-
src/tui/commands/: the slash command table (registry.ts) — name, aliases, description and handler per command, grouped insessionCommands/workflowCommands/configCommands.TuiCommandControlleronly parses the line and looks it up;assertMenuCoverage()keeps the table and the slash menu (commands/menu.json) from drifting apart. -
src/tui/navigation.ts: the tab table — function key, per-width labels, and the modal each tab toggles. The header row, the mouse click zones and the help cheatsheet all derive from it, so a relabelled tab cannot lose its click target. -
src/tui/layoutConfig.ts: layout presets, themes and widget order (tui.layout.json). -
src/tui/keybindings.json: raw escape sequences mapped to key names.
-
-
3-tier risk system:
SAFE(instant),RESTRICTED(prompt with session bypass option),DANGEROUS(always interactive manual confirmation). -
Workspace Jail: file operations are restricted to
workspaceRoot. - Credential Masking: automatic redaction of sensitive environment keys.
-
Opt-in Self-Authoring:
create_tooland executable custom modules are disabled by default. When explicitly enabled, all generated tools are DANGEROUS;node:vmperforms bounded shape validation only and is not treated as a security boundary.
In compliance with Directives 8, 9, and 10 in AGENTS.md, Phase 8 refactored TSUKA's core from monolithic structures into modular, pluggable components:
┌────────────────────────────────────────────────────────────────────────┐
│ Unified Composition Root (src/core/runtime.ts) │
│ createHarnessRuntime() -> HarnessRuntime (CLI / TUI) │
└───────────┬──────────────────────┬──────────────────────┬──────────────┘
│ │ │
▼ ▼ ▼
┌──────────────────────┐┌──────────────────────┐┌────────────────────────┐
│ Agent Invariants ││ Provider Boundary ││ Memory & Storage │
│ (src/core/agent.ts) ││(src/core/provider/) ││ (src/core/memory/) │
│ ││ ││ │
│ ├─ tokenCalibration ││ ├─ wireFormat ││ ├─ codec & dedup │
│ ├─ conversationHist. ││ ├─ streamAccumulator ││ ├─ storage & recovery │
│ ├─ toolRound ││ ├─ errorClassific. ││ ├─ bm25 ranking │
│ ├─ reactState ││ └─ llmProvider ││ ├─ retention decay │
│ └─ reasoningTrace ││ ││ └─ jsonBackend │
└──────────────────────┘└──────────────────────┘└────────────────────────┘
│ │ │
└──────────────────────┼──────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────────────────┐
│ Modular Tool Registry (src/tools/) │
│ IToolRegistry -> schema.ts + tierPolicy.ts + execution.ts + registry │
└────────────────────────────────────────────────────────────────────────┘
-
Composition Root (
src/core/runtime.ts):-
createHarnessRuntime()unifies config loading, LLM provider initialization, native tool discovery, MCP server attachment, and permission manager across CLI and TUI. - Provides an idempotent
close()method to cleanly terminate child MCP stdio processes and release resources.
-
-
Agent Invariants (
src/core/):-
tokenCalibration.ts: runtime chars-per-token calibration. -
conversationHistory.ts: history management and pruning enforcing context budget. -
toolRound.ts: sequenced tool execution and lifecycle telemetry. -
reactState.ts: deterministic ReAct state machine. -
reasoningTrace.ts: reasoning artifact persistence (memory/thinking/*.md).
-
-
Tight Tool Contracts (
src/tools/):- Explicit
IToolRegistry,Tool,ToolExecutionContext, andToolSchemaDatainterfaces intypes.ts. - Execution pipeline in
execution.ts, schema resolution inschema.ts, tier policy intierPolicy.ts.
- Explicit
-
Provider Boundary Normalization (
src/core/provider/):- Encapsulates OpenAI wire format in
wireFormat.ts, streaming chunk aggregation instreamAccumulator.ts, and error parsing inerrorClassification.ts.
- Encapsulates OpenAI wire format in
-
Focused JSON Memory Backend (
src/core/memory/):- Clear decoupling between serialization/dedup (
codec.ts) and atomic disk persistence/recovery (storage.ts).
- Clear decoupling between serialization/dedup (
-
Decoupled I/O Completed: core agent loop communicates via structured event interfaces (
AgentEvents) and injectable sinks (logSink). - Dual Client Interfaces: seamless support for both interactive CLI and full-screen TUI.
- Context Optimization & Shadow Memory (Phase 9): deterministic context pressure scheduling and memory shadow evaluation.
For practical tutorials and examples, see the Educational Guide and Multi-Agent Workflows.
TSUKA v0.8.1 · Repository · Issues · MIT License