Skip to content

Repository files navigation

πŸ›Έ Coding-Harness

An advanced, autonomous, Claude-Code-style AI agent execution loop built completely from scratch in TypeScript and running under Bun.

It natively orchestrates tool-calling, multi-layered context memory, tree-structured session persistence, and permission gating without using external agent frameworks (like LangChain or LangGraph).


πŸ“Ή Demo

🎬 Watch Coding Harness in Action:

Coding-Harness.4.mp4

Coding-Harness.4.mp4

πŸ“‹ Table of Contents


✨ Features

  • πŸ’» Dynamic Interactive CLI REPL: Live streaming of assistant responses, formatted πŸ’­ Thinking blocks, tool call parameters, execution results, and runtime token dashboard.
  • βš™οΈ Headless Mode: Non-interactive automation entry point that accepts --task and --cwd and outputs structured JSON results for script/CI integration.
  • 🧠 Advanced Context Engineering: Automatic file read staleness invalidation (tombstoning), tool-call microcompaction, LLM summarization compaction, and cache_control breakpoint injection.
  • 🌳 Tree-Structured Session Storage: Append-only JSONL event-log format supporting linear history, parent-pointer branching, leaf rewinding, and session resume capabilities.
  • πŸš€ Dual Tool Execution Modes: Switch dynamically between Parallel execution (running independent read/write calls concurrently via Promise.all) and Sequential execution.
  • πŸ“ Range-Targeted Editing with Drift Recovery: Line-targeted find-and-replace (startLine/endLine) with sliding-window offset recovery (Β±10 lines tolerance) and mismatch diagnostics.
  • πŸ” Fast Search Capabilities: Ripgrep-backed (rg) recursive text pattern matching with Bun-glob fallback and wildcard glob scanning.
  • πŸ€– Provider Agnostic: Seamlessly switch between local Ollama models (qwen3:14b, qwen3:8b, llama3.1:8b) and cloud Gemini models (gemini-1.5-flash, gemini-1.5-pro, gemini-3.1-flash-lite).
  • πŸ›‘οΈ Permission Gate & Policy Engine: Safety barrier enforcing user confirmation before running mutating actions (writes, edits, shell commands) with policy-based auto-approval.
  • πŸ›°οΈ Read-Only Sub-Agent Dispatch: Isolated sub-agent worker context for performing background research without mutating workspace files.

πŸ—οΈ High-Level Architecture

The framework is decoupled into modular layers, separating execution control, context lifecycle, persistence, tool execution, and model connectivity:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                          CLI Layer                               β”‚
β”‚     Interactive REPL (repl.ts)   β”‚   Headless CLI (headless.ts)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                  β”‚
                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
                         β”‚   Agent Core    β”‚
                         β”‚ (src/agent.ts)  β”‚
                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                  β”‚
       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚                          β”‚                          β”‚
β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ ContextManager β”‚       β”‚ SessionStore    β”‚       β”‚ PermissionGate   β”‚
β”‚ - History      β”‚       β”‚ - JSONL Tree    β”‚       β”‚ - Read/Mutate    β”‚
β”‚ - Invalidation β”‚       β”‚ - Branching     β”‚       β”‚   Classification β”‚
β”‚ - Compaction   β”‚       β”‚ - Path Resolve  β”‚       β”‚ - Policy Engine  β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚
       β”‚                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Ίβ”‚  ToolRegistry   │◄────────┐
       β”‚                 β”‚ - 10 Built-ins  β”‚         β”‚
       β”‚                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β”‚
       β”‚                          β”‚                  β”‚
       β”‚                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚                 β”‚ Sub-Agent Engineβ”‚ β”‚ Tool Execution β”‚
       β”‚                 β”‚  (Read-only)    β”‚ β”‚ Sequential/    β”‚
       β”‚                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ Parallel       β”‚
       β”‚                                     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  ChatModelClient Interface                  β”‚
β”‚       OllamaClient (Local)   β”‚   GeminiClient (API)         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

🧠 Context Management Engine

The ContextManager (src/context/contextManager.ts) handles memory representation, context limits, and message cleanup across turns.

1. File Staleness Tracking & Tombstoning

When a tool modifies a file (write_file or edit_file), any earlier read_file output for that same file path residing in message history becomes outdated and potentially misleading to the model.

  • ContextManager.invalidateStaleReads(mutatedPath) scans history for past read_file tool results matching the mutated file.
  • It overwrites the old content with a tombstone message:
    [File content of <path> has been modified by a subsequent edit/write tool call. This read result is now stale and has been invalidated to save context space.]
    
  • Benefits: Prevents context window bloat, eliminates stale code references, and reduces token cost.

2. Microcompaction

Continuous passive optimization (microcompact() in src/context/compaction.ts) runs before every turn. It scans history and deduplicates redundant tool operations (such as repeated identical file reads or superseded checks), replacing duplicated payload blocks with compact references.

3. LLM Summarization Compaction

When total session tokens exceed the configured threshold (default: 8,000 tokens):

  1. compactIfNeeded() invokes summarizeHistory().
  2. The LLM summarizes the oldest 50% of the message transcript into a structured system summary block.
  3. The original old turns are removed from the active context window, and the summary is inserted as a system block.
  4. Active tool call/result pairing structures are preserved to maintain model validation constraints.

4. Ephemeral Prompt Caching

ContextManager.getPayload() automatically attaches cache_control: { type: "ephemeral" } metadata to:

  • The base System Prompt (containing runtime environmental rules and tool specifications).
  • The AGENT.md Project Memory block.

This enables models supporting prompt caching (e.g. Anthropic / Gemini) to skip redundant prompt processing overhead across chat turns.

5. Workspace Project Memory (AGENT.md)

At startup, Agent checks for an AGENT.md file in the workspace root. If present, its contents are injected into system context as persistent project memory (coding conventions, architecture guidelines, forbidden files).


πŸ’Ύ Session Management & Tree Persistence

Session persistence (src/session/sessionStore.ts) uses an append-only JSONL format to guarantee crash-resilient storage and support non-linear conversation branching.

1. Append-Only JSONL Tree Storage

Sessions are saved in ~/.harness/agent/session/--<encoded-cwd>--/<sessionId>.jsonl.

Each line in the file represents a single SessionEntry with strict metadata:

export interface BaseEntry {
  id: string;          // Unique entry UUID/timestamp identifier
  parentId: string | null; // Pointer to preceding entry ID
  timestamp: string;   // ISO timestamp
}

Supported Entry Types:

  • SessionMessageEntry: User, assistant, or tool interaction messages.
  • ThinkingLevelChangeEntry: Model thinking parameter changes.
  • ModelChangeEntry: Model or provider switches.
  • CompactionEntry: System summary generated during context compaction.
  • BranchSummaryEntry: Context state preserved when creating alternative branches.
  • CustomEntry / CustomMessageEntry: Metadata extensions and hook payload data.
  • LabelEntry / SessionInfoEntry: User annotations and session summaries.

2. Tree Branching & Leaf Pointer Rewinding

Because every entry explicitly references a parentId, history forms a Directed Acyclic Graph (DAG) / Tree:

           β”Œβ”€β”€β”€ Entry 3 (Branch A) ─── Entry 4A
Entry 1 ── Entry 2
           └─── Entry 3 (Branch B) ─── Entry 4B  <-- leafId
  • branch(branchFromId): Rewinds the session's active leafId back to an earlier entry. Subsequent entries are appended as children of branchFromId, creating a side branch without altering original history.
  • branchWithSummary(branchFromId, summary): Creates a branch and records a BranchSummaryEntry capturing context from the abandoned branch.
  • resetLeaf(): Rewinds the leaf pointer to root, allowing full conversation restarts.

3. Path Resolution & Context Rebuilding

When preparing messages to send to the LLM:

  1. buildSessionPath(entries, leafId) starts at leafId and walks backwards via parentId pointers to the root. It reverses the list to reconstruct the active linear path.
  2. buildContextEntries(path) inspects the resolved path for any CompactionEntry. If found, it drops raw messages prior to firstKeptEntryId and prefixes context with the compaction summary.
  3. sessionEntryToContextMessages() converts the entries into standard model Message objects.

4. Deferred Disk Flushing

To prevent creating empty session files when users open and immediately close the CLI, Session uses deferred flushing:

  • New sessions accumulate entries in memory (flushed = false).
  • Disk creation and bulk writing (flush()) occur only when the first assistant message is generated.
  • After flushing, subsequent entries are appended synchronously (fs.appendFileSync).

5. Automatic Version Migrations

Session files include a version header and automatically upgrade legacy formats upon loading:

  • v1 β†’ v2: Upgrades flat message arrays to tree nodes (id, parentId) and converts index pointers to entry IDs.
  • v2 β†’ v3: Normalizes legacy roles (hookMessage β†’ custom).

6. Session Discovery & Resumption

  • SessionStore.getLatestSessionId() reads latest_id.txt to identify the most recent session for the current workspace.
  • The REPL CLI automatically detects existing sessions and prompts the user to resume or start fresh upon launch.
  • Dynamic /models changes, /mode toggling, and clear commands immediately sync session state.

