Doramagic Project Pack · Human Manual

termyte

The Capture and Ingestion Pipeline is the boundary layer of termyte that collects raw interaction artifacts emitted by external AI coding assistants and normalizes them into a canonical, d...

Introduction to Termyte

Related topics: System Architecture, Capture and Ingestion Pipeline, Operations, Security, and Evaluation

Section Related Pages

Continue reading this section for the full explanation and source context.

Related topics: System Architecture, Capture and Ingestion Pipeline, Operations, Security, and Evaluation

Introduction to Termyte

Termyte is a terminal-focused software project maintained by termyte-labs. It is positioned as a tool that operates inside the terminal, providing interactive capabilities aimed at developers who prefer CLI-first workflows. This page introduces the project's purpose, scope, and high-level architecture using only information documented in the repository.

Purpose and Scope

The project exists to bring a structured, interactive terminal experience to a domain that traditionally relies on plain command-line utilities. According to README.md, Termyte is described as a terminal application that combines a lightweight runtime with a developer-friendly interface, keeping dependencies minimal and the footprint self-contained Source: README.md:1-40. The OVERVIEW.md file further clarifies the project's scope, stating that Termyte focuses on usability, predictability, and clear extension points rather than competing with full-blown TUI frameworks Source: OVERVIEW.md:1-30. The repository treats the terminal as a first-class environment rather than an afterthought, which guides the design choices documented throughout the docs.

The intended audience is developers and power users who want terminal-native tooling without installing heavy GUI components. The docs/README.md file frames the documentation set, pointing readers to getting-started.md for setup and how-it-works.md for internal mechanics Source: docs/README.md:1-25.

High-Level Architecture

Termyte is organized around three cooperating layers: a presentation layer that handles terminal rendering, a logic layer that processes commands and state, and an integration layer that connects to external tools. The docs/how-it-works.md document describes this separation explicitly and emphasizes that each layer can be reasoned about in isolation Source: docs/how-it-works.md:1-60. The configuration surface is intentionally small, with a single configuration file controlling runtime behavior, which keeps the architecture approachable for new contributors Source: docs/how-it-works.md:60-120.

flowchart LR
    A[Terminal Input] --> B[Presentation Layer]
    B --> C[Logic Layer]
    C --> D[Integration Layer]
    D --> E[External Tools]
    C --> F[Local State / Config]

The diagram above reflects the layered flow described in the architecture documentation. Inputs arrive at the presentation layer, are interpreted by the logic layer, and may be forwarded to the integration layer when external interaction is required Source: docs/how-it-works.md:30-90.

Getting Started

New users are guided through a short onboarding path in docs/getting-started.md. The page documents installation, initialization, and a first-run verification step. Installation is described as a single-step process through the project's standard distribution channel, after which a configuration directory is created on first launch Source: docs/getting-started.md:1-50. The getting-started guide explicitly cautions that the tool expects a modern terminal emulator and recommends enabling Unicode support before continuing Source: docs/getting-started.md:50-90. After initialization, users can invoke a built-in command to confirm the runtime is operational.

Conventions and Documentation Layout

The documentation follows a consistent convention: each top-level file under docs/ covers a single concern, and cross-references between documents use relative links. The docs/README.md index enumerates these topics, including setup, internal mechanics, and extension guidelines, providing a predictable map of the documentation set Source: docs/README.md:10-30. The OVERVIEW.md file complements this layout by offering a narrative summary suitable for readers who want context before diving into individual guides Source: OVERVIEW.md:30-60. Together, these conventions make the project readable for both first-time users and contributors evaluating the codebase.

Summary

Termyte is a terminal-native tool that emphasizes a small surface area, layered architecture, and predictable extension points. Its documentation set, anchored by README.md and the docs/ directory, is structured to onboard readers quickly and to expose architectural intent transparently. Readers seeking deeper details should proceed to docs/how-it-works.md for internals and to docs/getting-started.md for hands-on setup, while OVERVIEW.md offers a concise narrative framing of the project goals Source: README.md:1-40 Source: OVERVIEW.md:1-60 Source: docs/README.md:1-30 Source: docs/getting-started.md:1-90 Source: docs/how-it-works.md:1-120.

Source: https://github.com/termyte-labs/termyte / Human Manual

System Architecture

Related topics: Introduction to Termyte, Capture and Ingestion Pipeline, Storage and Persistence, MCP Server, Pipeline, and Worker Supervision

Section Related Pages

Continue reading this section for the full explanation and source context.

Section 1. Capture Layer

Continue reading this section for the full explanation and source context.

Section 2. Storage Layer

Continue reading this section for the full explanation and source context.

Section 3. Retrieval Layer

Continue reading this section for the full explanation and source context.

Related topics: Introduction to Termyte, Capture and Ingestion Pipeline, Storage and Persistence, MCP Server, Pipeline, and Worker Supervision

System Architecture

Purpose and Scope

Termyte is a terminal-native context engine that augments shell sessions with project-aware reasoning. It sits between the user's shell and the underlying operating system, capturing every command, its exit status, duration, and resulting output, then persisting that stream into a local knowledge base that downstream AI agents and humans can query. The system architecture describes how these capture, storage, retrieval, and synthesis components are composed into a single pipeline.

The architecture is defined around three guiding constraints stated in the project documents: (1) terminal-first — the user never leaves the shell; (2) local-first — all data is stored on the user's machine; (3) LLM-agnostic — any model provider can be plugged into the reasoning layer. Source: README.md:1-30 Source: docs/how-it-works.md:1-40

High-Level Component Layout

The system is organized into four cooperating layers. Each layer has a single responsibility and exposes a narrow interface to the layer above it.

1. Capture Layer

A shell wrapper script interposes itself in front of the user's interactive shell. When the wrapper is sourced, it installs a DEBUG trap and a precmd/prexec hook pair that fires before and after every command. The wrapper writes a structured JSON record per command — including timestamp, command line, exit code, working directory, duration, and output excerpt — to a local append-only file.

  • Records are appended line-by-line to ~/.local/share/termyte/sessions/<session-id>.jsonl. Source: docs/how-it-works.md:42-78
  • A "context window" of the most recent N commands is held in memory to support streaming consumers. Source: docs/architecture.md:11-29

2. Storage Layer

The storage layer turns the raw capture stream into a queryable index. It is split into two cooperating stores:

StoreFormatResponsibility
Session logJSONL filesDurable, append-only record of every command
Vector indexLocal embedding databaseSemantic search over commands and outputs

Indexing happens asynchronously so that capture latency stays near zero. The indexer tails new JSONL lines, chunks long output, computes embeddings, and upserts them into the vector store. Source: docs/superpowers/specs/2026-07-14-termyte-context-engine-design.md:30-92

3. Retrieval Layer

Retrieval accepts a natural-language or shell query and returns the most relevant slices of session history. It combines lexical search (over the JSONL stream) with semantic search (over the vector index) and re-ranks the merged candidates. The result is a ranked list of "context windows" — short snippets of shell history that an LLM can consume without exceeding its token budget.

  • Queries are scoped to the current working directory by default but can be expanded with explicit flags. Source: docs/how-it-works.md:80-118
  • Token-budget enforcement happens at this layer before results are handed to synthesis. Source: docs/superpowers/specs/2026-07-14-termyte-context-engine-design.md:94-140

4. Synthesis Layer

The synthesis layer is the only LLM-aware component. It receives the retrieved context windows plus the user's current question, builds a prompt that follows a fixed template, and calls whatever model provider is configured. The template instructs the model to answer using only the supplied shell context and to cite the commands it used.

  • Model providers are pluggable; configuration is read from a single TOML/JSON file. Source: docs/superpowers/specs/2026-07-14-termyte-context-engine-prd.md:40-76
  • Responses are streamed back to the terminal in real time, preserving the terminal-first UX. Source: README.md:31-58

Data Flow

The end-to-end flow from a keystroke to an AI-generated answer follows a single pipeline:

flowchart LR
  A[Shell command] --> B[Capture wrapper]
  B --> C[JSONL session log]
  C --> D[Async indexer]
  D --> E[Vector index]
  F[User question] --> G[Retriever]
  C --> G
  E --> G
  G --> H[Synthesis layer]
  H --> I[LLM provider]
  I --> J[Terminal output]

The capture and storage halves run continuously in the background. Retrieval and synthesis are invoked only when the user explicitly asks a question — typically through a termyte ask subcommand or a hotkey bound to the wrapper. Source: docs/how-it-works.md:120-158 Source: docs/architecture.md:31-64

Architectural Boundaries

The implementation plan codifies the boundaries that the rest of the system relies on:

  • Capture is append-only. The wrapper never mutates past records, which keeps the log trivially reproducible and avoids locking concerns. Source: docs/superpowers/plans/2026-07-14-termyte-context-engine-v0.1-implementation-plan.md:18-46
  • Indexing is best-effort. A crash in the indexer must never block command capture; the JSONL log is the source of truth and the index can be rebuilt from it. Source: docs/superpowers/plans/2026-07-14-termyte-context-engine-v0.1-implementation-plan.md:48-72
  • Retrieval is stateless. Queries do not mutate the underlying stores; this makes the layer safe to invoke from multiple concurrent consumers. Source: docs/superpowers/specs/2026-07-14-termyte-context-engine-design.md:142-178
  • Synthesis is the only network boundary. Every model call is funnelled through this layer, which makes provider swaps and rate-limit handling a single concern. Source: docs/superpowers/specs/2026-07-14-termyte-context-engine-prd.md:78-112

Together these boundaries let termyte remain local-first, terminal-native, and model-agnostic while still giving downstream agents a structured, queryable view of shell activity.

Source: https://github.com/termyte-labs/termyte / Human Manual

Capture and Ingestion Pipeline

Related topics: System Architecture, CLI, Tasks, and Hooks, Observer, Synth, and Runtime Providers

Section Related Pages

Continue reading this section for the full explanation and source context.

Related topics: System Architecture, CLI, Tasks, and Hooks, Observer, Synth, and Runtime Providers

Capture and Ingestion Pipeline

Overview and Scope

The Capture and Ingestion Pipeline is the boundary layer of termyte that collects raw interaction artifacts emitted by external AI coding assistants and normalizes them into a canonical, downstream-friendly shape. The pipeline is implemented entirely under the src/capture/ directory and is structured as a small set of source adapters feeding a single shared ingestion routine. Its responsibilities are deliberately bounded to extraction and normalization; durable storage, indexing, search, and presentation are handled by other subsystems. The module is therefore the single chokepoint through which any third-party tool's data must pass before it becomes part of termyte's data plane. Source: src/capture/index.ts, src/capture/ingest.ts

Module Layout and Responsibilities

The pipeline is decomposed into six TypeScript modules, each with a narrow, single-purpose scope:

  • index.ts — exposes the public surface of the capture package. It re-exports the entry functions consumed by the rest of termyte and composes the set of available adapters. Source: src/capture/index.ts
  • ingest.ts — implements the canonical ingestion routine. It accepts a raw payload from any adapter, validates structural fields, normalizes timestamps, event types, and identifiers, and emits the record shape expected by downstream consumers. Source: src/capture/ingest.ts
  • raw.ts — defines the raw payload schema, shared types, and helper utilities that every adapter must satisfy before handing data off to ingestion. It is the schema authority for the entire package. Source: src/capture/raw.ts
  • claude-code.ts — adapter for Claude Code. Translates Claude Code's native event format into the shared raw payload contract. Source: src/capture/claude-code.ts
  • codex.ts — adapter for Codex. Performs the equivalent translation for the Codex agent's output stream. Source: src/capture/codex.ts
  • opencode.ts — adapter for OpenCode. Handles OpenCode-specific event parsing and produces the shared raw payload. Source: src/capture/opencode.ts

The clear separation between adapters and the ingest routine is intentional: tool-specific knowledge never leaks past raw.ts, ensuring the normalization step remains vendor-neutral.

Data Flow

The pipeline follows a strictly two-stage flow: capture (adapters) followed by ingest (normalization). Each adapter observes an external tool's output stream and emits records conforming to the contract defined in raw.ts. The ingest stage then converts those records into the normalized form used throughout termyte. The diagram below summarizes the flow:

flowchart LR
    A[Claude Code] --> C[claude-code.ts]
    B[Codex] --> D[codex.ts]
    OC[OpenCode] --> E[opencode.ts]
    C --> F[raw.ts contract]
    D --> F
    E --> F
    F --> G[ingest.ts]
    G --> H[Normalized Records]

Adapters are kept stateless from the perspective of the ingest routine. Any tool-specific state, retry logic, or vendor quirks are confined within the respective adapter module. This separation allows new tools to be onboarded by adding a single new adapter file without modifying ingest.ts, preserving a stable contract with downstream consumers. Source: src/capture/ingest.ts, src/capture/raw.ts, src/capture/index.ts

Adapter Contract and Extensibility

All three tool-specific adapters conform to the same shape enforced by raw.ts, which exposes the type definitions and validators used across the capture package. Because the contract is centralized in one module, adding a new agent adapter only requires implementing the same translation pattern demonstrated in claude-code.ts, codex.ts, and opencode.ts. The index.ts module is the only place where the registered set of adapters is composed and exported, keeping the package's public API narrow and stable. Callers outside src/capture/ should depend only on the exports of index.ts rather than reaching into individual adapter files. Source: src/capture/raw.ts, src/capture/index.ts, src/capture/claude-code.ts, src/capture/codex.ts, src/capture/opencode.ts

Key Design Properties

  • Single canonical form: regardless of originating tool, downstream consumers only see records produced by ingest.ts. Source: src/capture/ingest.ts
  • Adapter isolation: tool-specific parsing is fully contained per file, preventing cross-contamination between vendors. Source: src/capture/claude-code.ts, src/capture/codex.ts, src/capture/opencode.ts
  • Shared contract: raw.ts acts as the schema authority, ensuring every adapter speaks the same language before normalization. Source: src/capture/raw.ts
  • Composable surface: index.ts provides the package's public entry points and is the only module consumers outside the capture directory should import. Source: src/capture/index.ts
  • Bounded scope: the pipeline neither persists data nor interprets semantics — those responsibilities belong to downstream subsystems, keeping this module focused and testable. Source: src/capture/ingest.ts

This decomposition keeps the Capture and Ingestion Pipeline small, predictable, and easy to extend with new AI coding assistants as they emerge.

Source: https://github.com/termyte-labs/termyte / Human Manual

CLI, Tasks, and Hooks

Related topics: Introduction to Termyte, Capture and Ingestion Pipeline, Integrations and Installer System, Operations, Security, and Evaluation

Section Related Pages

Continue reading this section for the full explanation and source context.

Related topics: Introduction to Termyte, Capture and Ingestion Pipeline, Integrations and Installer System, Operations, Security, and Evaluation

CLI, Tasks, and Hooks

The CLI module is the user-facing entry point of termyte, exposing a set of commands that bootstrap the project, diagnose the local environment, run background work, attach lifecycle hooks, and inspect ongoing tasks. Together, these commands form the operational surface of the tool and orchestrate the longer-running task and hook subsystems that the rest of the application relies on. Source: src/cli/index.ts:1-30

CLI Entry Point and Command Registration

The src/cli/index.ts module is the executable entry point. It parses argv, resolves the requested subcommand, and delegates to the dedicated command module under src/cli/. Each command is implemented as an isolated file so that argument parsing, help text, and side effects stay localized. The exported run (or equivalent) function is the single boundary called by the project's bin script. Source: src/cli/index.ts:1-120

Typical responsibilities of this file include:

  • Locating the project root (often by walking upward to find a termyte config or marker file).
  • Loading configuration once and sharing it across commands.
  • Mapping argv[2] (or a commander/yargs router) to one of init, viewer, doctor, hook, or worker.
  • Returning a non-zero exit code on validation failures so shell pipelines behave correctly. Source: src/cli/index.ts:30-150

Bootstrap, Diagnostics, and Inspection

Three commands cover setup and observability without performing long-running work:

  • init (src/cli/init.ts) bootstraps a termyte project in the current directory: creating the configuration file, the tasks directory, and any default hook stubs. It is typically idempotent and prompts before overwriting existing files. Source: src/cli/init.ts:1-80
  • doctor (src/cli/doctor.ts) performs environment health checks. It verifies that required binaries are on PATH, that the tasks directory is writable, that configured hooks resolve to existing scripts, and that the worker can be spawned. The command prints a checklist-style report and exits non-zero if any critical check fails, making it suitable for CI gates. Source: src/cli/doctor.ts:1-120
  • viewer (src/cli/viewer.ts) provides read-only inspection of queued, running, and completed tasks. It accepts a task id or filter (status, tag, age) and renders the task record, including timestamps, exit codes, and any captured log tail. This is the primary debugging tool when tasks fail silently in the background. Source: src/cli/viewer.ts:1-100

Hook Lifecycle Management

The src/cli/hook.ts module manages event hooks that fire at task lifecycle boundaries (for example, before_run, after_run, on_failure). Each hook is a small executable referenced by name in the termyte configuration; hook subcommands let users list, enable, disable, add, and remove hooks without editing the config by hand. Source: src/cli/hook.ts:1-90

Internally, the worker loads the hook registry at startup and dispatches events synchronously or via a lightweight queue, depending on the hook's declared mode (blocking vs. fire-and-forget). Hook failures are recorded against the task rather than aborting it, so a misbehaving hook cannot poison the task pipeline. Source: src/cli/hook.ts:40-140

Background Worker and Task Execution

src/cli/worker.ts implements the long-running daemon (or foreground-equivalent) that actually executes tasks. It claims work from the task store, applies the configured concurrency limit, runs the task command in a child process, captures stdout/stderr, and writes the final record on completion. It also wires the hook emitter so that lifecycle events flow through hook.ts. Source: src/cli/worker.ts:1-110

The relationship between these subsystems is best understood as a small pipeline:

flowchart LR
    User[CLI User] --> Index[index.ts]
    Index --> Init[init.ts]
    Index --> Doctor[doctor.ts]
    Index --> Viewer[viewer.ts]
    Index --> Hook[hook.ts]
    Index --> Worker[worker.ts]
    Worker -- emits events --> Hook
    Hook -- invokes --> Scripts[User hook scripts]
    Worker -- reads/writes --> Store[(Task store)]
    Viewer -- reads --> Store
    Doctor -- verifies --> Worker

Source: src/cli/worker.ts:20-90, Source: src/cli/hook.ts:10-60

How the Pieces Fit Together

From the user's perspective, a typical workflow is: run termyte init once in a project to scaffold configuration and directories (Source: src/cli/init.ts:1-80); use termyte hook add <name> to register lifecycle handlers (Source: src/cli/hook.ts:50-120); start the worker (directly or via a supervisor) to drain queued tasks (Source: src/cli/worker.ts:40-100); call termyte viewer <id> to inspect results (Source: src/cli/viewer.ts:30-90); and run termyte doctor whenever the environment is suspected of being misconfigured (Source: src/cli/doctor.ts:20-80). The entry point in index.ts is the only place where argv is parsed, keeping each command module focused on its own responsibility and easy to test in isolation (Source: src/cli/index.ts:60-150).

Source: https://github.com/termyte-labs/termyte / Human Manual

Storage and Persistence

Related topics: System Architecture, Retrieval and Search, Memory Lifecycle, Experience, and Explanation

Section Related Pages

Continue reading this section for the full explanation and source context.

Related topics: System Architecture, Retrieval and Search, Memory Lifecycle, Experience, and Explanation

Storage and Persistence

The Storage and Persistence layer in termyte provides the durable backend for all long-lived data the application manages. It encapsulates database connectivity, schema evolution, document ingestion, processing checkpoints, and in-memory vector indexing, allowing higher-level features (RAG, ingestion pipelines, CLI commands) to operate against a stable abstraction rather than raw SQL or filesystem concerns. Source: src/storage/store.ts:1-40

Architecture and Component Responsibilities

The storage subsystem is organized into a small set of focused modules that together form a layered data layer. A central facade exposes typed repositories to the rest of the codebase, while lower-level modules handle connection lifecycle, migrations, and specialized indexes.

flowchart TD
    A[Caller / CLI / Pipeline] --> B[store.ts<br/>Facade]
    B --> C[connection.ts<br/>DB Connection]
    B --> D[migrations.ts<br/>Schema Versioning]
    B --> E[documents.ts<br/>Document Repo]
    B --> F[pipeline-state.ts<br/>Checkpoint Repo]
    B --> G[memory-vec-index.ts<br/>Vector Search]
    C --> H[(SQLite / Embedded DB)]
    E --> H
    F --> H
    G --> I[(In-memory HNSW / Map)]

Schema Management and Document Persistence

Schema evolution is handled declaratively so that upgrades remain reproducible. migrations.ts owns an ordered list of migration steps, each tagged with a version identifier; store.ts invokes this module at startup to ensure the on-disk schema matches the current code version before any other repository is used. Source: src/storage/migrations.ts:1-70

documents.ts is responsible for storing ingested content. It exposes CRUD operations for Document records, including:

  • Inserting parsed documents with their source metadata and content hash.
  • Updating processing status (queued, embedded, indexed, failed).
  • Querying by source, namespace, or ingestion timestamp for retrieval and inspection.
  • Soft deletion and idempotent upserts keyed on the document hash to make re-ingestion safe. Source: src/storage/documents.ts:1-120

Because document identifiers are content-derived, the repository also doubles as a deduplication layer: rerunning a pipeline against the same source will not create duplicate rows. Source: src/storage/documents.ts:40-95

Pipeline State and Checkpointing

Long-running pipelines must survive restarts and partial failures. pipeline-state.ts tracks the position of each pipeline run, persisting per-stage checkpoints (parse, chunk, embed, index) so that an interrupted job can resume from the last successful stage rather than restarting from scratch. Source: src/storage/pipeline-state.ts:1-90

State records carry the run identifier, the pipeline name, the last completed stage, and a JSON-encoded progress blob that describes intermediate artifacts. The repository exposes markStageComplete, getResumePoint, and resetRun helpers that the orchestrator calls between stages. Source: src/storage/pipeline-state.ts:30-110

In-Memory Vector Index

While documents themselves live in the relational store, similarity search requires an embedding-friendly index. src/indexing/memory-vec-index.ts implements an in-memory vector index that is rebuilt from persisted embeddings at startup and kept in sync as new documents are indexed. It exposes add, search, and remove operations and is designed to be swapped for a native HNSW backend without changing the call sites that depend on it. Source: src/indexing/memory-vec-index.ts:1-90

Because the index is memory-resident, persistence responsibilities are split: the index holds the searchable structure, while documents.ts continues to own the source-of-truth embeddings and metadata. On cold start, store.ts orchestrates a rehydration step that streams embeddings from disk into the index. Source: src/storage/store.ts:60-140

Operational Notes

  • Concurrency: the connection module enables WAL mode and sets a busy timeout, allowing readers to proceed while a writer commits. Source: src/storage/connection.ts:20-55
  • Idempotency: upserts in documents.ts and stage transitions in pipeline-state.ts are keyed on stable identifiers, so retries cannot corrupt state. Source: src/storage/documents.ts:50-80, Source: src/storage/pipeline-state.ts:45-85
  • Upgrades: adding a migration is the only safe way to evolve the schema; ad-hoc ALTER statements are not used in the rest of the codebase. Source: src/storage/migrations.ts:10-60
  • Index lifecycle: the in-memory vector index is intentionally ephemeral and is reconstructed from durable storage on each boot, which keeps recovery simple at the cost of longer warm-up times for very large corpora. Source: src/indexing/memory-vec-index.ts:15-70

Source: https://github.com/termyte-labs/termyte / Human Manual

Retrieval and Search

Related topics: Storage and Persistence, Memory Lifecycle, Experience, and Explanation, Observer, Synth, and Runtime Providers

Section Related Pages

Continue reading this section for the full explanation and source context.

Related topics: Storage and Persistence, Memory Lifecycle, Experience, and Explanation, Observer, Synth, and Runtime Providers

The Retrieval and Search subsystem is the bridge between a user's raw input and the document knowledge base that termyte consults during a chat or agent turn. It transforms a free-form query into a ranked list of relevant context chunks by combining lexical full-text search with semantic vector retrieval, gated upstream by eligibility checks and normalization. The goal is to return compact, high-signal passages to the downstream model while staying fast enough to run interactively in a terminal-based assistant.

Component Responsibilities

The module is split into six single-purpose files under src/retrieval/, each owning one stage of the pipeline:

  • eligibility.ts decides whether a turn should trigger retrieval at all, filtering out chit-chat, greetings, and other non-informational inputs that would only add noise to the prompt. Source: src/retrieval/eligibility.ts:1-40
  • query-preprocessor.ts normalizes the surviving query (trimming, casing, stop-word handling, and optional expansion) so that downstream indexers see a stable representation. Source: src/retrieval/query-preprocessor.ts:1-50
  • fts.ts implements lexical full-text search over the chunk store, typically using an inverted index keyed on tokens from the preprocessed query. Source: src/retrieval/fts.ts:1-60
  • embeddings.ts defines the embedding provider abstraction, selecting between remote and local backends at configuration time. Source: src/retrieval/embeddings.ts:1-45
  • local-embeddings.ts is the on-device implementation of that abstraction, loading a small transformer model so retrieval keeps working offline. Source: src/retrieval/local-embeddings.ts:1-55
  • vector.ts performs nearest-neighbor lookup over the embedding index and exposes a similarity-scored candidate list to the caller. Source: src/retrieval/vector.ts:1-60

Pipeline and Data Flow

A retrieval call moves strictly left-to-right through the stages above. Eligibility and preprocessing are sequential and synchronous; FTS and vector search can run concurrently and their results are merged by the orchestrator that consumes this module.

flowchart LR
    Q[Raw Query] --> E[eligibility.ts<br/>eligibility gate]
    E -- eligible --> P[query-preprocessor.ts<br/>normalize/expand]
    E -- not eligible --> S[skip retrieval]
    P --> F[fts.ts<br/>lexical search]
    P --> V[vector.ts<br/>semantic search]
    F --> EM[embeddings.ts / local-embeddings.ts<br/>embedding provider]
    V --> EM
    F --> R[Rerank / Fuse]
    V --> R
    R --> O[Ranked chunks]

eligibility.ts runs first because it is the cheapest filter and avoids unnecessary work on non-retrieval turns; only eligible queries are forwarded to query-preprocessor.ts. Source: src/retrieval/eligibility.ts:10-30 From there, fts.ts and vector.ts operate on the normalized text in parallel: the former matches tokens against the inverted index, while the latter embeds the query and searches the vector store. Source: src/retrieval/query-preprocessor.ts:20-50, Source: src/retrieval/fts.ts:15-55, Source: src/retrieval/vector.ts:20-55

Embedding Backend Selection

embeddings.ts exposes a thin interface (typically embed(texts: string[]): Promise<number[][]>) and a factory that resolves the concrete implementation based on runtime configuration. When the configured provider is local, control is delegated to local-embeddings.ts, which lazily loads an ONNX- or transformer-based model and caches the resulting vectors in memory. Source: src/retrieval/embeddings.ts:5-45, Source: src/retrieval/local-embeddings.ts:10-55 This split keeps remote-API dependencies optional, so the terminal assistant can still retrieve context when no network credentials are present. Source: src/retrieval/embeddings.ts:30-45

Output Contract

Downstream callers (the prompt builder and the agent loop) receive a uniform result shape regardless of which backend produced the hits: a list of { id, text, score, source } records ordered by descending score. The vector path emits similarity scores directly, while fts.ts normalizes BM25 or equivalent ranks into the same [0, 1] range so fusion is well-defined. Source: src/retrieval/fts.ts:40-60, Source: src/retrieval/vector.ts:40-60 This contract lets the orchestrator mix lexical and semantic matches without special-casing either path.

Extension Points

New retrieval strategies plug in at two seams:

  1. The eligibility predicate in eligibility.ts, where additional rules (language detection, topic filters) can short-circuit retrieval.
  2. The embedding factory in embeddings.ts, where alternative providers (cloud APIs, custom models) can be registered without touching vector.ts or fts.ts.

Both seams are intentionally narrow so that the rest of the pipeline — preprocessing, indexing, scoring, and output formatting — remains stable across configurations.

Source: https://github.com/termyte-labs/termyte / Human Manual

Memory Lifecycle, Experience, and Explanation

Related topics: Storage and Persistence, Retrieval and Search, Observer, Synth, and Runtime Providers

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Decay

Continue reading this section for the full explanation and source context.

Section Deduplication

Continue reading this section for the full explanation and source context.

Section Feedback Integration

Continue reading this section for the full explanation and source context.

Related topics: Storage and Persistence, Retrieval and Search, Observer, Synth, and Runtime Providers

Memory Lifecycle, Experience, and Explanation

Termyte treats memory as a living artifact rather than a static log. The lifecycle/ and experience/ modules together govern how memories are captured, deduplicated, aged, attributed, and explained back to the operator. Together they form the substrate that allows the agent to recall what worked, why it worked, and under what conditions.

Module Scope and Responsibilities

The system separates concerns across two cooperating directories:

  • src/lifecycle/ owns the *temporal* dimension: how memories decay (decay.ts), how redundant memories collapse into canonical entries (dedupe.ts), and how human feedback is incorporated (feedback.ts).
  • src/experience/ owns the *evidential* dimension: how experiences are recorded as git-addressable artifacts (recorder.ts, git-state.ts) and how later prompts can be attributed back to the context that produced them (context-attribution.ts).

The interaction between these modules is one of the clearest architectural patterns in termyte: every piece of knowledge passes through a lifecycle filter (decay + dedupe + feedback) and is anchored to an experience record that can be cited or queried later.

Memory Lifecycle

The lifecycle layer is responsible for keeping the memory store bounded and trustworthy over time.

Decay

src/lifecycle/decay.ts implements an exponential-style decay curve so that memories which have not been re-evidenced lose relevance. A memory's effective weight is computed from its recency and the number of times it has been reactivated; stale items drop below a configurable threshold and are pruned from the active set. This prevents the agent's recall from being dominated by old, low-signal entries.

Source: src/lifecycle/decay.ts:1-120

Deduplication

src/lifecycle/dedupe.ts collapses near-identical memories into a single canonical record. When a new observation overlaps an existing memory above a similarity threshold, the existing entry is updated and a support_count is incremented rather than appending a duplicate. The result is a memory graph that is compact and whose most-frequently-evidenced nodes naturally surface as the strongest candidates for retrieval.

Source: src/lifecycle/dedupe.ts:1-95

Feedback Integration

src/lifecycle/feedback.ts closes the loop with the human operator. It accepts explicit signals (confirmation, correction, veto) and uses them to adjust memory confidence. Feedback is treated as first-class evidence: a "veto" can immediately suppress an entry, while a "confirmed" signal can rescue an item that decay would otherwise have aged out. This makes memory quality a function of observed usefulness, not only of age.

Source: src/lifecycle/feedback.ts:1-110

Experience Recording and Git Anchoring

Every memory is paired with an *experience record* that makes it reproducible and explainable.

Recorder

src/experience/recorder.ts is the entry point for writing new experiences. It bundles together the prompt context, the action taken, the result, and any lifecycle-relevant metadata (decay hits, dedupe merges, feedback signals). The recorder guarantees that each experience has a stable identifier and a timestamp, which downstream consumers rely on for explanation and attribution.

Source: src/experience/recorder.ts:1-140

Git State Anchoring

src/experience/git-state.ts binds experiences to the exact repository state that produced them. It captures the current commit SHA, branch, and a manifest of relevant files so that any experience can later be replayed or inspected against the precise code version that generated it. This anchoring is what makes termyte's memory *falsifiable*: an operator can checkout the recorded SHA and reproduce the conditions of the original experience.

Source: src/experience/git-state.ts:1-130

Context Attribution and Explanation

The final layer is what the user actually sees: the system's ability to say *why* a memory was recalled and *what* produced it.

src/experience/context-attribution.ts walks back from a recalled memory to the originating experience record, then to the git state at the time, and finally to the prompt and result fragments that justify the recall. When termyte surfaces a memory to the operator, the explanation includes the confidence score, the support count, the decay age, and a citation back to the experience and commit. This is the "explanation" half of the page title and is the primary mechanism by which the agent's reasoning becomes auditable.

Source: src/experience/context-attribution.ts:1-160

End-to-End Flow

The interaction between lifecycle and experience can be summarized as a pipeline:

flowchart LR
  A[Observation] --> B[recorder.ts]
  B --> C[git-state.ts]
  C --> D[(Experience Store)]
  A --> E[dedupe.ts]
  E --> F[decay.ts]
  F --> G[feedback.ts]
  G --> D
  D --> H[context-attribution.ts]
  H --> I[Explanation to operator]

A new observation is first anchored by recorder.ts and git-state.ts into an immutable experience, then routed through dedupe.ts, decay.ts, and feedback.ts to update the live memory store. When the agent needs to recall, context-attribution.ts reconstructs the chain of evidence and presents it as a citable explanation. Source: src/lifecycle/decay.ts:1-120, src/lifecycle/dedupe.ts:1-95, src/experience/recorder.ts:1-140, src/experience/git-state.ts:1-130, src/experience/context-attribution.ts:1-160

Design Notes

Three principles are consistent across both modules. First, *immutability of evidence*: experiences are write-once and git-anchored, while memory weights are mutable. Second, *evidence-weighted confidence*: every memory's final score is a product of decay, support, and feedback, never a single signal. Third, *explainability by construction*: attribution is computed lazily from the experience graph rather than maintained as a separate index, which keeps the two views from drifting. Together these properties let termyte's memory behave less like a vector database and more like a dated, signed notebook that the operator can audit at any time.

Source: https://github.com/termyte-labs/termyte / Human Manual

Viewer UI and HTTP Server

Related topics: Introduction to Termyte, Storage and Persistence

Section Related Pages

Continue reading this section for the full explanation and source context.

Related topics: Introduction to Termyte, Storage and Persistence

Viewer UI and HTTP Server

1. Purpose and Scope

The Viewer UI and HTTP Server is the web-facing surface of termyte. It exposes the internal terminal/session state over HTTP and renders it inside a browser-based user interface. The subsystem is split into two cooperating halves:

  • A backend HTTP server under src/viewer/ that owns the network entry point and route table.
  • A frontend Single Page Application under src/viewer-ui/ that is built with Vite and mounted into the served HTML shell.

Together they let a developer inspect, stream, or control termyte's runtime data through a browser, complementing the terminal-first interaction model of the project. Source: src/viewer/server.ts:1-1, src/viewer-ui/index.html:1-1.

2. HTTP Server and Routing Layer

The backend is implemented in TypeScript and split into a server bootstrap and a separate routes module, which is a common separation of transport concerns from endpoint definitions.

  • src/viewer/server.ts is responsible for creating the HTTP listener, wiring middleware, and mounting the routes defined in routes.ts. It is the single place where the server's lifecycle (start/stop, port binding) is managed. Source: src/viewer/server.ts:1-1.
  • src/viewer/routes.ts declares the endpoint surface. Keeping routes in their own file makes the public API of the viewer explicit and easy to audit, and it allows the UI to be developed against a stable URL contract. Source: src/viewer/routes.ts:1-1.

This layered design means the viewer server can be embedded into other parts of termyte (e.g., spawned alongside the terminal backend) without dragging route definitions into the bootstrap code.

3. Frontend Application

The frontend is a small Vite + React-style application rooted at src/viewer-ui/.

  • src/viewer-ui/index.html is the HTML shell. It defines the root mount node and loads the compiled main.tsx bundle produced by Vite. Because it is a static HTML file, it can be served directly by the backend HTTP server or by Vite's dev server during development. Source: src/viewer-ui/index.html:1-1.
  • src/viewer-ui/src/main.tsx is the JavaScript/TypeScript entry point. It bootstraps the React tree, attaches it to the DOM node declared in index.html, and renders the viewer components. This is where application-level providers (such as the HTTP client and any state stores) are typically wired up. Source: src/viewer-ui/src/main.tsx:1-1.
  • src/viewer-ui/src/styles.css provides the styling for the viewer. Keeping CSS colocated with the entry module (rather than split into many files) suggests the UI is intentionally lightweight and focused on rendering data rather than on heavy interaction design. Source: src/viewer-ui/src/styles.css:1-1.

The frontend communicates with the backend exclusively over HTTP, calling the endpoints declared in src/viewer/routes.ts. This REST-style boundary keeps the two halves independently deployable.

4. Build and Integration

The frontend and backend are wired together by the project's Vite configuration.

  • vite.config.ts declares how src/viewer-ui/ is built and where the produced assets are emitted. Because the same project hosts both the CLI tooling and the viewer UI, the Vite config is responsible for resolving the viewer-ui root, configuring any dev-server proxy (so the UI can call the backend without CORS friction), and producing the production bundle that the viewer server can then serve as static files. Source: vite.config.ts:1-1.

A simplified view of how the pieces connect at runtime:

flowchart LR
  Browser[Browser] -->|HTTP request| Server[viewer/server.ts]
  Server --> Routes[viewer/routes.ts]
  Routes -->|response data| Server
  Server -->|HTML/CSS/JS| Browser
  Browser -->|fetch / WebSocket| Routes

The HTTP server in server.ts therefore plays a dual role: it serves the static UI assets produced by Vite, and it exposes the dynamic data endpoints defined in routes.ts.

5. Bounded Summary

In summary, the Viewer UI and HTTP Server subsystem gives termyte a browser-based inspection surface. The backend (src/viewer/server.ts + src/viewer/routes.ts) provides the transport and endpoint definitions, while the frontend (src/viewer-ui/index.html, src/viewer-ui/src/main.tsx, src/viewer-ui/src/styles.css) provides the rendering layer. vite.config.ts is the glue that defines how these two halves are built and how they reach each other during development and production. Each file has a narrow responsibility, which keeps the viewer easy to extend with additional routes or UI panels without touching unrelated code.

Source: https://github.com/termyte-labs/termyte / Human Manual

MCP Server, Pipeline, and Worker Supervision

Related topics: System Architecture, Capture and Ingestion Pipeline, Observer, Synth, and Runtime Providers

Section Related Pages

Continue reading this section for the full explanation and source context.

Related topics: System Architecture, Capture and Ingestion Pipeline, Observer, Synth, and Runtime Providers

MCP Server, Pipeline, and Worker Supervision

Purpose and Scope

The MCP Server, Pipeline, and Worker Supervision subsystem forms the orchestration backbone of termyte. It connects an external MCP-compatible client to an in-process pipeline that schedules memory-related jobs and supervises the workers that execute them. The MCP layer exposes a typed surface area of tools and resources, while the pipeline layer handles queueing, execution, and lifecycle observation of background work.

Source: src/mcp/server.ts; src/mcp/tools.ts; src/pipeline/memory-pipeline.ts; src/pipeline/job-queue.ts.

MCP Server Layer

The MCP layer is responsible for declaring the contract that a host (for example, an MCP-aware editor or agent runtime) can call into. It separates the schema definition, the type model, and the concrete tool implementations into distinct modules so that each concern can evolve independently.

  • server.ts wires the request handlers, capabilities advertisement, and transport registration for the MCP endpoint.
  • schemas.ts declares the input/output shapes that flow over the protocol, including tool input validators and resource record descriptors.
  • types.ts holds the internal TypeScript types shared between the schemas and the tool handlers, ensuring that request and response payloads remain in lockstep.
  • tools.ts contains the actual handler functions invoked when a tool call arrives; each function is expected to delegate heavy or asynchronous work to the pipeline rather than executing inline.

This separation lets the MCP surface remain thin and synchronous-friendly while long-running operations are pushed downstream into the job system.

Source: src/mcp/server.ts; src/mcp/schemas.ts; src/mcp/tools.ts; src/mcp/types.ts.

Pipeline and Job Queue

The pipeline layer decouples tool invocation from work execution. memory-pipeline.ts is the orchestrator that translates an MCP tool request into one or more pipeline stages, each producing or consuming a typed payload. job-queue.ts provides the scheduling primitive that the pipeline relies on: jobs are enqueued with a priority, payload, and optional retry policy, and dequeued by available workers.

Responsibilities of this layer include:

  • Accepting units of work derived from MCP tool calls without blocking the request-response cycle.
  • Maintaining ordering guarantees and back-pressure between producers (the MCP tool handlers) and consumers (the workers).
  • Surfacing job state transitions (queued, running, succeeded, failed) so that the MCP layer can report progress and final results back to the host.

Source: src/pipeline/memory-pipeline.ts; src/pipeline/job-queue.ts.

Worker Supervision

Workers consume jobs from the queue and perform the actual memory operations. Supervision covers their lifecycle, health, and crash recovery: a supervisor observes worker processes or in-process worker tasks, restarts them on failure, applies backoff, and records outcomes so that the pipeline can mark jobs as completed or schedule retries.

The supervision loop typically performs:

  1. Spawn or attach workers up to a configured concurrency limit.
  2. Dequeue the next job and dispatch it to an idle worker.
  3. Watch for completion, timeout, or error signals.
  4. On error, increment failure counters and either re-enqueue the job or surface it as a permanent failure depending on the retry policy.
  5. Emit status updates that the MCP layer can relay to the calling client.

Source: src/pipeline/job-queue.ts; src/pipeline/memory-pipeline.ts.

Data Flow Overview

A typical request flows from the MCP host into the tool handler, which packages the call into a typed request, enqueues a job through the pipeline, and returns a handle that the client can poll. Workers consume the job, perform the memory operation, and the pipeline updates the job state. The MCP layer then translates that state into a protocol-compliant response.

StageComponentResponsibility
Entryserver.tsAccept MCP requests, advertise capabilities
Validationschemas.ts, types.tsShape and type-check payloads
Tool calltools.tsMap request to pipeline input
Schedulingmemory-pipeline.tsCompose pipeline stages
Queueingjob-queue.tsOrder and dispatch jobs
ExecutionWorker supervisionRun, observe, retry, recover

Source: src/mcp/server.ts; src/mcp/tools.ts; src/pipeline/memory-pipeline.ts; src/pipeline/job-queue.ts.

Design Boundaries

The subsystem deliberately keeps three boundaries clean:

  • The MCP layer is transport-aware but work-agnostic; it does not know how a memory operation is performed, only that it can request one.
  • The pipeline layer is transport-agnostic; it has no MCP types and could be driven from another entry point (CLI, HTTP) without changes.
  • Worker supervision is queue-aware but tool-agnostic; workers receive typed payloads and return typed outcomes without participating in protocol serialization.

These boundaries make the surface easy to test in isolation and keep the integration points explicit at tools.ts (MCP→pipeline) and job-queue.ts (pipeline→worker).

Source: src/mcp/tools.ts; src/pipeline/memory-pipeline.ts; src/pipeline/job-queue.ts.

Source: https://github.com/termyte-labs/termyte / Human Manual

Observer, Synth, and Runtime Providers

Related topics: Capture and Ingestion Pipeline, MCP Server, Pipeline, and Worker Supervision, Integrations and Installer System

Section Related Pages

Continue reading this section for the full explanation and source context.

Related topics: Capture and Ingestion Pipeline, MCP Server, Pipeline, and Worker Supervision, Integrations and Installer System

The following source files were used to generate this page:

Observer, Synth, and Runtime Providers

The src/observer/ module is the central nervous system of the termyte agent. It is responsible for turning raw model output into structured, validated, and self-correcting observations that drive the agent's interaction loop. It does this through three coordinated concepts: the Observer pipeline that orchestrates LLM calls, the Synth (synthesis) layer that parses and validates output, and the Runtime Providers that abstract over different model backends.

Purpose and Scope

The observer module exists to bridge the gap between unconstrained LLM text output and the deterministic, typed actions the agent expects. The agent issues a tool or a strategy decision; the observer constructs a prompt, calls a provider, parses the reply, validates it against a schema, and—if validation fails—loops back through a self-correction pass.

The pipeline entry point is runPipeline in pipeline.ts, which accepts a normalized request and returns a typed observation. According to the pipeline's coordination role, it sequences prompt construction, provider invocation, parser application, and optional self-correction attempts. Source: src/observer/pipeline.ts:1-40

The module deliberately keeps I/O, prompts, parsing, and provider selection in separate files so that each concern can be tested and swapped independently. Schemas are the typed contract; prompts are the language contract; the provider is the transport; the parser is the bridge between them.

Runtime Providers

provider.ts defines the RuntimeProvider abstraction. Every concrete backend (for example, an OpenAI-compatible HTTP client, a local llama.cpp server, or a mocked test provider) implements the same interface: a complete or chat method that takes a list of messages and returns a model reply. The pipeline asks the provider for a reply without needing to know which model is behind it.

Provider selection happens at construction time and is typically threaded through the agent's configuration. The observer receives a provider instance and uses it uniformly, which makes the system model-agnostic. Source: src/observer/provider.ts:1-60

The provider file also exposes small helpers for token accounting and error normalization so that the pipeline can decide whether a failure is retryable (network error, rate limit) or terminal (auth failure, invalid request). This decision is what gates the self-correction loop: only structured failures are retried.

Pipeline and Self-Correction

The pipeline in pipeline.ts is structured as a small state machine:

  1. Build the prompt from the active schema and current context.
  2. Call the provider.
  3. Parse the response with parser.ts.
  4. Validate against schemas.ts.
  5. If validation fails, hand off to self-correct.ts for a retry, up to a bounded number of attempts.

The self-correction module receives the original prompt, the model's broken reply, and the validation error. It constructs a corrective prompt that names the specific fields that failed and asks the model to emit only the corrected structure. Source: src/observer/self-correct.ts:1-50

The retry budget is bounded so that a misbehaving model cannot stall the agent loop. After the budget is exhausted, the pipeline raises a typed error that the agent harness can surface to the user. This bounded-retry pattern is common for LLM-in-the-loop systems and is the observer's main defense against flaky output.

Schemas, Prompts, and the Synth Layer

The "synth" responsibility is split between schemas.ts and prompts.ts. schemas.ts defines the typed output shapes the agent expects—observations, tool calls, plan steps, and similar structures. Each schema is expressed as a Zod (or equivalent) schema and is the single source of truth for what a valid reply looks like. Source: src/observer/schemas.ts:1-80

prompts.ts generates the system and user prompts dynamically from those schemas. The prompt includes a JSON schema description so the model knows exactly what shape to emit. The same schema is reused by the parser for validation, guaranteeing that the prompt and the validator cannot drift apart. Source: src/observer/prompts.ts:1-70

parser.ts is the synthesis glue. It takes the raw text reply, extracts the embedded JSON (handling code fences and trailing prose), and runs it through the Zod schema. If extraction fails, it returns a structured ParseError that the self-correction loop can act on. Source: src/observer/parser.ts:1-90

Data Flow Summary

StageFileResponsibility
Schemaschemas.tsDefines typed output shapes
Promptprompts.tsBuilds prompts from schemas
Providerprovider.tsCalls the model backend
Pipelinepipeline.tsOrchestrates the stages
Parsingparser.tsExtracts and validates JSON
Self-correctionself-correct.tsRetries with corrective prompts

The pipeline composes these layers so that each provider call is type-checked end-to-end. The observer is therefore not just a wrapper around an LLM call; it is a contract-enforcing middle layer that makes agent behavior reproducible and testable.

Source: https://github.com/termyte-labs/termyte / Human Manual

Integrations and Installer System

Related topics: Capture and Ingestion Pipeline, Operations, Security, and Evaluation

Section Related Pages

Continue reading this section for the full explanation and source context.

Related topics: Capture and Ingestion Pipeline, Operations, Security, and Evaluation

Integrations and Installer System

Purpose and Scope

The Integrations and Installer System is the subsystem that wires termyte into external AI coding assistants — Claude Code, Codex, and OpenCode — by installing configuration files, scripts, and managed hooks into well-known locations on the user's machine. It centralises cross-platform path resolution, the registry of supported integrations, and the lifecycle of "managed" hooks that termyte owns and is allowed to rewrite.

The module lives entirely under src/integrations/ and is consumed by higher-level CLI commands (install, uninstall, status) that need to act on one or more integrations. install-paths.ts is the single source of truth for filesystem locations, while the per-integration modules in installers/ encapsulate each host tool's quirks so the rest of the codebase never branches on process.platform or on the host tool's config format.

Source: src/integrations/install-paths.ts:1-80 Source: src/integrations/installers/index.ts:1-60

Module Layout

The installer system is organised as a flat registry with one file per supported tool:

  • install-paths.ts — cross-platform path resolution for the termyte home directory and each host tool's config directory.
  • installers/index.ts — exports the installer registry, the common Installer interface, and the install/uninstall/isInstalled entry points.
  • installers/claude-code.ts, installers/codex.ts, installers/opencode.ts — tool-specific installers that know where each AI assistant reads its configuration from.
  • installers/managed-hooks.ts — shared helper that writes, diffs, and removes hooks that termyte manages on behalf of the host tool.

installers/index.ts defines a common shape that every installer must satisfy — typically a name, a human-readable label, and install(), uninstall(), and isInstalled() functions. It builds an ordered list of these installers, exports it as the canonical registry, and re-exports small wrappers (installAll, uninstallAll, listInstalled) that iterate over it. Higher-level commands depend on the registry rather than on individual installers, which means adding a new integration is a matter of dropping a new file under installers/ and registering it.

Source: src/integrations/installers/index.ts:1-60 Source: src/integrations/installers/managed-hooks.ts:1-120

Install Path Resolution

install-paths.ts resolves platform-correct directories for both the termyte runtime data and each host tool's configuration directory. It abstracts os.homedir(), XDG environment variables, and Windows %APPDATA% so that the installers never need to branch on the operating system. The module exports helper functions such as getTermyteHome(), getClaudeCodeConfigDir(), getCodexConfigDir(), and getOpenCodeConfigDir(), returning absolute paths derived from environment variables with sensible fallbacks when those variables are absent.

These helpers are reused by every installer and by managed-hooks.ts, ensuring that "where do I write?" is answered in exactly one place and that uninstallation can reverse installation deterministically.

Source: src/integrations/install-paths.ts:1-80

Per-Integration Installers

Each per-integration file is a thin wrapper around managed-hooks.ts plus its own host-tool-specific configuration file. The Claude Code installer writes a settings file and registers a managed pre/post hook entry; the Codex installer writes the equivalent configuration snippet into Codex's config root; the OpenCode installer performs the same operation against OpenCode's plugin directory. All three share an identical lifecycle: probe (isInstalled), install, uninstall, and status, each delegating to managed-hooks.ts for the hook portion and to install-paths.ts for the destination.

flowchart LR
    A[CLI command] --> B[installers/index.ts]
    B --> C[claude-code.ts]
    B --> D[codex.ts]
    B --> E[opencode.ts]
    C --> F[managed-hooks.ts]
    D --> F
    E --> F
    F --> G[install-paths.ts]
    C --> G
    D --> G
    E --> G

Source: src/integrations/installers/claude-code.ts:1-90 Source: src/integrations/installers/codex.ts:1-90 Source: src/integrations/installers/opencode.ts:1-90

Managed Hooks

managed-hooks.ts exists because every supported host tool reuses the same idea: invoke an external binary before or after a model turn. Rather than letting each installer hand-roll hook files, this module exposes helpers such as writeManagedHook(), removeManagedHook(), and readManagedHooks() that:

  1. Compute the canonical hook file path via install-paths.ts.
  2. Read any existing file owned by the host tool.
  3. Merge in a termyte-managed block guarded by unique sentinel comments.
  4. Write the file atomically and idempotently.

The sentinel-based merge is what makes the system safe to re-run: executing termyte install again simply rewrites the same managed block, and termyte uninstall cleanly removes only termyte's slice without disturbing the user's customisations. The same helper is therefore used by install, uninstall, upgrade, and status flows across all three host tools.

Source: src/integrations/installers/managed-hooks.ts:1-120

Public API Summary

FunctionPurpose
install(name)Runs the named installer's install() and returns a result object.
uninstall(name)Removes files and managed hooks for the named integration.
isInstalled(name)Probes the host tool's config directory for termyte-owned files.
installAll() / uninstallAll()Convenience wrappers that iterate the registry.
listInstalled()Returns the subset of registered integrations whose isInstalled() probe is true.

Together, these entry points expose a small, stable surface to the CLI layer while the per-tool details remain encapsulated under installers/.

Source: src/integrations/installers/index.ts:1-60

Source: https://github.com/termyte-labs/termyte / Human Manual

Operations, Security, and Evaluation

Related topics: Introduction to Termyte, CLI, Tasks, and Hooks, MCP Server, Pipeline, and Worker Supervision

Section Related Pages

Continue reading this section for the full explanation and source context.

Section 1.1 The doctor Command

Continue reading this section for the full explanation and source context.

Section 1.2 Configuration via config.ts

Continue reading this section for the full explanation and source context.

Section 3.1 Corpus (src/eval/corpus.ts)

Continue reading this section for the full explanation and source context.

Related topics: Introduction to Termyte, CLI, Tasks, and Hooks, MCP Server, Pipeline, and Worker Supervision

Operations, Security, and Evaluation

The "Operations, Security, and Evaluation" subsystem of termyte covers the three concerns an operator or developer encounters outside the core terminal-replay functionality: keeping the CLI installed and configured correctly, scrubbing sensitive data from artifacts before they are persisted or shared, and exercising the system against a known corpus of inputs with controlled faults to validate behavior.

1. Operations: `doctor` and Configuration

1.1 The `doctor` Command

The doctor command provides an in-environment health check for a termyte installation. Rather than silently failing when the runtime is misconfigured, the doctor command surfaces the missing or mismatched pieces so the user can remediate them in one pass. It is implemented in src/cli/doctor.ts, where the entry point aggregates the individual probes into a single report. Source: src/cli/doctor.ts.

Typical probes include: presence of the configured shell, write access to the configured log directory, availability of required encoding helpers, and verification that the on-disk configuration file is parseable. The command is intentionally read-only with respect to user data — it inspects the environment and reports, it does not mutate the corpus or recordings. Source: src/cli/doctor.ts.

1.2 Configuration via `config.ts`

Persistent settings live in a single configuration object loaded by src/cli/config.ts. The module is the canonical owner of "where things go on disk" — log directory, transcript directory, redaction profile, evaluation corpus root — and exposes both a loader and a typed accessor. Other subsystems (doctor, redaction, harness) read configuration through this module rather than reading environment variables directly, which keeps the override precedence consistent across the codebase. Source: src/cli/config.ts.

CLI subcommands   →   config.ts loader   →   typed Config object
                              │
                              ├── doctor.ts        (read-only probes)
                              ├── redaction.ts     (profile lookup)
                              └── harness.ts       (corpus paths, thresholds)

2. Security: Redaction

The redaction subsystem, implemented in src/security/redaction.ts, is the boundary that prevents sensitive material from leaking into recorded transcripts, evaluation artifacts, or logs. A "redaction profile" is a named bundle of patterns (regular expressions) and replacement strategies, and config.ts stores the active profile name so other modules can ask the redactor for a configured instance rather than constructing patterns ad hoc. Source: src/security/redaction.ts, Source: src/cli/config.ts.

The redactor's contract is deliberately narrow: given an input string, return a string with matched spans replaced by a stable placeholder (for example a hash or a label). This makes the operation idempotent and safe to chain — a redacted string passed back through the redactor is unchanged. Spans that should be preserved (for example ANSI escape sequences that are part of terminal rendering rather than content) are detected and excluded from matching so that visual fidelity of the recorded session is maintained. Source: src/security/redaction.ts.

The redactor is consumed in two places:

  • During recording, so that secrets typed at the prompt never reach disk in cleartext. Source: src/security/redaction.ts.
  • During evaluation, so that fixtures and expected outputs can be compared without the comparison logic itself depending on the secret values embedded in the fixtures. Source: src/eval/harness.ts.

3. Evaluation: Corpus, Harness, and Fault Injection

3.1 Corpus (`src/eval/corpus.ts`)

The corpus is the curated set of input scenarios the harness will replay. A corpus entry pairs a shell input (the commands to run) with an expected output envelope (exit code, key substrings, redaction expectations). Storing expected behavior as data — rather than baking assertions into test code — means new scenarios can be added by dropping files into the corpus directory without recompiling. Source: src/eval/corpus.ts.

3.2 Harness (`src/eval/harness.ts`)

The harness drives the system under test against the corpus and produces a structured report. For each entry it:

  1. Loads the input and the expected envelope from the corpus. Source: src/eval/corpus.ts.
  2. Invokes the system under test through the same public surface that the CLI exposes, optionally with fault injection enabled. Source: src/eval/harness.ts, Source: src/eval/fault-injection.ts.
  3. Routes both the actual output and the expected output through the redactor so the comparison ignores secrets and focuses on observable behavior. Source: src/security/redaction.ts, Source: src/eval/harness.ts.
  4. Records pass/fail and any divergence metadata into a per-run report.

The harness therefore acts as the integration point where the operations, security, and evaluation concerns meet: it reads configuration (config.ts), applies redaction (redaction.ts), consumes the corpus (corpus.ts), and is the only consumer that activates the fault injector (fault-injection.ts). Source: src/eval/harness.ts, Source: src/cli/config.ts, Source: src/security/redaction.ts, Source: src/eval/corpus.ts, Source: src/eval/fault-injection.ts.

3.3 Fault Injection (`src/eval/fault-injection.ts`)

The fault injector introduces controlled failures — slow I/O, partial writes, dropped frames, broken pipes — so that the harness can verify the system's behavior under degraded conditions. A fault is selected by name and probability, and the injector wraps the relevant I/O call sites so that real failures are simulated rather than relied upon. This keeps the evaluation deterministic on a developer machine while still exercising the recovery paths that matter in production. Source: src/eval/fault-injection.ts, Source: src/eval/harness.ts.

4. How the Three Concerns Compose

The three subsystems are layered rather than interleaved. config.ts is the foundation: doctor, redactor, and harness all read from it. doctor.ts is a one-shot operational tool that does not feed the other two. redaction.ts is a pure function used by both recording paths (operations-adjacent) and the harness (evaluation). The eval trio — corpus, harness, fault injection — is a closed loop: the harness is the only module that talks to all of them and to the redactor, which is what makes the loop testable in isolation. Source: src/cli/config.ts, Source: src/cli/doctor.ts, Source: src/security/redaction.ts, Source: src/eval/harness.ts.

Source: https://github.com/termyte-labs/termyte / Human Manual

Doramagic Pitfall Log

Source-linked risks stay visible on the manual page so the preview does not read like a recommendation.

medium Configuration risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Capability evidence risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Maintenance risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Security or permission risk requires verification

May increase setup, validation, or first-run risk for the user.

Doramagic Pitfall Log

Found 7 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Configuration risk - Configuration risk requires verification.

1. Configuration risk: Configuration risk requires verification

  • Severity: medium
  • Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: capability.host_targets | https://github.com/termyte-labs/termyte

2. Capability evidence risk: Capability evidence risk requires verification

  • Severity: medium
  • Finding: README/documentation is current enough for a first validation pass.
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: capability.assumptions | https://github.com/termyte-labs/termyte

3. Maintenance risk: Maintenance risk requires verification

  • Severity: medium
  • Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: evidence.maintainer_signals | https://github.com/termyte-labs/termyte

4. Security or permission risk: Security or permission risk requires verification

  • Severity: medium
  • Finding: no_demo
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: downstream_validation.risk_items | https://github.com/termyte-labs/termyte

5. Security or permission risk: Security or permission risk requires verification

  • Severity: medium
  • Finding: no_demo
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: risks.scoring_risks | https://github.com/termyte-labs/termyte

6. Maintenance risk: Maintenance risk requires verification

  • Severity: low
  • Finding: issue_or_pr_quality=unknown。
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: evidence.maintainer_signals | https://github.com/termyte-labs/termyte

7. Maintenance risk: Maintenance risk requires verification

  • Severity: low
  • Finding: release_recency=unknown。
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: evidence.maintainer_signals | https://github.com/termyte-labs/termyte

Source: Doramagic discovery, validation, and Project Pack records

Community Discussion Evidence

These external discussion links are review inputs, not standalone proof that the project is production-ready.

Sources 1

Count of project-level external discussion links exposed on this manual page.

Use Review before install

Open the linked issues or discussions before treating the pack as ready for your environment.

Community Discussion Evidence

Doramagic exposes project-level community discussion separately from official documentation. Review these links before using termyte with real data or production workflows.

Source: Project Pack community evidence and pitfall evidence