Skip to content

awf-project/tower

Repository files navigation

Tower

Tower is a core engine for a high-performance productivity tool: a virtual file system with a persistent inverted index, parallel content search, safe mass text refactoring, and an out-of-process native extension architecture — all exposed over a JSON-RPC 2.0 stdio interface following the Model Context Protocol (MCP).

Architecture: Domain-Driven Design + Hexagonal (Ports & Adapters) + Microkernel. See project-brief.md for the full vision.


Features

Capability Description
Virtual file system Workspace-scoped VFS with a persistent sled inverted index; sub-millisecond file lookup
Parallel content search Rayon-backed grep across all indexed files
Safe file mutations Shadow-file pattern (<path>.tmp_write → flush → atomic fs::rename); crash-safe
Mass refactoring Parallel global find-and-replace with per-file atomic rewrites and a TxReport
MCP server JSON-RPC 2.0 over stdin/stdout; native tower_* tools plus any extension tools, served from one surface
Native extension host Out-of-process native sidecar extensions over a JSON-RPC 2.0 protocol on stdio; OS-process isolation, per-call timeouts, restart/backoff, and quarantine
AST analysis ast extension — Tree-sitter outline and symbol search for Rust, Go, PHP
Code intelligence lsp extension — diagnostics, definition, references, hover via a language-server bridge
Standalone linting and fixes lint extension — on-demand diagnostics and structured fixes from configured external linters, using the same diagnostic shape as LSP
Single static binary No WASM, WASI SDK, JVM, Node, or container required at runtime

60-second quick start

Install (prebuilt binary)

No toolchain required — download a prebuilt binary from GitHub Releases:

curl --proto '=https' --tlsv1.2 -fsSL \
  https://raw.githubusercontent.com/awf-project/tower/main/scripts/install.sh | sh

Installs the latest stable release to $HOME/.local/bin/tower. Override via environment:

Variable Default Purpose
TOWER_VERSION latest latest/stable, dev (rolling prerelease), or a tag like v0.1.0
TOWER_INSTALL_DIR $HOME/.local/bin Where the binary is installed
TOWER_TARGET auto-detected Force a target triple instead of auto-detecting
curl -fsSL .../install.sh | TOWER_VERSION=dev sh      # rolling dev build
curl -fsSL .../install.sh | TOWER_VERSION=v0.1.0 sh   # pinned version

The installer verifies the published .sha256 checksum when present. To build from source instead, follow the steps below.

Prerequisites

  • Rust toolchain — pinned by rust-toolchain.toml; rustup installs it automatically:

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  • cargo-deny for the license/advisory gate:

    cargo install cargo-deny --locked

Build

git clone <repository-url> tower
cd tower
cargo build -p core_engine        # produces target/debug/tower

Run the MCP server

# Workspace root = current directory (or set --workspace-dir / $TOWER_WORKSPACE)
cargo run -p core_engine
# stderr: tower: initial scan complete — N files indexed

Drive it over a pipe

# Handshake
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | cargo run -p core_engine -q

# List tools (native tower_* tools, plus tower_<ext>_<tool> for any loaded extension)
echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | cargo run -p core_engine -q

# Find a file
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"tower_find_file","arguments":{"query":"main.rs"}}}' \
  | cargo run -p core_engine -q

# List indexed directory entries
echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"tower_list_dir","arguments":{"path":"src","recursive":true,"max_depth":1}}}' \
  | cargo run -p core_engine -q

# Run configured standalone linters for all supported indexed files
echo '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"tower_lint_check","arguments":{}}}' \
  | cargo run -p core_engine -q

# Preview structured lint fixes without writing files
echo '{"jsonrpc":"2.0","id":6,"method":"tools/call","params":{"name":"tower_lint_fix","arguments":{"path":"src/main.rs","dry_run":true}}}' \
  | cargo run -p core_engine -q

Each request is a single newline-delimited JSON object on stdin; responses arrive on stdout. No Content-Length header — unlike LSP.

Install an extension

Extensions are out-of-process native sidecar binaries described by an extension.toml manifest. tower discovers them at startup (resolved from --extensions-dir, then $TOWER_EXTENSIONS_DIR, then the global XDG dir and <workspace>/.tower/extensions/). Drop a binary + manifest into a scope, restart, and its tools appear in tools/list — no host recompile:

mkdir -p .tower/extensions/ast
cp target/debug/ast_extension     .tower/extensions/ast/
cp extensions/ast/extension.toml  .tower/extensions/ast/
cargo run -p core_engine -q     # tools/list now also exposes tower_ast_get_outline, tower_ast_find_symbols, …

No extensions serves the native tools; an extension that fails to spawn is skipped with a stderr warning and never aborts startup. See docs/extensions.md for details.


Quality gate

Run these checks in order before every merge (mirrors CI):

cargo fmt --all --check                                   # make fmt-check
cargo clippy --workspace --all-targets -- -D warnings     # make clippy

# Build native extension binaries first so host integration tests can locate
# them under target/debug/. No WASM, no WASI SDK.
cargo build --workspace --bins
cargo test --workspace                                    # make test

cargo deny check                                          # make deny

Or run the whole sequence with make gate.


Workspace layout

crates/                   Engine + shared protocol (host-side)
├── core_engine/          Host binary (tower) + lib; domain / ports / adapters
└── extension_protocol/   Shared host ↔ extension wire contract (types + serde only)

extensions/               Native sidecar extensions (separate binaries)
├── ast/                  Reference Tree-sitter AST extension (eager)
├── hello/                Minimal example extension (lazy)
├── lsp/                  Language-server bridge extension (lazy)
├── lint/                 Standalone linter extension (lazy)
└── fixtures/             Test-only fault-isolation fixtures (not shipped)

The reference extensions are ordinary native binaries. Build them with cargo build --workspace --bins before cargo test --workspace so host integration tests can locate sidecars under target/debug/. There is no WASM build step and no WASI SDK.


Documentation

Page Contents
docs/getting-started.md Prerequisites, build, quality gate, first MCP session
docs/architecture.md Hexagonal boundary, crate layout, ports, data flow, design decisions
docs/mcp-tools.md Full MCP tool reference — wire protocol, the native tools, extension tools including lint fix, error codes
docs/user-guide/lint-fixes.md How to preview and apply structured linter fixes safely with tower_lint_fix
docs/extensions.md Extension authoring guide — native sidecars, the JSON-RPC protocol, capabilities, manifest, fault model
docs/development.md Contributing, TDD workflow, CI pipeline, test conventions
docs/ADR/ Architecture Decision Records
project-brief.md Vision, objectives, functional scope

License

EUPL-1.2.

About

EXPERIMENTAL - A Rust VFS indexing engine driven by AI via the MCP protocol.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages