Metadata-Version: 2.4
Name: carve-server
Version: 0.1.1
Summary: Text Editor for AI Agents
Author-email: Scott Russell <me@scottrussell.net>
License: MIT
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: fastapi>=0.115.0
Requires-Dist: mcp>=1.0.0
Requires-Dist: pathspec>=0.12.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: tree-sitter>=0.24.0
Requires-Dist: uvicorn>=0.34.0
Provides-Extra: all
Requires-Dist: tree-sitter-bash>=0.24.0; extra == 'all'
Requires-Dist: tree-sitter-css>=0.24.0; extra == 'all'
Requires-Dist: tree-sitter-html>=0.23.0; extra == 'all'
Requires-Dist: tree-sitter-javascript>=0.24.0; extra == 'all'
Requires-Dist: tree-sitter-jinja>=0.3.3; extra == 'all'
Requires-Dist: tree-sitter-json>=0.24.0; extra == 'all'
Requires-Dist: tree-sitter-markdown>=0.5.1; extra == 'all'
Requires-Dist: tree-sitter-python>=0.24.0; extra == 'all'
Requires-Dist: tree-sitter-toml>=0.7.0; extra == 'all'
Requires-Dist: tree-sitter-yaml>=0.7.2; extra == 'all'
Provides-Extra: bash
Requires-Dist: tree-sitter-bash>=0.24.0; extra == 'bash'
Provides-Extra: css
Requires-Dist: tree-sitter-css>=0.24.0; extra == 'css'
Provides-Extra: dev
Requires-Dist: mypy>=1.14.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.25.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.9.0; extra == 'dev'
Requires-Dist: tree-sitter-bash>=0.24.0; extra == 'dev'
Requires-Dist: tree-sitter-css>=0.24.0; extra == 'dev'
Requires-Dist: tree-sitter-html>=0.23.0; extra == 'dev'
Requires-Dist: tree-sitter-javascript>=0.24.0; extra == 'dev'
Requires-Dist: tree-sitter-jinja>=0.3.3; extra == 'dev'
Requires-Dist: tree-sitter-json>=0.24.0; extra == 'dev'
Requires-Dist: tree-sitter-markdown>=0.5.1; extra == 'dev'
Requires-Dist: tree-sitter-python>=0.24.0; extra == 'dev'
Requires-Dist: tree-sitter-toml>=0.7.0; extra == 'dev'
Requires-Dist: tree-sitter-yaml>=0.7.2; extra == 'dev'
Provides-Extra: html
Requires-Dist: tree-sitter-html>=0.23.0; extra == 'html'
Provides-Extra: javascript
Requires-Dist: tree-sitter-javascript>=0.24.0; extra == 'javascript'
Provides-Extra: jinja
Requires-Dist: tree-sitter-jinja>=0.3.3; extra == 'jinja'
Provides-Extra: json
Requires-Dist: tree-sitter-json>=0.24.0; extra == 'json'
Provides-Extra: markdown
Requires-Dist: tree-sitter-markdown>=0.5.1; extra == 'markdown'
Provides-Extra: python
Requires-Dist: tree-sitter-python>=0.24.0; extra == 'python'
Provides-Extra: toml
Requires-Dist: tree-sitter-toml>=0.7.0; extra == 'toml'
Provides-Extra: yaml
Requires-Dist: tree-sitter-yaml>=0.7.2; extra == 'yaml'
Description-Content-Type: text/markdown

# Carve

**Text Editor for AI Agents**

Carve lets AI agents edit code structurally instead of rewriting entire files. It parses source code into a tree-sitter AST, exposes navigation and mutation tools over MCP or HTTP, and regenerates source files from the tree.

## Install

```bash
pip install carve-server
```

Install with language grammars:

```bash
# Individual languages
pip install "carve-server[python]"
pip install "carve-server[javascript]"

# All supported languages
pip install "carve-server[all]"
```

Supported: Python, JavaScript, HTML, CSS, JSON, Markdown, TOML, YAML, Bash, Jinja.

## Quick Start (MCP)

Add to Claude Code with one command:

```bash
claude mcp add carve -- carve serve --mcp
```

Or add to your MCP client config manually:

```json
{
  "mcpServers": {
    "carve": {
      "command": "carve",
      "args": ["serve", "--mcp", "--path", "/path/to/your/project"]
    }
  }
}
```

Or run directly:

```bash
carve serve --mcp --path ./my-project
```

The agent can then navigate and edit code through Carve's tool interface.

## Quick Start (HTTP)

```bash
carve serve --http --path ./my-project --port 8080
```

Import a file, explore its structure, make a surgical edit:

```bash
# See the tree structure
curl -X POST http://127.0.0.1:8080/tree/subtree \
  -H "Content-Type: application/json" \
  -d '{"node_id": "module", "depth": 2}'

# Inspect a specific function
curl -X POST http://127.0.0.1:8080/tree/inspect \
  -H "Content-Type: application/json" \
  -d '{"node_id": "module::MyClass::my_method"}'

# Update just that function
curl -X POST http://127.0.0.1:8080/tree/update \
  -H "Content-Type: application/json" \
  -d '{
    "node_id": "module::MyClass::my_method",
    "snippet": "def my_method(self, x):\n        return x * 2"
  }'

# Write changes to disk
curl -X POST http://127.0.0.1:8080/project/serialize \
  -H "Content-Type: application/json" \
  -d '{}'
```

## How It Works

```
Source file → Tree-sitter AST → In-memory tree store → Tools → Regenerated source
```

Carve parses source files into a tree of named nodes with hierarchical IDs like `module::Calculator::add`. Agents navigate with `subtree`, `search`, and `inspect`, then make targeted edits with `insert`, `update`, and `delete` — down to individual statements. When done, `project_serialize` writes the tree back to disk.

This means an agent can change one line inside a method without seeing or rewriting the rest of the file.

## Tools

| Tool | Description |
|------|-------------|
| `subtree` | Navigate tree structure from any node |
| `ancestors` | Get the path from a node up to root |
| `inspect` | Read a node's full source and metadata |
| `search` | Find nodes by name pattern and/or type |
| `find_references` | Cross-file dependency tracing |
| `insert` | Add new code at a specific position |
| `update` | Replace a node's implementation |
| `delete` | Remove a node |
| `move` | Relocate a node in the tree |
| `batch` | Apply multiple mutations in one pass |
| `ts_query` | Run tree-sitter S-expression queries |
| `project_import` | Load a file or directory |
| `project_serialize` | Write the tree back to source files |
| `error_locate` | Map stack traces to node IDs |
| `checkpoint` / `undo` / `redo` | Version control for mutations |

## Configuration

### carvesettings.toml

Drop a `carvesettings.toml` in your project root to configure formatters, custom tools, and language mappings.

```toml
workspace = "."
sidecars = true

[formatters]
python = "ruff format --quiet {file}"
javascript = "prettier --write {file}"

[tools]
test = "uv run pytest {args}"
lint = "uv run ruff check carve/ {args}"
typecheck = "uv run mypy carve/"

[language_map]
".djhtml" = "jinja"
".j2" = "jinja"

[import_map]
jinja = "tree_sitter_jinja"
```

**`formatters`** — Run after every disk write. `{file}` is replaced with the file path. Keyed by language name.

**`tools`** — Custom shell commands exposed as MCP tools (prefixed with `run_`). Placeholders like `{args}` become tool parameters. Requires `--allow-custom-tools` to enable.

**`sidecars`** — When `true` (default), Carve writes `.crv` sidecar files (see below). Set to `false` to disable.

**`workspace`** — Default project path. Also settable via `CARVE_WORKSPACE` env var.

**`language_map`** — Map file extensions to language names, extending the built-in defaults.

**`import_map`** — Map language names to tree-sitter grammar module names.

### .carveignore

Controls which files are included when importing a directory. Uses gitignore-style patterns. Without this file, all supported files are included.

```
# Common defaults
.git/
__pycache__/
*.egg-info/
.venv/
node_modules/
dist/
build/

# Carve metadata
*.crv

# Project-specific
*.db
*.png
```

### .crv Sidecar Files

Every time Carve mutates a source file, it appends an entry to a `.crv` JSON file next to it (e.g. `app.py.crv`). This is an audit trail of AI-driven changes:

```json
[
  {
    "operation": "update",
    "node_id": "Calculator::add",
    "timestamp": "2026-02-13T18:30:00+00:00",
    "model": "claude-opus-4-6",
    "prompt": "Simplify the add method",
    "notes": "Removed type annotations per user request"
  }
]
```

Each entry records *what* changed, *when*, *which model* did it, and *why*. This metadata is restored when you re-import the file, so `inspect` shows the prompt and model that last touched each node.

To disable: set `sidecars = false` in `carvesettings.toml`. To keep them out of version control, add `*.crv` to your `.gitignore`.

## CLI Options

```
carve serve --mcp              # MCP server on stdio
carve serve --http             # HTTP server (default port 8080)
  --path DIR                   # Project directory or file to load
  --port 8080                  # HTTP port
  --host 127.0.0.1             # HTTP host
  --read-only                  # Block all mutations
  --no-create                  # Block new file creation
  --no-delete                  # Block file/directory deletion
  --allow-custom-tools         # Enable tools from carvesettings.toml
```

## License

MIT