πŸ› οΈ Tool Ecosystem

The harness provides 10 core tools in src/tools/:

Tool Name Type Description
read_file Read-only Reads text files with line numbering, offset paging, and line range slicing.
write_file Mutating Creates new files or overwrites existing files completely.
edit_file Mutating Performs range-targeted find-and-replace using startLine/endLine, with sliding-window line drift recovery (Β±10 lines tolerance) and exact line mismatch diagnostics.
run_command Mutating Executes shell commands on the host machine. Gated by permission checks and safety policies.
check_syntax Read-only Validates JavaScript/TypeScript files using Bun's internal bundler compiler to report syntax errors prior to execution.
glob Read-only Performs fast wildcard pattern file and directory scanning across the workspace.
grep Read-only Executes workspace text searches using system ripgrep (rg) with a native Bun glob fallback.
todo_read Read-only Reads the persistent checklist file (.todo.md).
todo_write Mutating Updates and manages the project task checklist (.todo.md).
dispatch_subagent Read-only Spawns an isolated, read-only sub-agent to perform deep research tasks without file mutation access.

πŸ€– Multi-Provider LLM Support

The harness abstracts LLM integrations behind a unified ChatModelClient interface (src/providers/types.ts):

export interface ChatModelClient {
  chatStream(
    messages: Message[],
    tools: ToolDefinition[],
    onChunk: (chunk: { content: string; thinking: string; toolCalls: ToolCall[] }) => void
  ): Promise<Message>;
}

Supported Providers:

  1. Ollama (src/providers/ollama.ts):
    • Native streaming, thinking tag extraction (<think>...</think>), raw tool payload parsing, and token usage reporting.
    • Built-in support for qwen3:14b, qwen3:8b, and llama3.1:8b.
  2. Gemini (src/providers/gemini.ts):
    • Google Generative AI REST API streaming integration.
    • Handles thought signatures (thought_signature), structured tool declarations, and usage metadata.
    • Built-in support for gemini-1.5-flash, gemini-1.5-pro, and gemini-3.1-flash-lite.

Model switching can be done interactively during REPL sessions using the /models command.


πŸš€ Execution Modes

1. Interactive CLI REPL

Launch using bun start or bun run src/cli/repl.ts:

  • Features colored streaming responses and thinking visualization.
  • Displays live tool invocation summaries and execution results.
  • Includes interactive command shortcuts:
    • /models: Open interactive model selector menu.
    • /mode: Toggle between parallel and sequential tool execution.
    • clear: Reset history and delete current session.
    • exit / quit: Terminate the REPL.
  • Displays token usage metrics and context window percentage after every turn.

2. Headless Automation CLI

Launch using bun run src/cli/headless.ts:

bun run src/cli/headless.ts --task "Fix bug in search parser" --cwd "/path/to/repo" --max-iterations 30
  • Redirects logs to stderr and prints clean JSON results to stdout:
{
  "status": "success",
  "output": "Task completed successfully...",
  "filesChanged": ["src/parser.ts"]
}

3. Parallel vs. Sequential Tool Execution

The Agent loop supports two tool execution modes:

  • Parallel Mode (Default): When the model outputs multiple tool calls in a single turn, permissions are checked sequentially, and all approved tool executions run concurrently via Promise.all.
  • Sequential Mode: Executes tool calls one by one in serial order.

4. Mid-Run User Steering Intercept

Pressing Ctrl+C (SIGINT) while the agent is running tool cycles triggers mid-run steering:

  • The agent loop pauses after the current tool execution completes.
  • Prompts the user for a steering instruction: steer instruction (or press Enter to resume)>.
  • Injects [User Steering Instruction]: <input> into conversation history without destroying session context.
  • Pressing Ctrl+C a second time forces an immediate program exit.

🚦 Permission Gate & Safety Engine

PermissionGate (src/permissions/permissionGate.ts) acts as a security barrier between the agent and host machine operations:

  • Read-Only Operations: (read_file, grep, glob, todo_read, check_syntax, dispatch_subagent) execute automatically.
  • Mutating Operations: (write_file, edit_file, run_command, todo_write) require user confirmation in interactive mode.
  • Policy Engine Auto-Approval: Evaluates safe command patterns (e.g. git status, ls, npm test) against policy rules to bypass prompts for non-destructive operations.
  • Dangerous Command Blocking: Rejects destructive system commands (e.g. rm -rf /) automatically.
  • Auto-Confirm Option: autoConfirm: true (used in headless mode) automatically approves non-blocked mutating actions.

⚑ Quick Start

