Skip to content

Editing records via the agent (the resolution layer)

T1150, the last child task of the T1143 EPIC (the record-mutation API, D050's write side), builds the seam between "tell the agent what you want changed, in plain language" and the typed Mutate<Class> calls mcp-tools.md documents. This page explains the contract and its current integration status honestly — read the "What's wired up today" section before assuming a command below already exists.

The contract

plain-language request
    --[a Planner resolves it]--> a Plan: zero or more typed Calls, shown for confirmation
    --[you confirm, or decline]--
    --[Execute dispatches each confirmed call]--> the record's rendered text, reported back
  • The agent never opens a record's markdown file in an editor. Every change goes through the same typed Mutate<Class> functions the CLI verbs and MCP tools (mcp-tools.md) already call — there is no separate, parallel write path for agent-driven edits.
  • You always see the plan before anything happens. A Plan renders as a one-line summary plus one line per call (e.g. task 42: set status="paused", priority_score=8) — nothing executes until that plan is confirmed.
  • An unresolvable request refuses cleanly, with a reason — "I couldn't figure out what you meant" is a normal outcome, not a crash or a guess.
  • One call failing does not abort the rest of the plan. If a request resolves to several edits and one of them fails (an unknown id, a validation error), the others still run; you get a per-call result.

What's wired up today

This task landed the resolution layer itself — gald3r_project/board/resolve — as a Go package: a Planner interface (the seam any real language-understanding step plugs into), a small deterministic reference planner covering a narrow, fixed set of request shapes (see below), and the Plan -> confirm -> Execute -> rendered result orchestration, wired against the real ops.MutateTask/ops.MutateBug functions.

It is not yet wired into gald3r chat or any other end-user command. That integration — along with the actual language-model-backed planner (see "Design boundary" below) — is expected to land on top of the always-on project-agent runtime (gald3r.ai/swarm/projectagent, tracked as a separate, larger epic) once that runtime reaches main. Until then, this page documents the package contract for whoever wires that integration up, and the narrow reference planner you can already exercise directly against the package.

The reference planner's recognized request shapes

resolve.ReferencePlanner is a small, fully deterministic, zero-model implementation that recognizes exactly these English sentence shapes (case-insensitive):

Request Effect
set task <id> status to <status> Sets the task's status
set task <id> priority score to <n> Sets the task's priority_score
pause task <id> Shorthand for status: paused
set bug <id> status to <status> Sets the bug's status
set bug <id> severity to <severity> Sets the bug's severity
resolve bug <id> as <resolution> Sets the bug's status: done and resolution

Anything outside these shapes returns an unresolved Plan with a Reason explaining that nothing matched — it never guesses.

Design boundary: this package does not ship an LLM integration

T1150's own description imagines a human telling "the AI what needed to be done" and the agent resolving that into calls — i.e. a language model doing the actual understanding. Which model to call, what prompt/context to give it, how much of the board to feed it, and how ambiguity gets surfaced back to the human are all real product decisions with no ratified answer on record as of this task. Wiring a live model call is also outside gald3r_project/'s territory (this task's scope): gald3r_llm and the always-on project-agent runtime are the natural home for a real Planner implementation once that design is ratified.

Nothing about the package changes when that planner arrives — it is just another Planner:

type Planner interface {
    Plan(ctx context.Context, request string, board BoardContext) (Plan, error)
}

Any implementation — the reference planner above, a test's fake model, or a future LLM-backed one — plugs into the exact same resolve.ResolveAndExecute orchestration.

Supported record classes today

Only task and bug ship a built-in dispatcher out of the box (resolve.ClassTask / resolve.ClassBug), routed to ops.MutateTask / ops.MutateBug — the two record classes with the richest, fully DB-first mutation API. The other ten classes T1143 named (ADR, TO-DO, idea, decision, PRD, feature, subsystem, release, constraint, document) already have their own Mutate<Class> functions (see mcp-tools.md); wiring one into the resolution layer is a resolve.RegisterClass("adr", myDispatchFunc) call away, not a package change.

Guard: a "child process" cannot bypass the API with a direct write

Every write this package ever performs goes through a registered Mutate<Class> function — Execute has no write path of its own to fall back to. While building this task, an audit found that ops.MutateTask/MutateBug/MutateTodo/MutateIdea (unlike every other Mutate<Class> function in the codebase) carried no reviewsandbox.Guard check at all: a sandboxed reviewer-turn child (GALD3R_REVIEW_SANDBOX=1) or a T1141 single-writer-board child (GALD3R_SINGLE_WRITER_BOARD=1) could call them directly and mutate the board anyway. This task closes that gap in gald3r_project/board/ops (mutate.go/mutate2.go) — both markers now refuse with the same named errors every other guarded write path in this codebase already uses — and proves the fix holds all the way through this package's own Execute step (resolve_reviewsandbox_test.go), not just when Mutate<Class> is called directly (mutate_reviewsandbox_test.go).