Protocol and platform for asynchronous, massively collaborative agent work.
Quick Start · Full Walkthrough · Presets · Architecture · MCP Guide
Grove models agent output as a contribution graph instead of a branch. Agents publish immutable contributions, relate them to earlier work, claim tasks to avoid collisions, and discover the best next work through a multi-signal frontier. No merges. No conflicts. Just a growing DAG of versioned knowledge.
Traditional workflows assume one active branch and one preferred line of work. That breaks down when many agents are exploring in parallel.
Grove replaces branch-centric coordination with a DAG of immutable contributions:
| Concept | What it does |
|---|---|
| Contribution | Immutable unit of work with a stable content-addressed ID (CID) |
| Relation | Links work by intent: derives_from, reviews, reproduces, responds_to, adopts |
| Claim | Lease-based coordination record that prevents duplicate effort |
| Frontier | Ranks promising work by metric value, adoption, recency, review quality, and reproduction signal |
| Outcome | Local operator annotation (accepted, rejected, flagged) |
| Bounty | Credit reservation for work that satisfies explicit criteria |
| Gossip | Peer-to-peer frontier federation across multiple Grove servers |
- Immutable contributions with BLAKE3 content-addressed storage
- Multi-signal frontier ranking across metrics, adoption, recency, reviews, and reproduction
- Lease-based claims for collision-free parallel work
- 6 built-in presets for turnkey multi-agent topologies (review loops, swarms, research, PR review)
- One-command startup via
grove up-- launches configured services and TUI together - MCP-native with stdio and HTTP/SSE transports for direct agent integration
- HTTP API powered by Hono for remote agent access
- TUI operator dashboard with 12+ panels for real-time visibility
- GitHub bridge to import/export PRs and Discussions
- Gossip federation for multi-server geographic distribution
- Routed
ask_userwith rules, LLM, interactive, and agent strategies - Strict TypeScript with zero
any, full type safety from protocol to UI
grove init --preset <name>
|
v
+----------------------------------+
| .grove/ directory |
| grove.db | cas/ | GROVE.md | ... |
+----------------------------------+
| |
grove up |
(orchestrator) |
/ \ |
v v v
+------+ +---+ +-----+
|Server| |TUI| | CLI |
|:4515 | | | | |
+------+ +---+ +-----+
| \ / |
| (optional) |
| +-----+ |
| | MCP | |
| |:4015| |
| +-----+ |
| | |
v v v
+------------------------------------+
| Protocol Core |
| Contributions | Claims | Frontier |
| Bounties | Outcomes | Topology |
+------------------------------------+
| |
+------+------+ +---+---+
| Local SQLite | | Nexus |
| + FS CAS | | HTTP |
+--------------+ +-------+
|
Gossip Federation
(CYCLON protocol)
MCP is optional -- only presets with
services.mcp: true(currentlyswarm-ops) start the MCP server. All presets start the HTTP server.
Surfaces at a glance:
| Surface | Entry point | Purpose |
|---|---|---|
| CLI | grove |
Author, coordinate, discover, and operate from the terminal |
| HTTP server | grove-server (port 4515) |
Expose Grove over REST-style HTTP |
| MCP server | grove-mcp / grove-mcp-http |
Give MCP hosts a Grove-native tool surface |
| TUI | grove tui |
Real-time operator dashboard |
| TypeScript library | grove, grove/core, grove/local |
Embed protocol logic in your own code |
| Nexus integration | grove/nexus |
Nexus-backed storage adapters |
| Ask-user package | @grove/ask-user |
Routed clarification prompts for agents |
Requires Bun 1.3.x
# Install and build
bun install
bun run build
# Link the CLI so "grove" is on your PATH
bun link
# Launch Grove
grove upThat's it. If no .grove/ directory exists, the TUI opens a welcome screen
where you pick a preset, name your grove, and start -- no separate grove init
needed. If already initialized, grove up starts services and the TUI directly.
Use --headless for CI or --no-tui for server-only mode.
tmux note. When the TUI launches inside a tmux session it automatically runs
tmux set-option -g allow-passthrough onso OpenTUI's terminal-capability queries reach the outer terminal. If you prefer to set this once globally, addset -g allow-passthrough onto your~/.tmux.conf.
# Or initialize from the CLI if you prefer
grove init "Latency hunt" --preset review-loop
grove upStop everything:
grove downFor the full end-to-end walkthrough -- including claims, threads, checkout, HTTP, MCP, and TUI usage -- see QUICKSTART.md.
Every grove works with or without a GROVE.md file.
# Bare grove — no GROVE.md, session config comes from preset per-session.
grove init my-project
# With project defaults — writes GROVE.md populated from the preset.
grove init my-project --preset review-loopWhen you start a session (grove session start --preset … or POST /api/sessions { "preset": "…" }), Grove snapshots the full config into the session record. GROVE.md, when present, acts as a project-level default for sessions that don't override it.
Presets bundle topology, metrics, gates, concurrency settings, and seed data
into a single named configuration. Initialize with --preset <name>:
grove init "My project" --preset swarm-ops| Preset | Roles | Topology | Mode | Backend | Services | Best for |
|---|---|---|---|---|---|---|
review-loop |
coder, reviewer | graph | exploration | nexus | server | Code review workflows |
exploration |
explorer, critic, synthesizer | graph | exploration | nexus | server | Open-ended discovery |
swarm-ops |
coordinator, worker, QA | tree | evaluation | nexus | server + MCP | Production multi-agent ops |
research-loop |
researcher, evaluator | graph | evaluation | local | server | ML research & benchmarks |
pr-review |
reviewer, analyst | graph | exploration | nexus | server | GitHub PR analysis |
federated-swarm |
worker (x8) | flat | exploration | nexus | server | Gossip-coordinated teams |
Each preset auto-generates a GROVE.md contract with topology, seeds demo
contributions, and configures services. Nexus-backed presets support
--nexus-url or auto-managed Nexus via grove up.
grove up is the orchestrator that starts your entire Grove environment:
grove up # Configured services + TUI
grove up --headless # Services only (CI mode)
grove up --no-tui # Services, no interactive dashboard
grove up --grove /custom # Custom .grove directory
grove up --nexus-source ~/nexus # Build Nexus from local source checkout
grove up --build # Same, using NEXUS_SOURCE env varWhat it does:
- Reads
.grove/grove.jsonfor configuration - Starts managed Nexus backend (if configured) with health checks
- Auto-provisions API key from
nexus.yaml(generated bynexus init) - Spawns enabled services in parallel -- HTTP server (port 4515) and, if the
preset enables it, MCP server (port 4015). Which services start is controlled
by
services.serverandservices.mcpin the preset config. - Writes
.grove/grove.pidfor process tracking - Launches the TUI as the foreground process
Graceful shutdown (grove down or Ctrl+C):
- SIGTERM to all child processes, 5-second grace period
- SIGKILL any stragglers
- Stops managed Nexus (if applicable)
- Cleans up PID file
Grove integrates with Nexus as a shared VFS backend for multi-agent coordination. Three connection modes are supported:
grove up handles the full Nexus lifecycle automatically:
grove init "My project" --preset review-loop # nexusManaged: true
grove up # nexus init + nexus up + health check + TUIOn startup, Grove:
- Runs
nexus init(generatesnexus.yamlwith ports and API key) - Runs
nexus up(starts Docker Compose stack) - Discovers the HTTP port from
nexus.yaml(handles port conflicts) - Reads the auto-provisioned API key and sets
NEXUS_API_KEY - Health-checks
/healthwith exponential backoff
Connect to an existing Nexus server (local or remote):
# At init time (persisted in grove.json)
grove init "My project" --preset review-loop --nexus-url http://nexus.example.com:2026
# Via environment variable
GROVE_NEXUS_URL=http://nexus.example.com:2026 grove up
# TUI-only override
grove tui --nexus http://nexus.example.com:2026When --nexus-url is set, Grove skips all lifecycle management and assumes the
server is already running.
For Nexus development, build from a local source checkout instead of pulling pre-built images from GHCR:
# Build from a local nexus repo checkout
grove up --nexus-source ~/nexus
# Same, using the NEXUS_SOURCE environment variable
export NEXUS_SOURCE=~/nexus
grove up --build--nexus-source (or --build with NEXUS_SOURCE set) passes --build --compose-file ~/nexus/nexus-stack.yml to nexus up. The repo-checkout compose
file has a build: directive that uses the local Dockerfile and source tree
(including maturin Rust extensions). The pip-installed bundled compose file has
no build: directive — this is why a source path is required.
Nexus supports three auth modes, configured by the nexus init preset:
| Preset | Auth | API Key |
|---|---|---|
local |
none |
Not generated |
shared |
static |
Auto-generated sk-<token> in nexus.yaml |
demo |
database |
Auto-generated sk-<token> in nexus.yaml |
Grove auto-reads the API key from nexus.yaml and passes it as a Bearer token
to all Nexus HTTP requests. Override with the NEXUS_API_KEY environment
variable.
To disable permission enforcement on the Nexus server, set
NEXUS_ENFORCE_PERMISSIONS=false in the Nexus container environment (via
nexus.yaml or docker-compose overrides).
All commands are available via grove or bun run src/cli/main.ts:
| Family | Commands | Purpose |
|---|---|---|
| Authoring | init, contribute, discuss, ask |
Create a grove, publish work, reply in threads, route questions |
| Lifecycle | up, down |
Start all services, stop them gracefully |
| Coordination | claim, release, claims, checkout |
Lease-based work coordination and artifact materialization |
| Discovery | frontier, search, log, tree, thread, threads |
Inspect the graph, rank work, browse discussions |
| Operations | outcome, bounty, tui |
Operator annotations, incentive flows, dashboard |
| Federation | gossip peers|status|frontier|watch|exchange|shuffle|sync|daemon|add-peer|remove-peer |
Gossip protocol management |
| GitHub | import, export |
Bridge PRs and Discussions in/out of Grove |
Key CLI options
grove init:--mode,--seed,--metric name:direction,--description,--force,--preset <name>,--nexus-url <url>grove up:--headless(CI mode, no TUI),--no-tui(server-only),--nexus-source <path>(build from source),--build(same, viaNEXUS_SOURCEenv)grove down: reads.grove/grove.pidand terminates child processesgrove contribute:--kind,--mode,--summary,--description,--artifacts,--from-git-diff,--from-git-tree,--from-report,--parent,--reviews,--responds-to,--adopts,--reproduces,--metric,--score,--taggrove ask:--options,--context,--strategy,--configgrove checkout:<cid> --to <dir>or--frontier <metric> --to <dir>
Start the server:
bun run src/server/serve.ts # port 4515 by default| Route group | Endpoints | Notes |
|---|---|---|
| Contributions | POST /api/contributions, GET /api/contributions, GET .../contributions/:cid, GET .../contributions/:cid/artifacts/:name |
JSON manifest or multipart upload |
| Frontier | GET /api/frontier |
Filters: metric, tags, kind, mode, agentId, limit |
| Search | GET /api/search |
Full-text via q plus filters |
| DAG | GET /api/dag/:cid/children, GET /api/dag/:cid/ancestors |
Graph traversal |
| Diff | GET /api/diff/:parentCid/:childCid/:artifactName |
UTF-8 text diff |
| Threads | GET /api/threads, GET /api/threads/:cid |
Discussion state |
| Claims | POST /api/claims, PATCH /api/claims/:id, GET /api/claims |
Create, heartbeat, release, complete |
| Bounties | GET /api/bounties, GET /api/bounties/:id |
Bounty listing with filters |
| Outcomes | GET /api/outcomes/stats, GET /api/outcomes, GET|POST /api/outcomes/:cid |
Operator metadata |
| Gossip | POST /api/gossip/exchange|shuffle, GET /api/gossip/peers|frontier |
Federation endpoints |
| Metadata | GET /api/grove, GET /api/grove/topology |
Instance stats and topology |
Grove exposes MCP over stdio and HTTP/SSE. Build once before using:
bun run build
# Stdio (for MCP hosts that spawn subprocesses)
bun run src/mcp/serve.ts
# HTTP/SSE on http://localhost:4015/mcp
bun run src/mcp/serve-http.ts| Tool family | Tools |
|---|---|
| Contributions | grove_submit_work, grove_submit_review, grove_reproduce, grove_discuss |
| Claims | grove_claim, grove_release |
| Queries | grove_frontier, grove_search, grove_log, grove_tree, grove_thread |
| Workspace | grove_checkout |
| Stop conditions | grove_check_stop |
| Bounties | grove_bounty_create, grove_bounty_list, grove_bounty_settle (claim via grove_claim) |
| Outcomes | grove_set_outcome, grove_get_outcome, grove_list_outcomes |
| Messaging | grove_send_message, grove_read_messages |
| Ask-user | ask_user |
grove up launches the TUI automatically. For standalone TUI use:
grove tui # Local mode
grove tui --url http://localhost:4515 # Remote server
grove tui --nexus http://localhost:2026 # Nexus-backedCore panels (always visible): DAG, Detail, Frontier, Claims.
Toggle additional panels with hotkeys:
| Key | Panel | Key | Panel |
|---|---|---|---|
5 |
Agents | 9 |
Activity |
6 |
Terminal | 0 |
Search |
7 |
Artifact | - |
Threads |
8 |
VFS | = |
Outcomes |
[ |
Bounties | ||
] |
Gossip |
Tab/Shift+Tab to cycle focus. Ctrl+P for the command palette. / for
full-text search.
GROVE.md is Grove's contract file — generated by grove init --preset <name> and read by all
surfaces. It defines:
- Grove metadata (name, description, mode)
- Metric definitions and score directions
- Gates for contribution acceptance
- Stop conditions for agent loops
- Concurrency and execution limits
- Lifecycle hooks
- Agent topology (roles, edges, spawning rules)
- Gossip configuration
Spawned agents can receive workspace-local Claude/Codex skills by declaring
skill names on their topology role. A skill is a directory containing
SKILL.md plus any supporting files:
.grove/skills/
comps-analysis/
SKILL.md
references/
...
Then reference that directory name from GROVE.md:
agent_topology:
roles:
- name: financial-analyst
platform: claude-code
skills: ["grove", "comps-analysis"]
- name: reviewer
platform: claude-code
skills: ["grove"]When the TUI or session orchestrator spawns those roles, Grove copies each resolved skill directory into the agent workspace:
<agent-workspace>/.claude/skills/<name>/
<agent-workspace>/.codex/skills/<name>/
In local mode, resolution order is:
- Workspace overrides from
.grove/skills/<name>/ - Bundled Grove skills from the installed
skills/catalog
In Nexus mode with skillCatalog configured, Grove tries the signed Nexus
catalog first. warn-and-fallback can then use verified local cache or local
fallback; required fails the spawn if Nexus catalog resolution cannot be
trusted.
The TUI currently consumes skills: from topology but does not yet provide a
launch-preview editor for adding or removing skills. That session-level
override UX is tracked in
#327. Nexus-hosted skill
distribution is tracked in
#326.
grove skill install is separate: it installs Grove's bundled grove skill
into your global Claude/Codex skill directories for manual assistant use
outside a Grove-provisioned workspace.
Bootstrap skills: remain the default way to give agents capabilities. A Grove
can also opt into runtime skill requests for stdio MCP agents by adding a
runtimeSkills allowlist to .grove/grove.json:
{
"runtimeSkills": {
"mode": "role-allowlist",
"roles": {
"coder": ["grove", "review"]
}
}
}An allowed agent can call grove_request_skill({ "skillName": "review" }).
Grove installs the skill into the live workspace, returns bounded SKILL.md
content for immediate use, and appends the skill to the session's effective
role skills for reattach or restart. HTTP MCP does not expose this mutation
tool.
| Variable | Purpose | Default |
|---|---|---|
GROVE_DIR |
Override .grove discovery |
$(pwd)/.grove |
GROVE_NO_ALT_SCREEN |
Disable TUI alternate-screen (useful for tmux capture-pane debugging) | -- |
GROVE_REPO_CACHE |
Override bare-clone cache root | $XDG_CACHE_HOME/grove/repo-cache (or ~/.cache/grove/repo-cache) |
GROVE_AGENT_ID |
Agent identity for CLI and MCP | -- |
GROVE_AGENT_NAME |
Human-readable agent name | -- |
GROVE_AGENT_ROLE |
Role hint for topology-aware workflows | -- |
PORT |
Server / MCP HTTP port | 4515 / 4015 |
GOSSIP_SEEDS |
peerId@address,... to enable federation |
-- |
GOSSIP_PEER_ID |
Explicit peer ID | -- |
GOSSIP_ADDRESS |
Public address advertised to peers | -- |
GROVE_NEXUS_URL |
Nexus backend URL | -- |
NEXUS_API_KEY |
Nexus API key (overrides nexus.yaml api_key) |
auto from nexus.yaml |
NEXUS_SOURCE |
Path to nexus source checkout for --build |
-- |
GROVE_ASK_USER_CONFIG |
JSON config for @grove/ask-user |
built-in defaults |
ANTHROPIC_API_KEY |
Required for ask_user LLM strategy |
-- |
Grove uses a user-wide bare-clone cache so agent worktrees are cheap regardless of whether the repo is checked out locally.
Cache location (first match wins):
$GROVE_REPO_CACHE$XDG_CACHE_HOME/grove/repo-cache/~/.cache/grove/repo-cache/
Maintenance:
grove repo list # every cached repo with manifest summary
grove repo prune <key> # remove one entry (refuses if any worktree still references it)
grove repo prune --all # remove every entry
grove repo fetch <key> # force a fetch on an existing cache entryCache growth is unbounded by design — Grove never evicts without being told. Run
grove repo prune --all if disk pressure bites.
By default Grove targets the git repo your shell is currently in. Override with
--repo (URL or local path):
grove up --repo https://github.com/you/project
grove session start --goal ... --repo /abs/path/to/checkoutOnly one --repo is accepted today; multi-repo sessions ship in a later release.
grove init writes a UUIDv4 to .grove/project-id (gitignored) that uniquely
identifies the clone for the life of its .grove/ directory. A user-level
registry at ~/.grove/projects.yaml maps each git origin URL to the first
clone's id, so multiple clones of the same remote can opt into sharing a
project identity.
Default: every clone gets a distinct id. Two clones of the same remote are two logical projects unless you explicitly unify them.
# First clone — generates a fresh UUID and registers it.
grove init my-project
# Second clone of the same remote — gets a NEW UUID by default.
grove init my-project
# Second clone, explicitly adopting the registry id.
grove init my-project --unify
# Second clone, explicitly opting out (bypasses the TTY prompt).
grove init my-project --no-unifyIn an interactive terminal, grove init prompts Unify? [y/N] when the
origin matches an existing registry entry. The default is N — pressing
Enter creates a new, distinct id, matching the documented "distinct by
default" contract. Type y (or pass --unify) to share identity. In CI /
non-TTY contexts the prompt is suppressed and the default is "new".
Origin URL normalization collapses HTTPS / SSH / SCP variants (with or
without .git, default port, or user:password@ credentials) to a single
canonical host/path key, so two clones cloned via different URL forms
still recognize each other. Non-default ports are preserved (a remote
on :2222 is treated as a distinct origin from the same host on the SSH
default :22), and any ?query or #fragment is stripped before keying so
credentials embedded in URL parameters never reach the registry.
Delete ~/.grove/projects.yaml to start the registry from scratch; delete
.grove/project-id to regenerate a clone's identity on the next grove init.
Additional agent metadata variables
| Variable | Purpose |
|---|---|
GROVE_AGENT_PROVIDER |
Provider metadata |
GROVE_AGENT_MODEL |
Model metadata |
GROVE_AGENT_PLATFORM |
Platform metadata |
GROVE_AGENT_VERSION |
Agent version metadata |
GROVE_AGENT_TOOLCHAIN |
Toolchain metadata |
GROVE_AGENT_RUNTIME |
Runtime metadata |
The codebase exposes a strict TypeScript API across multiple entrypoints:
| Import path | Use it for |
|---|---|
grove |
Batteries-included: manifests, GitHub adapter, gossip, reconciler |
grove/core |
Pure protocol types and logic -- no I/O assumptions |
grove/local |
SQLite stores, filesystem CAS, workspaces, artifact ingestion |
grove/server |
HTTP app factory for embedding Grove in Hono/Bun |
grove/mcp |
Transport-agnostic MCP server factory |
grove/nexus |
Nexus-backed adapters and HTTP client |
@grove/ask-user |
Ask-user tool registration and strategies |
Representative exports by entrypoint
grove:createContribution,fromManifest,toManifest,parseGroveContract,DefaultReconciler,createGitHubAdapter,createGhCliClient,DefaultGossipService,HttpGossipTransport,CyclonPeerSampler,CachedFrontierCalculatorgrove/core:Contribution,Claim,Bounty,GroveContract,DefaultFrontierCalculator,InMemoryCreditsService,EnforcingContributionStore,EnforcingClaimStore,evaluateStopConditions,LifecycleState,WorkspaceStatusgrove/local:FsCas,createSqliteStores,SqliteContributionStore,SqliteClaimStore,SqliteStore,LocalWorkspaceManager,LocalHookRunner,ingestFiles,ingestGitDiff,ingestGitTree,ingestReportgrove/server:createApp,ServerDeps,ServerEnvgrove/mcp:createMcpServer,resolveAgentIdentity,handleToolError,validationError,notFoundErrorgrove/nexus:NexusHttpClient,NexusContributionStore,NexusClaimStore,NexusOutcomeStore,NexusCas,resolveConfig,MockNexusClient@grove/ask-user:registerAskUserTools,loadConfig,parseConfig,buildStrategyFromConfig,createRulesStrategy,createInteractiveStrategy,createLlmStrategy,createAgentStrategy
The main platform package. Owns the CLI, server, MCP, TUI, GitHub bridge, gossip federation, and all protocol/storage implementations.
Standalone MCP package for routed agent clarification prompts.
- Binary:
grove-ask-user - Embedding:
registerAskUserTools(server, config?) - Strategies:
interactive,rules,llm,agent
See packages/ask-user/README.md for full docs.
grove export --to-discussion owner/repo <cid>
grove export --to-pr owner/repo <cid>
grove import --from-pr owner/repo#123
grove import --from-discussion owner/repo#456Start grove-server with seeds to enable federation:
GOSSIP_SEEDS=peer-a@http://server-a:4515,peer-b@http://server-b:4515 \
bun run src/server/serve.tsPeers discover each other via the CYCLON protocol and exchange merged frontier
state through CLI gossip commands and /api/gossip/* HTTP routes.
bun install # Install dependencies
bun test # Run all tests
bun run typecheck # Strict TypeScript checking
bun run check # Biome lint
bun run build # Build with tsup| Tool | Version |
|---|---|
| Runtime | Bun 1.3.x |
| Language | TypeScript 5.9 (strict) |
| Build | tsup |
| Lint/Format | Biome |
| Test runner | bun:test |
| CI | GitHub Actions |
Contributions are welcome! To get started:
- Fork the repo and create a feature branch
- Run
bun installand ensurebun testpasses - Follow the existing code style (enforced by Biome)
- Keep TypeScript strict -- no
any, no!, no@ts-ignore - Open a PR against
main
- QUICKSTART.md -- Full end-to-end walkthrough
- packages/ask-user/README.md -- Ask-user package docs
- docs/guides/mcp-setup.md -- MCP integration guide
- AGENTS.md -- Guidance for AI agents working in the codebase
Apache-2.0