Overall: TypeScript plugin + Rust worker process over a session-scoped NDJSON bridge. A unified CLI (packages/aft-cli/) serves setup/doctor across all harnesses; shared transport, binary resolution, and ONNX helpers live in packages/aft-bridge/.
Key Characteristics:
- Use
packages/opencode-plugin/src/index.tsandpackages/pi-plugin/src/index.tsto register harness tools and map them onto the unifiedtool_callcommand. - Use
packages/aft-bridge/src/bridge.tsandpackages/aft-bridge/src/pool.tsas the shared transport layer, isolating oneaftprocess per project root. - Use
packages/aft-cli/src/index.tsas the unified setup/doctor CLI across all harnesses. - Use
crates/aft/src/commands/handlers to keep protocol dispatch thin and command logic modular, withcrates/aft/src/commands/tool_call.rsacting as the single endpoint for tool invocation routing. - Use
crates/aft/src/edit.rs,crates/aft/src/format.rs,crates/aft/src/callgraph.rs,crates/aft/src/callgraph_store/mod.rs,crates/aft/src/semantic_index.rs,crates/aft/src/search_index.rs,crates/aft/src/compress/,crates/aft/src/patch/,crates/aft/src/pty_render.rs,crates/aft/src/response_finalize.rs, andcrates/aft/src/lsp/as shared engines behind multiple commands.
OpenCode integration layer:
- Purpose: Register tools, load config, and attach post-execution metadata.
- Location:
packages/opencode-plugin/src/index.ts - Contains: Plugin bootstrap, tool-surface selection, hoisting logic, disabled-tool filtering, session-directory management, RPC server, auto-update checker hook
- Depends on:
packages/opencode-plugin/src/config.ts,packages/opencode-plugin/src/tools/*.ts,packages/aft-bridge/ - Used by: OpenCode plugin loading through
@cortexkit/aft-opencode
Pi integration layer:
- Purpose: Register tools, load config, and manage Pi host notifications.
- Location:
packages/pi-plugin/src/index.ts - Contains: Plugin bootstrap, tool-surface selection, hoisting logic, LSP auto-install (npm/github/project-relevance probes),
aft-statuscommand - Depends on:
packages/pi-plugin/src/config.ts,packages/pi-plugin/src/tools/*.ts,packages/pi-plugin/src/commands/*.ts,packages/aft-bridge/ - Used by: Pi coding agent through
@cortexkit/aft-pi
Shared bridge layer:
- Purpose: Resolve or download the binary, start worker processes, manage ONNX runtime, format output, and forward requests. All harness adapters share this layer.
- Location:
packages/aft-bridge/src/bridge.ts,packages/aft-bridge/src/pool.ts,packages/aft-bridge/src/resolver.ts,packages/aft-bridge/src/downloader.ts,packages/aft-bridge/src/onnx-runtime.ts,packages/aft-bridge/src/migration.ts,packages/aft-bridge/src/zoom-format.ts - Contains: Session bridge lifecycle, restart handling, version checks, binary discovery, binary download, ONNX runtime detection, storage migration, compact UI formatting, active logger
- Depends on: Node child-process APIs, GitHub releases,
onnxruntime-node - Used by:
packages/opencode-plugin/src/index.ts,packages/pi-plugin/src/index.ts
Unified CLI layer:
- Purpose: Provide a single
npx @cortexkit/aftentry point for setup, doctor, and LSP management across all harnesses. - Location:
packages/aft-cli/src/index.ts,packages/aft-cli/src/commands/ - Contains:
setup,doctor,doctor lsp,doctor --fix,doctor --clear,doctor --issue; harness auto-detection (OpenCode/Pi) with--harnessoverride - Depends on:
packages/aft-bridge/, harness adapter config paths - Used by: End users via
npx @cortexkit/aft
Tool definition layer (OpenCode):
- Purpose: Convert OpenCode tool arguments into the unified
tool_callprotocol request and perform permission checks. - Location:
packages/opencode-plugin/src/tools/ - Contains: Hoisted tools (edit/write/apply_patch), reading tools, import tools, structure tools, navigation tools, refactoring tools, safety tools, bash tools, conflict tools, AST tools, LSP tools, search tools, semantic tools, inspect tools, permissions helpers, and the
callToolCalltransport wrapper (packages/opencode-plugin/src/tools/_shared.ts) - Depends on:
packages/aft-bridge/src/pool.ts,packages/opencode-plugin/src/shared/,packages/opencode-plugin/src/metadata-store.ts - Used by:
packages/opencode-plugin/src/index.ts
Tool definition layer (Pi):
- Purpose: Convert Pi tool arguments into the unified
tool_callprotocol request and perform permission checks. - Location:
packages/pi-plugin/src/tools/ - Contains: Hoisted tools (read/write/edit/grep), reading tools, import tools, structure tools, navigation tools, refactoring tools, safety tools, bash tools, conflict tools, AST tools, inspect tools, semantic tools, render helpers, diff-format helper, and the
callToolCalltransport wrapper (packages/pi-plugin/src/tools/_shared.ts) - Depends on:
packages/aft-bridge/src/pool.ts,packages/pi-plugin/src/shared/ - Used by:
packages/pi-plugin/src/index.ts
Protocol and command layer:
- Purpose: Accept NDJSON requests, route tool calls via the unified
tool_callcommand, and dispatch them to focused command handlers. - Location:
crates/aft/src/main.rs,crates/aft/src/protocol.rs,crates/aft/src/commands/,crates/aft/src/run_tool_call.rs,crates/aft/src/subc_translate.rs,crates/aft/src/subc_format.rs - Contains: Request dispatch, response encoding, a unified
tool_callrouting engine, tool-to-command translation mapping, server-rendered agent-facing text formatting, and standalone command handlers for read/write/edit/apply_patch/delete_file/move_file/outline/zoom/bash/bash_orchestrate/bash_status/batch/grep/glob/search/imports/refactor/LSP/inspect/conflicts/checkpoints/state - Depends on:
crates/aft/src/context.rs,crates/aft/src/parser.rs,crates/aft/src/callgraph.rs,crates/aft/src/callgraph_store/mod.rs,crates/aft/src/edit.rs,crates/aft/src/semantic_index.rs,crates/aft/src/search_index.rs,crates/aft/src/compress/ - Used by:
packages/aft-bridge/src/bridge.ts
Analysis and mutation engine layer:
- Purpose: Parse code, compute call graphs, apply edits, format files, manage imports, index code semantically, and search with trigram indexes.
- Location:
crates/aft/src/parser.rs,crates/aft/src/callgraph.rs,crates/aft/src/callgraph_store/mod.rs,crates/aft/src/callgraph_store/dead_code_projection.rs,crates/aft/src/edit.rs,crates/aft/src/format.rs,crates/aft/src/imports/,crates/aft/src/extract.rs,crates/aft/src/semantic_index.rs,crates/aft/src/search_index.rs,crates/aft/src/symbols.rs,crates/aft/src/calls.rs,crates/aft/src/symbol_cache_disk.rs,crates/aft/src/fuzzy_match.rs,crates/aft/src/ast_grep_hints.rs,crates/aft/src/ast_grep_lang.rs,crates/aft/src/query_shape.rs,crates/aft/src/pattern_compile.rs,crates/aft/src/patch/,crates/aft/src/pty_render.rs - Contains: Tree-sitter parsing, symbol extraction, diff generation, formatter detection, type-checker integration, import engines (Java, C#, PHP, Kotlin, Scala, Swift, Ruby, Lua, C/C++, Perl, Solidity, Vue), refactor helpers, semantic embedding index (covering Java, Kotlin, Scala, Swift, Ruby, PHP, Lua, Perl, R, and other supported languages), disk-backed trigram search index, disk-backed symbol cache, persisted SQLite callgraph store builder, AST-grep integration, patch parsing (Add, Delete, and Update hunks) and matching engine, vt100 terminal rendering for PTY screen snapshots
- Depends on: tree-sitter grammars, ast-grep, vt100, external formatter and checker processes, ONNX Runtime (optional), fastembed / OpenAI-compatible / Ollama backends (optional)
- Used by:
crates/aft/src/commands/*.rs
State and diagnostics layer:
- Purpose: Hold per-process mutable state for backups, checkpoints, file watching, call graph cache, LSP state, database storage, bash background tasks, cache freshness tracking, and file-system locking.
- Location:
crates/aft/src/context.rs,crates/aft/src/backup.rs,crates/aft/src/checkpoint.rs,crates/aft/src/lsp/,crates/aft/src/db/,crates/aft/src/cache_freshness.rs,crates/aft/src/fs_lock.rs,crates/aft/src/bash_background/,crates/aft/src/callgraph_store/mod.rs,crates/aft/src/response_finalize.rs - Contains:
AppContextwith symlink path verification checks (recursively following chain hops to reject escaping paths), undo history, backup policies and disk-locking handlers, named checkpoints, watcher receiver, LSP manager, diagnostics store, document store, persistent database tables (backups, bash tasks, compression events, state, callgraph edges and nodes), cache-freshness tracker, file-system lockfile, background task registry, PTY process pool, callgraph store background channels, and main-loop pending responses registry - Depends on:
notify, LSP transport helpers, RustRefCell, SQLite (viadb/andcallgraph_store/),serde - Used by: All command handlers through
AppContext
Tool invocation flow:
- Register tool definitions and config-driven surface selection --
packages/opencode-plugin/src/index.tsorpackages/pi-plugin/src/index.ts - Get a session bridge and send a unified
tool_callcommand carrying the bare tool name and arguments over NDJSON --packages/aft-bridge/src/pool.ts,packages/aft-bridge/src/bridge.ts - Dispatch the request to the
tool_callhandler in Rust, which translates it to the target command (viacrates/aft/src/subc_translate.rs) and executes it. For deferred tasks like foreground bash orchestration, the request is registered in the main-loop pending registry (crates/aft/src/main.rs). The execution outcome is processed through the server-side text formatter (crates/aft/src/subc_format.rs) and a pending response finalizer seam (crates/aft/src/response_finalize.rs) which attaches background completions and status bar updates before returning the response envelope.
Edit pipeline:
- Validate path and verify symlink safety (recursively follow components up to 40 hops to reject escaping paths) --
crates/aft/src/context.rs - Translate tool arguments to command parameters --
crates/aft/src/subc_translate.rs - Check edit permissions --
packages/opencode-plugin/src/tools/permissions.ts(or Pi equivalents) - Snapshot, mutate, diff, and validate content --
crates/aft/src/edit.rs - Auto-format and optionally collect diagnostics after write --
crates/aft/src/format.rs,crates/aft/src/context.rs
Call-graph and navigation flow:
- Configure project root and initialize file watching --
crates/aft/src/commands/configure.rs - Query workspace-wide call dependencies via the persisted background-built callgraph store --
crates/aft/src/callgraph_store/mod.rs - Serve navigation commands such as callers, call-tree, impact, trace-to, and trace-data using the callgraph store adapter --
crates/aft/src/commands/call_tree.rs,crates/aft/src/commands/callers.rs,crates/aft/src/commands/impact.rs,crates/aft/src/commands/trace_data.rs,crates/aft/src/commands/trace_to.rs,crates/aft/src/commands/trace_to_symbol.rs,crates/aft/src/commands/callgraph_store_adapter.rs. By default, hide test files from results (controlled via theincludeTestsparameter) and collapse unresolved stdlib or external leaf calls incall_treeunlessincludeUnresolvedis active. Truncate and return a summary (hub_summary) when results exceed 20 entries to save token context cost. - Serve symbol-level zoom inspection (
aft_zoom), which fetches a symbol's implementation. If the target is a large container (class, struct, interface, etc., exceeding 150 lines), it renders a member-signature menu instead of the full body. For standard functions, it dedupes outgoing (calls_out) and incoming (called_by) call sites by name, aggregating duplicate occurrences underextra_countto minimize context token cost.
Search and retrieval flow:
- Index project files using a disk-backed, pread-based trigram search index that keeps memory overhead bounded --
crates/aft/src/search_index.rs - Optionally index with dense embeddings (fastembed, OpenAI-compatible, or Ollama) --
crates/aft/src/semantic_index.rs. Serialize cold semantic warmups by gating callgraph store building and Tier 2 diagnostics refreshes behind active cold semantic index seeds. - Classify query shape (prose vs code) using the query shape parser --
crates/aft/src/query_shape.rs. Identify "type-concept identifier queries" (TitleCase PascalCase types combined with lowercase concepts) to trigger definition semantic priors. - Serve
grep(trigram, full-text) andaft_search(semantic + hybrid) queries, applying query-shape-dependent ranking priors to boost definitions and protect exact identifier matches from embedding noise --crates/aft/src/commands/grep.rs,crates/aft/src/commands/semantic_search.rs. Downrank generated documentation artifacts (e.g. minified CSS/JS, maps, SVGs) in lexical and hybrid search results.
File read flow:
- Map read arguments and validate boundary permissions --
packages/opencode-plugin/src/tools/reading.ts,packages/pi-plugin/src/tools/reading.ts - Sniff content type (text vs binary/PDF/image) and read contents --
crates/aft/src/commands/read.rs - Process media attachments (resizing, orientation correction, and animation checks) and return them as base64-encoded attachment payloads alongside text content --
crates/aft/src/commands/read.rs,crates/aft/src/subc_format.rs
Bash execution flow:
- Rewrite high-level commands (cat to read, grep to grep tool) --
crates/aft/src/bash_rewrite/ - Scan for dangerous commands and prompt for permission --
crates/aft/src/bash_permissions/ - Execute foreground, background, or PTY modes. Foreground bash executions are orchestrated with a wait window (defaulting to 15s, clamped to config) and deferred to background tasks if they exceed the budget, polling state and optionally rendering PTY screens with vt100 parsing --
crates/aft/src/commands/bash_orchestrate.rs,crates/aft/src/commands/bash_status.rs,crates/aft/src/pty_render.rs,crates/aft/src/bash_background/ - Compress output through the tiered compressor --
crates/aft/src/compress/
Binary resolution flow:
- Check cache, npm platform package, PATH, and cargo install locations --
packages/aft-bridge/src/resolver.ts - Download and checksum-verify a release asset when local resolution fails --
packages/aft-bridge/src/downloader.ts - Start bridges against the resolved binary and hot-swap after version mismatch --
packages/aft-bridge/src/bridge.ts,packages/aft-bridge/src/pool.ts
BinaryBridge:
- Purpose: Keep one live
aftsubprocess available for request/response traffic. - Location:
packages/aft-bridge/src/bridge.ts - Pattern: Persistent child-process adapter with timeout-triggered restart
BridgePool:
- Purpose: Scope bridges per OpenCode/Pi session and preserve isolated undo history.
- Location:
packages/aft-bridge/src/pool.ts - Pattern: Session-keyed object pool with LRU eviction
Tool groups (OpenCode):
- Purpose: Group related OpenCode tool definitions by capability surface.
- Location:
packages/opencode-plugin/src/tools/hoisted.ts,packages/opencode-plugin/src/tools/reading.ts,packages/opencode-plugin/src/tools/imports.ts,packages/opencode-plugin/src/tools/structure.ts,packages/opencode-plugin/src/tools/navigation.ts,packages/opencode-plugin/src/tools/refactoring.ts,packages/opencode-plugin/src/tools/safety.ts,packages/opencode-plugin/src/tools/conflicts.ts,packages/opencode-plugin/src/tools/lsp.ts,packages/opencode-plugin/src/tools/ast.ts,packages/opencode-plugin/src/tools/bash.ts,packages/opencode-plugin/src/tools/bash_watch.ts,packages/opencode-plugin/src/tools/bash_write.ts,packages/opencode-plugin/src/tools/inspect.ts,packages/opencode-plugin/src/tools/search.ts,packages/opencode-plugin/src/tools/semantic.ts,packages/opencode-plugin/src/tools/permissions.ts,packages/opencode-plugin/src/tools/hoisted-internals.ts - Pattern: Thin TypeScript adapters delegating to the unified
tool_calltransport
Tool groups (Pi):
- Purpose: Group related Pi tool definitions by capability surface.
- Location:
packages/pi-plugin/src/tools/hoisted.ts,packages/pi-plugin/src/tools/reading.ts,packages/pi-plugin/src/tools/imports.ts,packages/pi-plugin/src/tools/structure.ts,packages/pi-plugin/src/tools/navigate.ts,packages/pi-plugin/src/tools/refactor.ts,packages/pi-plugin/src/tools/safety.ts,packages/pi-plugin/src/tools/conflicts.ts,packages/pi-plugin/src/tools/ast.ts,packages/pi-plugin/src/tools/bash.ts,packages/pi-plugin/src/tools/semantic.ts,packages/pi-plugin/src/tools/inspect.ts,packages/pi-plugin/src/tools/fs.ts,packages/pi-plugin/src/tools/diff-format.ts,packages/pi-plugin/src/tools/render-helpers.ts - Pattern: Thin TypeScript adapters delegating to the unified
tool_calltransport with Pi-specific schema configuration
ToolCallCommand:
- Purpose: Route and execute client-facing agent tools via a single request.
- Location:
crates/aft/src/commands/tool_call.rs,crates/aft/src/run_tool_call.rs - Pattern: Unified request translator and response formatting coordinator
- Contains:
subc_translatemapping,subc_formattext rendering, and dispatching to target command handlers
AppContext:
- Purpose: Centralize runtime state for commands inside the Rust worker.
- Location:
crates/aft/src/context.rs - Pattern: Interior-mutable service container for a single-threaded request loop
- Contains:
CallGraph,CallGraphStore,SearchIndex,SemanticIndex,BgTaskRegistry,FilterRegistry, database connections, LSP manager, undo history
CallGraphStore:
- Purpose: Persisted SQLite database of project-wide call dependencies.
- Location:
crates/aft/src/callgraph_store/mod.rs - Pattern: Background-built SQLite schema containing resolved and name-only call edges, refreshed incrementally on file edits, and queried by navigation commands. Returns a
Buildingstatus during cold builds. Cold-build warming is deferred while a cold semantic index seed is actively collecting or embedding.
CallGraph:
- Purpose: Cache per-file local call data and resolve immediate import edges.
- Location:
crates/aft/src/callgraph.rs - Pattern: Lazy workspace index with invalidation on watcher events.
SearchIndex:
- Purpose: Provide fast trigram-based full-text search across the project.
- Location:
crates/aft/src/search_index.rs - Pattern: Disk-backed (pread) postings index written to a single cache file (
cache.bin) and read on-demand to maintain a bounded RAM footprint, rebuilding in the background on watcher events.
SemanticIndex:
- Purpose: Provide dense-embedding semantic search across the project.
- Location:
crates/aft/src/semantic_index.rs - Pattern: Optional index backed by fastembed (local), OpenAI-compatible, or Ollama; configurable
max_filescap
BgTaskRegistry:
- Purpose: Manage background bash tasks and PTY sessions.
- Location:
crates/aft/src/bash_background/registry.rs - Pattern: Thread-safe registry with a watchdog thread for output compression, completion notification, and task lifecycle cleanup
Compressor:
- Purpose: Reduce hoisted-bash output to relevant tokens.
- Location:
crates/aft/src/compress/(multiple modules),crates/aft/src/compress/mod.rs - Pattern: Trait-based dispatch with per-command Rust modules, output-shape sniffers, package-manager modules, declarative TOML filters, and a generic fallback
PendingResponses:
- Purpose: Hold and poll deferred or orchestrated requests in the main loop.
- Location:
crates/aft/src/response_finalize.rs,crates/aft/src/main.rs - Pattern: Vector-backed pending queue that polls registered completion steps and runs the finalizer seam before writing responses.
PatchEngine:
- Purpose: Parse, match, and apply unified file diffs/patches.
- Location:
crates/aft/src/patch/(includingmod.rs,parser.rs,matcher.rs,apply.rs) - Pattern: AST/line-based parser that maps update/create/delete hunks to target files, matches fuzzy sequences, and executes atomic writes with rollback support.
PtyRenderer:
- Purpose: Render raw PTY output bytes into a readable screen.
- Location:
crates/aft/src/pty_render.rs - Pattern: vt100 terminal state parser that outputs clean, grid-aligned text for screen snapshots.
Harness:
- Purpose: Represent the coding-agent harness (OpenCode or Pi) for config and CLI dispatch.
- Location:
crates/aft/src/harness.rs - Pattern: Simple enum with serde round-trip and display/from-str
OpenCode plugin entry point:
- Location:
packages/opencode-plugin/src/index.ts - Triggers: OpenCode loads the
@cortexkit/aft-opencodeplugin - Responsibilities: Load config, resolve the binary via
@cortexkit/aft-bridge, create the bridge pool, register tool definitions, manage session lifecycle, run auto-update checker, handle background completion push frames
Pi plugin entry point:
- Location:
packages/pi-plugin/src/index.ts - Triggers: Pi loads the
@cortexkit/aft-piplugin - Responsibilities: Load config, resolve the binary via
@cortexkit/aft-bridge, create the bridge pool, register tool definitions, manage LSP auto-install (npm + GitHub), handle background completion push frames
Unified CLI entry point:
- Location:
packages/aft-cli/src/index.ts - Triggers:
npx @cortexkit/aftinvocation - Responsibilities: Parse argv, auto-detect harness, dispatch to
setup,doctor, ordoctor lspcommands
Shared bridge entry point:
- Location:
packages/aft-bridge/src/index.ts - Triggers: Imported by
@cortexkit/aft-opencodeand@cortexkit/aft-pi - Responsibilities: Export
BinaryBridge,BridgePool, binary resolution (downloadBinary,ensureBinary,findBinary), ONNX runtime detection (ensureOnnxRuntime,isOrtAutoDownloadSupported), storage migration (ensureStorageMigrated), compact formatting helpers
Rust protocol entry point:
- Location:
crates/aft/src/main.rs - Triggers:
packages/aft-bridge/src/bridge.tsspawns theaftbinary - Responsibilities: Read NDJSON requests from stdin, dispatch handlers, drain watcher and LSP events, compress background task output, and write JSON responses
Rust subc daemon entry point:
- Location:
crates/aft/src/main.rs,crates/aft/src/subc.rs - Triggers: Spawned with the
--subc <connection-file>argument - Responsibilities: Connect to the subc daemon over loopback TCP, authenticate using HMAC handshake, and process frames via tokio client loop routed through the per-actor executor
Rust binary CLI subcommands:
- Location:
crates/aft/src/cli/ - Triggers:
aft warmuporaft migrate-storageinvocations - Responsibilities: Pre-warm tree-sitter grammars, migrate storage between legacy and CortexKit paths
Release automation entry point:
- Location:
.github/workflows/release.yml - Triggers: Git tag pushes matching
v* - Responsibilities: Test the workspace, build platform binaries, publish crates and npm packages, and create a GitHub release
Strategy: Return structured Rust Response::error payloads from command handlers, convert failed responses into plugin-side exceptions, and restart hung or crashed worker processes in packages/aft-bridge/src/bridge.ts.
Goal: an agent reading any AFT response must be able to distinguish three states without ambiguity: (1) the work could not be performed, (2) the work was performed and the result is complete, (3) the work was performed but the result is partial.
Rule (tri-state):
-
success: false+code+message-- the requested work could not be performed. Codes are machine-actionable strings such as"path_not_found","no_lsp_server","project_too_large","invalid_request","ambiguous_match". The agent must read the message before continuing. -
success: true+ completion signaling -- the work was performed. Tools that produce results MUST report whether the result is complete and, if not, name the gaps. Conventional fields:complete: true-- the agent can trust absence of items in the resultcomplete: false+ a named gap field -- partial result. Gap fields includepending_files,unchecked_files,scope_warnings,skipped_files: [{file, reason}],walk_truncatedremoved: bool(mutations) -- did the file actually change?falseis a valid success when the requested change was a no-op.no_files_matched_scope: bool(search tools) -- distinguishes "the path/glob you gave me resolved to zero files" from "I searched N files and found nothing"
-
Side-effect skip codes -- when the main work succeeded but a non-essential side step was skipped (e.g. post-write formatting), use a
<step>_skipped_reasonfield so the agent gets specific feedback without treating the whole call as a failure. Approved values:format_skipped_reason:"unsupported_language"|"no_formatter_configured"|"formatter_not_installed"|"formatter_excluded_path"|"timeout"|"error"validate_skipped_reason:"unsupported_language"|"no_checker_configured"|"checker_not_installed"|"timeout"|"error"
Anti-patterns this convention exists to prevent:
- Returning
success: truewith empty results when the scope (path/glob) didn't resolve to any files -- the agent reads it as "all clear" but really nothing was checked. Returnno_files_matched_scope: true(when the scope was syntactically valid but matched zero files) orsuccess: false, code: "path_not_found"(when a passed path doesn't exist). - Reusing one skip-reason string for two distinct causes (e.g.,
"not_found"for both "language has no formatter configured" and "configured formatter binary missing"). The agent has different remediations for each -- split them. - Silently dropping files that fail to parse / open / decode inside a multi-file or directory operation. Always include a
skipped_files: [{file, reason}]array so the agent knows X out of Y files were actually processed. - Asserting
success: trueafter a partial transaction without acomplete: falseflag and a list of pending work.
Where this is documented in code: crates/aft/src/protocol.rs Response doc comment carries the canonical rule and the approved field set. New tools must follow this convention; existing tools are migrating.
Goal: reduce hoisted-bash output to fewer tokens while keeping the information the agent actually needs (errors, summaries, ref updates) and discarding the noise (progress bars, repeated headers, deep nested directory listings).
Five-tier dispatch in crates/aft/src/compress/mod.rs:
-
Specific Rust
Compressormodules -- hand-written parsers for high-traffic tools identified by tool tokens (e.g.git,cargo,vitest). Always wins when matched. Each module lives in its own file undercrates/aft/src/compress/(e.g.git.rs,cargo.rs,eslint.rs) and implements theCompressortrait (fn tokens(&[&str]) -> bool+fn compress(&str, &str) -> String). Modules includebiome,bun,cargo,eslint,git,go,mypy,next,npm,playwright,pnpm,prettier,pytest,ruff,tsc,vitest. -
Output-shape
Compressorsniffers -- inner-tool parsers that recognize their own private summaries even when invoked through wrappers such asnpm test,make test, or./scripts/check.sh. Tried after specific modules, before package-manager modules. -
Package-manager
Compressormodules -- broad head-token matchers (npm,pnpm,bun) that compress unclaimed package-manager output. -
Declarative TOML filters -- strip + truncate + cap + shortcircuit rules for the long tail of CLI tools, loaded from three sources at startup with project > user > builtin priority by filename:
- Builtin: shipped via
include_str!()fromcrates/aft/src/compress/builtin_filters/*.toml, registered incrates/aft/src/compress/builtin_filters.rs::ALL. Currently 22 filters: ansible-playbook, aws, curl, deno, df, docker, du, find, gh, gradle, helm, kubectl, ls, make, pip, psql, terraform, tree, uv, wc, wget, xcodebuild. - User:
<storage_dir>/filters/*.toml(XDG-aware via the activestorage_dir) - Project:
<project_root>/.cortexkit/aft/filters/*.toml-- gated bycrate::compress::trust; never loaded for an untrusted project
- Builtin: shipped via
-
Generic fallback -- ANSI strip + consecutive-line dedup + middle-truncate. Always applies when no Rust module or TOML filter matches.
Pipeline for TOML filters (in crates/aft/src/compress/toml_filter.rs::apply_filter):
- ANSI strip (when
[ansi].stripis true; default true) [strip]regexes drop matching lines (multiline mode)[shortcircuit]checks remaining content; if matched, returnreplacement[truncate]middle-truncates per line atline_maxchars[cap]enforcesmax_lineswithkeep = "head" | "tail" | "middle"
Trust model (crates/aft/src/compress/trust.rs): project filters can lie about output (e.g. strip real failures and replace with tests: ok). They are off by default. Users opt in via npx @cortexkit/aft doctor filters trust, which records the canonicalized project root in <storage_dir>/trusted-filter-projects.json (atomic temp-file rename, deserialized fail-closed). The CLI also exposes untrust, trust --list, --show <name>, and the default list view.
Concurrency: the filter registry is exposed as Arc<RwLock<FilterRegistry>> so the BgTaskRegistry watchdog thread can compress completed task output without holding AppContext. The compressor is installed as a closure on BgTaskRegistry from crates/aft/src/main.rs after AppContext::new constructs both.
Configure invalidation: crates/aft/src/commands/configure.rs::handle_configure calls ctx.sync_bash_compress_flag() and ctx.reset_filter_registry() on every configure so changes to experimental.bash.compress, storage_dir, project_root, or trust state pick up immediately without restart.
Compression site: terminal-state output only. Live tail of running tasks (via bash_status polling) is shown raw so agents debugging long commands see exactly what the process emitted. Compression fires inside BgTaskRegistry::maybe_compress_snapshot (status / list paths) and enqueue_completion_locked (completion frame + bash_drain_completions cache).
Logging: Write plugin logs through packages/opencode-plugin/src/logger.ts or packages/pi-plugin/src/logger.ts and Rust logs through env_logger in crates/aft/src/main.rs.
Caching: Cache resolved binaries in ~/.cache/aft/bin through packages/aft-bridge/src/downloader.ts, cache session bridges in packages/aft-bridge/src/pool.ts, cache tool availability in crates/aft/src/format.rs, cache call-graph state in crates/aft/src/callgraph.rs, cache trigram search indexes on disk via crates/aft/src/search_index.rs, cache semantic embeddings on disk via crates/aft/src/semantic_index.rs, and cache symbol data on disk via crates/aft/src/symbol_cache_disk.rs.
Storage: Store undo snapshots in crates/aft/src/backup.rs using the append-only v2 layout (indexing files under <session_hash>/<path_hash>/ with locks to support multi-session project-shared bridges) governed by configured backup policies (backup.enabled, backup.max_depth, backup.max_file_size). Store named checkpoints in crates/aft/src/checkpoint.rs, database tables (backups, bash tasks, compression events, state, callgraph edges and nodes) in crates/aft/src/db/, pending UI metadata in packages/opencode-plugin/src/metadata-store.ts, and downloaded binaries in the cache directory managed by packages/aft-bridge/src/downloader.ts. Storage lives under the CortexKit shared root (~/.local/share/cortexkit/aft/), migrated from the legacy path via crates/aft/src/migrate_storage.rs.