using-grove · git:20260821.3dfe12f · 2026-08-21 · sha256 4fa7551c41bd3a3a
using-grove git:20260821.3dfe12fA
Immutable. This exact content is served forever at /api/v1/blob/4fa7551c41bd3a3a.
--- name: using-grove description: Use when orchestrating a fleet of independent coding agents with Grove from OUTSIDE — isolated per-task workspaces (tmux plus git worktree, host or container) across model providers and harnesses. Triggers on: spinning up, steering, pausing, resuming or killing workspaces, `grove create`/`fleet`/`show`/`message`/`tickets`, the grove_* MCP tools, splitting large or multi-part work across parallel agents, reviewing one diff from several angles, checking what the fleet is doing or who needs attention, linking issues or pull requests to a workspace, and handing a ticket to the fleet by assigning it. Covers the three status axes, the task phase an agent reports for itself, ticket and PR linking and the live status comment it turns on, and how to get agents to keep the tracker current. For configuring Grove itself see configuring-grove; for reporting from inside a workspace see working-in-grove. --- # Using Grove [Grove](https://github.com/bearlike/Grove) runs a fleet of coding agents that live outside your context rather than sub-agents inside it. Each workspace is a whole separate agent process with its own runtime, its own context window and its own git worktree, addressable from outside. You create, steer, watch, pause, resume, respawn and kill them. Reach for Grove when you want parallel workspaces that outlive a single turn. For quick in-session parallelism across a few scoped sub-tasks, plain sub-agents are lighter and fit better. Grove earns its keep on work too big, too parallel or too cross cutting for one agent in one context. - **Decompose and parallelize.** Split by component and spin up one workspace per slice. Each gets a clean worktree, so they never touch each other's files. - **Triage at scale.** Forty Sentry issues or a whole backlog, one workspace per issue or per cluster. Each agent investigates independently and you review results rather than noise. - **Work one ticket from several angles at once.** Implementation, tests and docs run in parallel in separate environments instead of one after another. - **Independent review.** Point separate agents, on different models and different harnesses, at the same diff for uncorrelated second opinions. ## The model - **One workspace is one isolated runtime for one agent.** A dedicated git worktree, or the repo root for a lightweight case, plus a tmux session running that agent's own CLI, on the host or inside a container. - **Model and harness agnostic by design.** Every workspace picks its own agent and model. The point is giving each slice the harness that suits it, not stretching one agent across everything. - **You own the fleet and each member owns its own task.** Decide the split, spawn one workspace per slice, then poll and steer and collect. A map step and a reduce step, with real isolation so one agent's long tool call never blocks another. ## What Grove reports back Three independent axes describe a workspace and you need all three. Conflating them is the mistake the design exists to prevent. | Axis | Answers | Reported by | |---|---|---| | Workspace status | Is the runtime there. `active`, `idle`, `paused`, `offline`, `orphaned`, `provisioning`, `error` | Grove observes it | | Agent activity | Is the agent moving right now. `working`, `waiting`, `blocked`, `error`, `idle` | Grove infers it from transcript, hooks and pane | | Task phase | How far through the task the agent believes it is | The agent declares it, and nothing derives it | Phase is the axis you could not get before. An agent reads `working` both while it is still reading the ticket and while it is pushing the branch, and those two call for opposite responses from you. Only the agent can tell them apart, which is why this axis is pushed rather than observed. The six phases run `scoping`, `planning`, `implementing`, `verifying`, `delivering`, `done`. Four things about phase are easy to get wrong. - **A missing phase is not `scoping`.** A workspace that never reported carries no phase at all. That is a fact about the agent, where `scoping` is a fact about the task, so render them differently. - **Backwards is a correct report.** An agent that discovers in `verifying` that its design was wrong should say `planning` again. Grove never enforces forward motion, and an honest reversal is worth more than a phase that only climbs. - **There is still no `error` phase — that lives on the activity axis.** An agent can flag `blocked: true` beside a phase instead, meaning it has no way to finish that piece of work; it still names the phase it actually reached. This is not the activity axis's own `blocked`, which means waiting on a human right now and clears the moment they answer. - **Grove renders no staleness verdict.** Three hours in `implementing` is a long task, not a stale report. Whether the agent is alive is what the other two axes answer. The timestamp is the file's own mtime, so hold your own policy if you want one. Phase does not survive `pause`. It lives in the worktree that pause removes, so a resumed workspace reports afresh and the durable record stays the commit log. ## Watching the fleet `grove fleet` is the read built for supervising many workspaces at once. It is host wide rather than repo scoped, takes no arguments and emits JSON. One call carries every workspace with its state, its reported phase, todo counts, git ahead and behind, recent commits, and per session activity including which agents are waiting on you. ```bash grove fleet | jq '.projects[].workspaces[] | select(.needs_attention)' ``` Prefer it over per workspace phase and peek calls the moment you supervise more than one agent. `grove_get_fleet_status` is the same payload over MCP. It has no pagination, so the response grows with the fleet. For a single workspace, `grove show` gives git, agent, transcript and live pane state at a glance. ## Tying a workspace to the work item A workspace carries references to the issues and pull requests it is working. This is what makes a fleet addressable by work item rather than by workspace id. ```bash grove tickets attach 42 grove tickets attach https://example.com/acme/widgets/pull/17 grove tickets list grove tickets detach 42 ``` You never name a provider. Grove infers both the provider and whether the ref is an issue or a pull request from the shape of what you pass. Four input forms work, a full URL, `#42`, `42`, and `owner/repo#42`. Linear keys such as `ENG-123` parse for free. Pass `--workspace` to name one, or let Grove infer it from the directory you are standing in. Attach and detach are both idempotent. Five things worth knowing before you document or automate this. - **A pull request is not a separate kind of attachment.** It is one ref list with a kind discriminator, so there is no separate verb to go looking for. Re-attaching a ref Grove recorded as an issue corrects the kind in place rather than duplicating the row. - **Grove never detects your pull request from the branch.** Branch names yield issue refs only. A pull request enters the list solely by explicit attach. - **Attach stores a link and fetches nothing.** Title, status and assignee are fetched on demand and never persisted, which is what keeps attach fast and safe offline. - **A merged pull request reads `merged` and never `closed`.** The issues endpoint calls a merged PR closed, which is true and useless, so Grove reads the pulls namespace and normalizes. This is how you learn work landed. - **Attaching a ticket is a private local link.** It does not make an issue reference safe to put in pull request text. That ban exists because PR text mirrors to public remotes where a bare number resolves against a different tracker, and attaching changes nothing about the mirror. - **Attaching is also what makes the status mirror appear.** When issue-ops is enabled, Grove keeps ONE live comment per attached ticket carrying the workspace's state, its reported phase and its todo checklist. Nothing is published for a workspace with no refs, so an attach is the difference between a fleet a human reads from the tracker and one they can only see in Grove. - **Every one of those comments is authored as whatever account the configured token belongs to.** Point it at a bot. Forges set authorship at creation and never change it on edit, so a comment first written under a personal token stays attributed to that person permanently. - **Attach succeeding tells you nothing about whether the tracker is reachable.** It performs no network call, and publish failures are swallowed so an outage cannot break the activity poll — so a misconfigured provider presents as silence rather than an error. If comments never appear, suspect the credential before the code. ### Keeping the tracker current The mirror is only as good as what the agent reports, and the agent is the only one who can report a phase. Two consequences for you as the orchestrator: - **Tell a workspace to report, and to keep its todo list honest**, in the prompt that starts it. An agent that never writes a phase publishes a comment with no progress in it, and Grove will not invent one — a missing phase renders as nothing rather than as `scoping`. This is the single most common reason a status comment looks empty. - **Attach every ticket the workspace owns, up front.** Attaching is also what seeds an entry of its own for that ticket, at `scoping` — so a ticket linked late starts with no history and no phase until the agent's next report. Each attached ticket now carries its own phase, seeded the moment it is attached and updated independently of the workspace's own — an agent verifying one issue while another sits untouched reports exactly that, rather than one shared answer for both. `blocked: true` sits beside a phase, on the workspace's own claim or on any one ticket's, and means the agent has no way to finish that piece of work — distinct from the activity axis's own `blocked`, which means waiting on a human right now and clears the moment they answer. You can correct a report from outside with `grove phase <ref> <phase> [--ticket <ticket-ref>] [--blocked]` or `grove_set_workspace_phase` — for when an agent has stopped reporting or has plainly mis-stated where it is. Use it to fix the record, not to drive it: a phase you set is your claim about someone else's work, and the next thing the agent writes overwrites it. Before you create a second workspace for a ticket, ask whether one already exists. Over MCP, `grove_list_workspaces` narrows by `ticket_provider` plus `ticket_id` and answers exactly that, which is the difference between steering the workspace already on the job and starting a duplicate. ### Handing work over by assignment The tracker's assignee field can be the fleet's inbound queue. With issue-ops pickup enabled, the daemon polls each configured tracker for open issues assigned to Grove's account and starts a workspace on each one, under a ceiling on how many pickup-started workspaces may be live at once. `grove tickets handover <ref>` does the same thing on the spot rather than waiting for the poll, `grove tickets owned` lists what the fleet is holding host wide, and `grove tickets handback <ref>` unassigns without touching the workspace. Assigning on the tracker and handing over from the CLI take the same path, so a ticket handed over is never picked up twice. Handover needs a provider with an owner and a repo configured, which is Gitea and GitHub; Linear refuses, because two repos' issue #7 would otherwise share one marker. Gitea, GitHub and Linear are supported and all three stay off until a repo opts in. Each wants `enabled`, its scope, a base URL, and the NAME of an env var holding the token rather than a token literal. With nothing configured, an attach by bare ref fails loudly and names the providers that are enabled. ## CLI Run from inside any git repo Grove knows about. `grove config add-project` registers a repo you are not currently standing in. | Command | What it does | |---|---| | `grove create <title> [--agent <name>] [--model <id>] [--prompt <text>] [--runtime host\|container] [--branch/--base/...]` | Spin up a workspace and kick it off with a first task | | `grove ls` | This repo's workspaces, as JSON | | `grove show [<ref>]` | One workspace's git, agent, transcript and live pane state | | `grove fleet` | Every workspace on the host, as JSON | | `grove message <ref> <text>` | Steer a running agent | | `grove phase [<ref>] [<phase>] [--ticket <ticket-ref>] [--blocked] [--note <text>]` | Read a phase, or set one — the workspace's own or one ticket's — from outside | | `grove tickets attach\|list\|detach <ref> [--workspace <id>]` | Issue and pull request links | | `grove tickets handover <ref>`, `grove tickets owned`, `grove tickets handback <ref>` | Hand an issue to the fleet by assigning it, list what the fleet holds, give one back | | `grove pause\|resume\|respawn\|kill <ref>` | Lifecycle | | `grove attach <ref>` | Drop into the workspace's live tmux session yourself | | `grove shell <ref>` | An interactive shell inside a container workspace, persistent across visits | | `grove code <ref>` | Attach VS Code to a container workspace | | `grove agent list\|add\|kill\|peek\|message\|attach` | Several agents sharing one container workspace | | `grove sessions list\|show\|dump\|remap` | Recorded agent transcripts across the project | | `grove doctor` | Check the host dependencies each runtime needs | | `grove config`, `grove init devcontainer`, `grove skills install`, `grove mcp install` | Setup and onboarding | `<ref>` is a workspace id or a unique id prefix. `grove <command> --help` carries every flag. `grove shell`, `grove code` and the whole `grove agent` group require a containerized workspace and error cleanly on a host one. A fresh container workspace reads `provisioning` while its image builds, which can be minutes. That is the one status whose remedy is to wait, and it ends on its own — `respawn` is the one action that destroys the build in flight. `--runtime` is fixed at create time and never editable afterwards. If a container was wanted and the runtime was unavailable, the workspace falls back to host and names the reason, which `grove show` and `grove ls` report. Fix the runtime, then `grove respawn` to promote it. A container workspace with no project `.devcontainer/` runs Grove's default image, and `grove init devcontainer` graduates it to a committed config. ## MCP The same fleet, over MCP. What your server actually registers is the census; each tool's own schema documents its inputs, so read those rather than guessing from here. | Group | Tools | |---|---| | Discovery | `grove_list_projects`, `grove_list_workspaces`, `grove_get_workspace`, `grove_list_agents`, `grove_list_sessions` | | Watching | `grove_get_fleet_status`, `grove_peek_workspace`, `grove_get_workspace_phase`, `grove_get_workspace_todo`, `grove_attach_instruction` | | Lifecycle | `grove_create_workspace`, `grove_pause_workspace`, `grove_resume_workspace`, `grove_respawn_workspace`, `grove_kill_workspace` | | Workspace metadata | `grove_update_workspace` | | Steering | `grove_send_workspace_message`, `grove_set_workspace_phase` | | Links and sessions | `grove_attach_ticket`, `grove_detach_ticket`, `grove_remap_workspace_session` | `grove_list_projects` takes no arguments and returns the repo roots every other tool wants, so start there. - `grove_kill_workspace` requires `delete_branch` explicitly and rejects the call without it. Destructive tools never guess. - `grove_send_workspace_message` that times out means delivery is unknown rather than failed. Peek before you resend, or the agent gets the message twice. - `grove_set_workspace_phase` is for correcting an agent's report from outside, with `ticket` and `blocked` parameters mirroring the CLI's `--ticket` and `--blocked`. The agent's own channel is a file, described below. - A server started with `--read-only` withholds every mutating tool by not registering it, because a tool an agent can see is a tool it will try to call. - `grove_peek_workspace` caps its pane snapshot, and a trailing ellipsis is the signal that it trimmed. ## What a container workspace cannot do A containerized agent cannot reach Grove at all. The daemon binds loopback with no route from inside, the `grove` command is not installed there, and Grove deliberately leaves its MCP server out of the seeded config rather than register a binary that is absent. So that agent has no CLI verbs and no Grove tools. It reports its phase by writing a file, which the worktree mount carries to the host the instant it lands. Everything else you want done to that workspace, you do from outside, including attaching the pull request it opened. You do not have to restate the reporting contract in your prompt. By default Grove hands every new workspace a one-paragraph brief on its first turn pointing it at the companion `working-in-grove` skill, and `--no-brief` turns that off per workspace. How it arrives differs, and the difference bites in a container: a host `claude_code` agent gets it from Grove's status hook whether or not you gave it a task, while an agent with no such hook gets it prepended to the initial prompt — so a container workspace created with no `--prompt` is never briefed at all. ## The other Grove skills - **`working-in-grove`** — the same fleet seen from the inside. Point a workspace agent at it rather than restating the phase contract in every prompt. - **`configuring-grove`** — the config cascade, agents, init scripts, containers, and ticket providers. Reach for it when a workspace will not start the way you meant, or when the status mirror is silent. - **`reinstalling-grove`** — when an update did not take: stale daemon, stale webapp build, old UI after a pull. ## Configuration Setting Grove up is a separate concern from using the fleet. If a `configuring-grove` skill is available here, use it for that. `grove skills install` and `grove mcp install`, or `grove config init --with-onboarding`, is how this skill and Grove's MCP server arrived in the first place. For anything this skill does not cover, `grove --help` or a repo aware research tool pointed at `bearlike/Grove` will get you unstuck faster than guessing.