Prerequisites

  1. Install Bun (v1.0+):
    powershell -c "irm bun.sh/install.ps1 | iex"
  2. Install and launch Ollama (optional if using Gemini API key):
    ollama pull qwen3:14b
    ollama serve
  3. (Optional) Configure Gemini API key in src/.env or project root .env:
    GEMINI_API_KEY=your_gemini_api_key_here

Installation

git clone https://github.com/raghuttama-dev/Coding-harness.git
cd Coding-harness
bun install

Running the Interactive REPL

bun start

Running Headless Tasks

bun run src/cli/headless.ts --task "Refactor search utility to use async/await" --cwd "."

Running Unit Tests

Execute the Vitest-compatible Bun test suite covering tools, context compaction, staleness tracking, session storage, and execution modes:

bun test

πŸ“ Repository Structure

Coding-harness/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ agent.ts                  # Core execution loop, steering, and turn orchestrator
β”‚   β”œβ”€β”€ client.ts                 # Provider export bridge
β”‚   β”œβ”€β”€ cli/
β”‚   β”‚   β”œβ”€β”€ repl.ts               # Interactive terminal REPL interface
β”‚   β”‚   └── headless.ts           # Non-interactive JSON automation CLI entry point
β”‚   β”œβ”€β”€ context/
β”‚   β”‚   β”œβ”€β”€ contextManager.ts     # History state, staleness tombstoning, token tracking
β”‚   β”‚   └── compaction.ts         # Microcompaction & LLM summarization compaction
β”‚   β”œβ”€β”€ permissions/
β”‚   β”‚   └── permissionGate.ts     # Read/mutate safety gate and command policy engine
β”‚   β”œβ”€β”€ providers/
β”‚   β”‚   β”œβ”€β”€ types.ts              # ChatModelClient, Message, and ToolCall interface types
β”‚   β”‚   β”œβ”€β”€ ollama.ts             # Ollama API client implementation
β”‚   β”‚   └── gemini.ts             # Gemini REST API client implementation
β”‚   β”œβ”€β”€ session/
β”‚   β”‚   └── sessionStore.ts       # Append-only JSONL tree persistence, branching, and migrations
β”‚   β”œβ”€β”€ tools/
β”‚   β”‚   β”œβ”€β”€ index.ts              # Unified ToolRegistry definition
β”‚   β”‚   β”œβ”€β”€ read.ts               # Range-sliced file reader with line numbers
β”‚   β”‚   β”œβ”€β”€ write.ts              # File creator and overwriter
β”‚   β”‚   β”œβ”€β”€ edit.ts               # Targeted find-replace editor with sliding drift recovery
β”‚   β”‚   β”œβ”€β”€ bash.ts               # Command execution tool
β”‚   β”‚   β”œβ”€β”€ checkSyntax.ts        # JS/TS syntax validator (Bun build compiler)
β”‚   β”‚   β”œβ”€β”€ glob.ts               # Wildcard pattern file scanner
β”‚   β”‚   β”œβ”€β”€ grep.ts               # Ripgrep-backed workspace search tool
β”‚   β”‚   β”œβ”€β”€ todo.ts               # Task list checklist management (.todo.md)
β”‚   β”‚   β”œβ”€β”€ subagent.ts           # Read-only background sub-agent dispatcher
β”‚   β”‚   β”œβ”€β”€ activeClient.ts       # Active LLM client reference container
β”‚   β”‚   └── types.ts              # Tool interface contracts
β”‚   └── tests/
β”‚       β”œβ”€β”€ context.test.ts       # Staleness and compaction test suite
β”‚       β”œβ”€β”€ executionMode.test.ts # Parallel vs sequential mode test suite
β”‚       β”œβ”€β”€ gemini.test.ts        # Gemini provider test suite
β”‚       β”œβ”€β”€ search.test.ts        # Glob and Grep test suite
β”‚       β”œβ”€β”€ tools.test.ts         # File edit, read, syntax, and todo tool test suite
β”‚       └── v4.test.ts            # Session tree, diff, policy engine, and subagent test suite
β”œβ”€β”€ AGENT.md                      # Workspace project memory rules file
β”œβ”€β”€ agent-harness-architecture.md # Architecture specification document
β”œβ”€β”€ pi-agent-session-storage.md   # Session storage specification document
β”œβ”€β”€ package.json                  # Dependencies and run scripts
└── tsconfig.json                 # TypeScript compiler configuration

πŸ“œ License

MIT License. Built for autonomous AI agent research and development.

About

πŸ›Έ A zero-dependency autonomous terminal coding agent CLI built from scratch in TypeScript & Bun, inspired by the pi-agent architecture. Features tree-structured session persistence, context compaction, staleness tombstoning, and parallel tool loops.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages