Skip to main content
Glama
README.md
# vesper

A small Rust workspace that lets multiple coding agents work on the same
codebase without a human relaying every message between them. Built and
tested across the `vesper-core` and `vesper-registry` crates.

## Why it exists

When several agents share a workspace, three things go wrong repeatedly:

- two agents edit the same file at the same time
- an agent "remembers" a useful script/prompt/tool and the next agent
  has to rediscover it
- a tool is shared before anyone has actually checked it works, so a
  broken tool spreads silently

`vesper` addresses each with a dedicated MCP server:

| Problem | Server | Mechanism |
| --- | --- | --- |
| Clobbered files | `vesper-core-server` | file/task **claims** — exclusive, keyed by resource, not agent+resource |
| Hand-off / coordination | `vesper-core-server` | per-agent **inbox** (direct message + broadcast) |
| Tool re-discovery | `vesper-registry` | **versioned tool registry** (append-only, never overwrites) |
| Unverified tools spreading | `vesper-registry` | **multi-agent verification** — needs N distinct verifiers; a single failure flags and hides |

## Workspace layout

```
.
├── Cargo.toml                    # workspace root = vesper-core
├── src/
│   ├── lib.rs                    # AgentId, Message, Claim, CoordinationState
│   ├── model_router.rs           # ModelClient trait + HttpModelClient (Phase 5)
│   ├── python.rs                 # PyO3 bindings (feature-gated, Phase 7)
│   ├── main.rs                   # `vesper-core-demo` binary
│   └── bin/
│       └── vesper-core-server.rs # coordination server (rmcp Streamable HTTP)
├── tests/
│   └── end_to_end.rs             # integration: claim → handoff → register → verify
└── vesper-registry/
    ├── Cargo.toml
    ├── src/
    │   ├── lib.rs                # Registry, ToolId, ToolVersion, VerificationState
    │   └── main.rs               # registry server (rmcp Streamable HTTP)
    └── tests/
        └── live_roundtrip.rs     # real MCP-client round-trip
```

## Crates

### `vesper-core`

The shared library. Defines:

- `AgentId`, `AgentStatus`, `Message`, `Claim`, `ClaimTarget`
- `CoordinationState` — DashMap-backed shared store for claims, inboxes,
  and statuses. Cloning is cheap; the inner maps are wrapped in `Arc`,
  so the same state can be shared across the coordination server,
  integration tests, and (optionally) the Python bindings.
- `AgentState` — single-process per-agent loop (Phase 1).
- `model_router` — `ModelClient` trait plus an `HttpModelClient` that
  talks to any OpenAI-compatible `/chat/completions` endpoint. API keys
  resolve via a `secrets://ENV_VAR` reference, never embedded in config.
- `python` module — PyO3 bindings, compiled only when the
  `python-bindings` feature is on. A plain `cargo build` / `cargo test`
  never needs a Python toolchain or links against `libpython`.

### `vesper-registry`

A versioned, multi-agent-verified tool registry.

- `ToolId`, `ToolVersion` (monotonic, never overwrites)
- `VerificationState` — `Unverified` → `Verified` (after N distinct
  verifiers) or `Flagged` (a flag hides it, but the `(flagger, reason,
  when)` record is contestable: `unflag` or enough distinct re-verifiers
  restores it)
- `Registry` — `register`, `verify`, `flag`, `unflag`, `fork`, `unregister`,
  `list_tools`, `list_all_tools`, `get_tool`, `find_similar`

Exposed as an MCP server on `http://127.0.0.1:9899/mcp`.

## Servers (MCP Streamable HTTP)

Both servers use the official `rmcp` Streamable HTTP transport
(spec `2024-11-05`), not a hand-rolled JSON-RPC. Stateless requests
share one `Arc<CoordinationState>` / `Arc<Registry>` captured by the
service factory.

| Server | Port | Tools |
| --- | --- | --- |
| `vesper-core-server` | 9898 | `claim_file`, `release_file`, `claim_task`, `release_task`, `renew_file_claim`, `renew_task_claim`, `send_message`, `broadcast`, `get_inbox`, `drain_inbox`, `get_status`, `list_claims`, `expire_stale_claims`, `release_agent_claims` |
| `vesper-registry` | 9899 | `register_tool`, `list_tools`, `list_all_tools`, `get_tool`, `verify_tool`, `flag_tool`, `unflag_tool`, `fork_tool`, `unregister_tool` |

## Build, test, run

Requires a recent stable Rust toolchain.

```bash
# Build & test the whole workspace
cargo build --workspace
cargo test --workspace

# Run the servers (separate terminals)
cargo run --bin vesper-core-server
cargo run --bin vesper-registry-server
```

On Windows the dev workflow hits an `Access denied` if both server
binaries are still running while a rebuild tries to remove the `.exe`.
Stop the running server (or `Stop-Process` it) before `cargo build`.

## Python bindings (optional)

`vesper-core` is also a `cdylib` with PyO3 bindings, packaged via
Maturin. Built and tested against a real Python venv — claim/release,
send_message, broadcast, inbox, drain_inbox, and status all work from
Python the same way the Rust tests say they should.

```bash
# Requires the python-bindings feature + a Python toolchain on PATH
maturin build --release
pip install <generated wheel>
```

A plain `cargo build` / `cargo test` does **not** enable the feature
and does not need a Python toolchain.

## Phases (status)

| Phase | Content | Status |
| --- | --- | --- |
| 1 | Single-agent loop, `AgentState` | done |
| 2 | `CoordinationState` + `vesper-core-server` JSON-RPC | done |
| 3 | `vesper-registry` (versioning + multi-agent verification) | done |
| 4 | (planned) | — |
| 5 | `model_router` (trait + `HttpModelClient`) | done |
| 6 | Convert both servers to rmcp Streamable HTTP | done |
| 7 | PyO3 bindings + Maturin wheel | done |
| 8 | Closed SDK (deliberately last) | pending |

The remaining gap before any of this is useful day-to-day is the
**live wiring**: actually pointing real agents at the running servers
as MCP clients and running a full claim → handoff → register → verify
cycle. That's what the `live_roundtrip` integration test exercises.