🏛️ Eko System Architecture & Design
This document details Eko's underlying software architecture, component cell diagrams, concurrency model, and data storage workflows.
1. High-Level Architecture Overview
Eko is composed of three core architectural layers:
- CLI Command Layer (
cmd/): Built on the Go Cobra framework (init,save,restore,history,summary,clean,migrate,tag,ai). - Engine & Utility Layer (
internal/):snapshot: Orchestrates snapshot creation, manifest writing, env serialization, and atomic directory restores.objects: Content-Addressable Storage (CAS) engine (.eko/objects/<prefix>/<hash>.<ext>), Zstandard (Zstd) compression, adaptive raw storage heuristic (.rawfor binary files), atomic writes, and mark-and-sweep garbage collection.manifest: Lightweight JSON snapshot manifests (.eko/manifests/<id>.json) backed by an in-memory thread-safe LRU cache (internal/manifest/cache.go, default capacity: 50 manifests) for ~24.26 ns/op RAM lookups.cache: Incremental SQLite hash cache (hash_cachetable indb.sqlite) to skip reading unchanged files.ai/mind: GitMind AI Reasoning Engine (handles all 20 AI capabilities: status, review, semdiff, risk, impact, bisect, ask, owners, next, security, gate, explain, test, conflict, pr).util: Worker-pool directory copy engine and thread-safe error reporting.api: File diff and workspace change calculators.
- Persistence Layer (
.eko/): Local SQLite database (db.sqlite+hash_cache+ tags), CAS object store (objects/), and snapshot tree manifests (manifests/).
graph TD
subgraph CLI ["1. CLI Command Layer (cmd/)"]
RootCmd["root.go (Cobra Engine)"]
InitCmd["init.go (eko init)"]
SaveCmd["save.go (eko save --ai)"]
RestoreCmd["restore.go (eko restore)"]
HistoryCmd["history.go (eko history)"]
SummaryCmd["summary.go (eko summary)"]
CleanCmd["clean.go (eko clean)"]
MigrateCmd["migrate.go (eko migrate)"]
TagCmd["tag.go (eko tag)"]
AICmd["ai.go (eko ai <subcommand>)"]
end
subgraph Core ["2. Core Engines & Utilities (internal/)"]
GitMindEngine["GitMind AI Reasoning Engine\n(internal/ai/mind/gitmind.go)"]
SnapshotEng["Snapshot Engine\n(internal/snapshot/)"]
CASEngine["CAS Object Store\n(internal/objects/)"]
ManifestEngine["Manifest Engine\n(internal/manifest/)"]
CacheEngine["Hash Cache Engine\n(internal/cache/)"]
FSEngine["Worker-Pool FS Engine\n(internal/util/fs.go)"]
DiffEngine["Diff & Comparison Engine\n(internal/api/diff.go)"]
AIEngine["AI Provider Layer\n(internal/ai/provider.go)"]
end
subgraph Storage ["3. Persistence Layer (.eko/)"]
SQLiteDB[("SQLite Database\n.eko/db.sqlite (metadata + tags + hash_cache)")]
CASObjects["CAS Object Store\n.eko/objects/<prefix>/<hash>.gz"]
Manifests["Tree Manifests\n.eko/manifests/<id>.json"]
EnvState[".eko_env_vars.json"]
end
RootCmd --> InitCmd & SaveCmd & RestoreCmd & HistoryCmd & SummaryCmd & CleanCmd & MigrateCmd & TagCmd & AICmd
AICmd -->|Reason & Audit| GitMindEngine
GitMindEngine -->|Analyze Diffs| DiffEngine
GitMindEngine -->|Invoke Models| AIEngine
SaveCmd -->|Check Hash Cache| CacheEngine
SaveCmd -->|Store Blobs| CASEngine --> CASObjects
SaveCmd -->|Write Manifest| ManifestEngine --> Manifests
SaveCmd -->|Generate Summary| AIEngine
RestoreCmd -->|Extract Tree| CASEngine
CleanCmd -->|Garbage Collect Blobs| CASEngine
MigrateCmd -->|Convert Legacy Dirs| CASEngine & ManifestEngine
2. Concurrency Worker Pool Cell Diagram
Eko uses a hybrid Serial Walk + Worker Pool model:
- Serial Walk: Walks source directory tree serially to synchronously create parent target directories (
os.MkdirAll) before parallel workers begin writing files, preventing directory creation race conditions. - Worker Pool: Spawns
runtime.NumCPU()worker goroutines to process copy tasks concurrently.
graph LR
subgraph TreeWalker ["1. Serial Tree Walk (Main Goroutine)"]
Walk["filepath.Walk(src)"]
Filter{"ShouldIgnore()?"}
Mkdir["os.MkdirAll(target, 0755)\n(Synchronous)"]
end
subgraph Queue ["2. Task Channel"]
TaskChan["chan copyTask\n(Buffer: NumCPU * 2)"]
end
subgraph WorkerPool ["3. Worker Pool (NumCPU Workers)"]
W1["Worker Goroutine 1"]
W2["Worker Goroutine 2"]
W3["Worker Goroutine N"]
end
subgraph ErrorBus ["4. Thread-Safe Error Channel"]
ErrChan["chan error\n(Buffer: NumCPU)"]
end
Walk --> Filter
Filter -->|No| Mkdir
Mkdir -->|Enqueue File Copy| TaskChan
Filter -->|Yes| Skip["Skip Dir/File"]
TaskChan --> W1
TaskChan --> W2
TaskChan --> W3
W1 -->|Copy Failure| ErrChan
W2 -->|Copy Failure| ErrChan
W3 -->|Copy Failure| ErrChan
ErrChan -->|Bail & Abort Walk| Walk
3. Lock-Free Atomic CAS Restore Sequence
During workspace restoration, existing non-ignored workspace items are deleted in parallel using atomic.Pointer[error] Compare-And-Swap (CAS) to capture the first error without mutex lock overhead:
sequenceDiagram
autonumber
participant Main as Restore Main Goroutine
participant WG as sync.WaitGroup
participant G1 as Worker Goroutine 1 (file A)
participant G2 as Worker Goroutine 2 (file B)
participant CAS as atomic.Pointer[error]
Main->>Main: Read top-level workspace entries (excluding .eko)
Main->>WG: Add(N) goroutines
Main->>G1: Spawn os.RemoveAll("fileA")
Main->>G2: Spawn os.RemoveAll("fileB")
alt G1 encounters permission error
G1->>CAS: CompareAndSwap(nil, &err1) -> SUCCESS (Stores err1)
end
alt G2 encounters disk error later
G2->>CAS: CompareAndSwap(nil, &err2) -> FAILS (err1 is already stored)
end
G1->>WG: Done()
G2->>WG: Done()
WG->>Main: Wait() finishes
Main->>CAS: Load()
Note over Main: Returns first error (err1). Short-circuits restore phase!
4. AI Provider Strategy Engine
Eko abstracts LLM services behind a clean Provider interface:
graph TD
Client["eko summary / eko save --ai"] -->|Request Summary| Engine["GenerateSnapshotSummary()"]
Engine --> ProviderSelect{"Select Provider?"}
ProviderSelect -->|--provider gemini| Gemini["GeminiProvider\n(Google Gemini API)"]
ProviderSelect -->|--provider openai| OpenAI["OpenAIProvider\n(OpenAI / Custom LLM)"]
ProviderSelect -->|--provider heuristic| Local["HeuristicProvider\n(Offline Rule Engine)"]
ProviderSelect -->|Auto (Default)| AutoCheck{"API Keys Present?"}
AutoCheck -->|GEMINI_API_KEY set| Gemini
AutoCheck -->|OPENAI_API_KEY set| OpenAI
AutoCheck -->|No API keys| Local
Gemini -->|Prompt Engineering & JSON Format| Response["Summary Result Struct"]
OpenAI -->|Prompt Engineering & JSON Format| Response
Local -->|Extract Added/Deleted Metrics| Response
Response -->|Update Database| DB[(".eko/db.sqlite")]
5. High-Performance Storage & Zero-Copy Reflinks
Eko utilizes high-throughput storage engines and platform-specific system calls to minimize both I/O latency and disk usage.
flowchart TD
subgraph Save["eko save (Compression Engine)"]
File["File input"] --> ExtCheck{"Is already binary\nor compressed?"}
ExtCheck -->|"Yes (.png, .zip, etc.)"| RawStore["Store Raw (.raw)\nBypass compression CPU cycles"]
ExtCheck -->|"No (text/code)"| ZstdStore["ZSTD Compression (.zst)\n3x faster decompression than Gzip"]
end
subgraph Restore["eko restore (Extraction Engine)"]
ObjFile["Stored Object"] --> ObjType{"Stored as .raw\nor .zst?"}
ObjType -->|".zst"| Decompress["Decompress normally\nRecycle decoders via sync.Pool"]
ObjType -->|".raw"| Reflink{"CoW Reflink supported\nby platform/volume?"}
Reflink -->|"Yes (APFS / btrfs / xfs)"| Clone["OS Reflink Clone\nconstant-time ~0.12 ms"]
Reflink -->|"No"| RawCopy["Standard CopyFile\nFast block-by-block copy"]
end
1. Adaptive ZSTD Compression
- Zstandard Engine: Upgraded from
gziptogithub.com/klauspost/compress/zstdfor 3x faster decompression and higher compression ratios. - sync.Pool Decoder Recycling: Reuses
*zstd.Decoderstates in a globalsync.Poolto eliminate the expensive buffer allocation overhead (typically ~1MB+ of buffer structures) on every read operation. - Adaptive Compression Level: Constrains files under 1MB to single-threaded modes to prevent thread overhead, while using auto-concurrency for larger payloads.
2. Raw Binary Store Bypass
- Binary/Archive Detection: Scans file extensions and magic-bytes headers to skip compressing already compressed files (e.g.
.png,.jpg,.zip,.pdf,.zst). - Direct Raw Storage: Saves binary assets directly as
.rawfiles, completely skipping CPU-intensive compression cycles.
3. Zero-Copy OS Reflinks (CoW Clones)
- Strategy Pattern for OS Sycalls: Exposes a unified
Reflinkerinterface and loads strategies dynamically:- macOS (APFS):
clonefile(2) - Linux (btrfs, xfs):
ioctl(FICLONE) - Fallback: standard optimized byte copy.
- macOS (APFS):
- Sub-Millisecond Restore: Restores uncompressed
.rawfiles in ~128 microseconds (70.8x faster than standard byte copies) by pointing directly to existing physical disk blocks, bypassing the Go memory space completely.