Comments
Comments are how you direct agents in Grove. You leave a comment on a line of the diff; the agent reads it, replies, and resolves it. It's the load-bearing protocol of the product — the diff view, walkthroughs, and the agent loop are all built on top of it.
Why a protocol, not a chat
Chat is a bad surface for code review: it's linear, it isn't anchored to files, and it conflates "let's talk about design" with "fix line 42." Grove's comments are:
- Anchored — pinned to content, not line numbers, so they survive rewrites.
- Threaded — each comment carries its replies, from you and from agents.
- Inspectable — one sqlite file per workspace (
<workspace>/.grove/grove.db) that you can open and read by hand. The store is the source of truth; every surface (diff overlay, comments panel, task badges, agent tool calls) is a view onto it.
The data model, briefly
- Comments and replies are insert-only: nobody rewrites your words after the fact. Each task hands out a monotonic sequence number, so the order of a conversation is unambiguous.
- Resolution is state, not content. Resolving a comment marks it resolved (with an optional note and who resolved it); it doesn't rewrite history. Unresolve and delete exist too.
- All tasks in a workspace share the one database. Workspace-level chats (against the repo root) file their comments under a
_workspacesentinel.
Anchors: how comments survive edits
Each comment is pinned two ways:
- A content hash of the target line and the two lines on either side (a 5-line window). If the line moves, Grove re-scans nearby lines for the matching window at render time.
- A semantic path — the tree-sitter chain of named ancestors (e.g.
class Foo → method bar). When a body rewrite drifts the hash, the AST gives a second chance at relocation, and detects outright deletion.
A comment's anchor is one of four states:
fresh— exactly where you left it.moved— relocated automatically after an edit.stale— the content drifted out of range; shown at the nearest line, flagged not deleted.orphaned— the enclosing function or class is gone entirely.
What agents see
Grove's embedded MCP server exposes the comment store to agents as tools:
comments_list_pending— unresolved comments for the task. The agent's inbox.comments_list_all— full history, including resolved.comments_create(file, line, body)— agents can leave comments too; Grove computes the anchor.comments_reply(commentId, body)— append to a thread.comments_resolve(commentId, note?)— mark done.walkthrough_create/walkthrough_list— see Walkthroughs.
This is a pull model. Each task's CLAUDE.md tells the agent to check comments_list_pending and reply/resolve as it works — there's no injected system prompt and no daemon poking the agent awake. When you write a comment, the UI updates immediately; the agent discovers it on its next turn. Nothing is lost if the agent isn't running — the comment just waits in the pending list.
There's deliberately no "acknowledge" operation: pending simply means unresolved. An agent replies, resolves, or leaves it open.
Walkthroughs
A walkthrough is an ordered, multi-step explanation pinned across files — each step is a normal comment row, so per-step reply and resolve work unchanged. Agents author them via MCP to tell a story across files instead of dropping isolated comments. See Walkthroughs.
Limits
- One agent conversation per task drives the comment loop — no multi-agent concurrency on a single task's comments.
- Comment bodies can't be edited after posting (reply or resolve instead).