Guides
Propose and Review Changes
Change proposals let agents suggest specific code modifications that you can review before applying. Each proposal captures the file path, the original content, and the replacement, creating a structured diff you can accept or reject.
When to Use Proposals
Proposals are useful when:
- A background agent finds something to fix and you want to review it before any changes are made
- Multiple agents are working on a codebase and need a review step
- You want a structured record of what changed, when, and why
- You're coordinating changes across files and want to review them together
Step 1: Propose a Change
Create a proposal with the file path, the content to replace, and the new content:
changes(action="propose",
file_path="/src/config.ts",
old_content="const MAX_RETRIES = 3;",
new_content="const MAX_RETRIES = 5;",
description="Increase retry limit to handle flaky API responses",
domain="backend")
The proposal is saved with pending status. It includes the exact before and after, so reviewers see precisely what will change.
Proposals are records, not live edits
Creating a proposal does not modify any files. The proposal captures intent. Applying it later marks it as applied, but the actual file edit is performed separately (e.g., by an editor tool or manually).
Step 2: Link to a Task (Optional)
If the change relates to an existing task, link them:
changes(action="propose",
file_path="/src/auth/middleware.ts",
old_content="if (!token) return unauthorized();",
new_content="if (!token) {\n logger.warn('Missing auth token', { path: req.path });\n return unauthorized();\n}",
description="Add logging for missing auth tokens",
domain="backend",
related_task_id="task_abc123")
Linked proposals can be filtered by task, making it easy to review all changes associated with a piece of work.
Step 3: Review Pending Proposals
List all proposals waiting for review:
changes(action="list", status="pending")
Each proposal shows the file path, description, old content, new content, domain, and when it was proposed.
Filter by Domain
changes(action="list", status="pending", domain="backend")
Filter by Task
changes(action="list", related_task_id="task_abc123")
Limit Results
changes(action="list", status="pending", limit=10)
Step 4: Apply or Reject
Apply a Proposal
Mark a proposal as applied:
changes(action="apply", proposal_id="prop_m4k8n")
The response includes the full old_content and new_content so you (or an editor tool) can perform the actual file change.
Reject with a Reason
If a proposal isn't right, reject it with feedback:
changes(action="reject",
proposal_id="prop_m4k8n",
reason="The logging should use structured fields, not string interpolation")
The reason is stored with the proposal. This is useful when agents learn from rejection feedback to make better proposals next time.
Proposal Lifecycle
Proposals follow a simple state machine:
pending ──▶ applied
pending ──▶ rejected
pending ──▶ expired (automatic, after 7 days)
Only pending proposals can be applied or rejected. Expired proposals remain in history for reference.
Reviewing Change History
See all applied changes in a domain:
changes(action="list", domain="backend", status="applied")
See all rejected changes to understand what was tried and why:
changes(action="list", status="rejected", limit=20)
Example: Agent-Driven Code Review
Here's a typical workflow where a background agent proposes fixes and you review them:
# Agent finds an issue and proposes a fix
changes(action="propose",
file_path="/src/utils/date.ts",
old_content="function formatDate(d) {\n return d.toISOString();\n}",
new_content="function formatDate(d: Date, locale = 'en-US') {\n return d.toLocaleDateString(locale, {\n year: 'numeric',\n month: 'short',\n day: 'numeric'\n });\n}",
description="Add locale support and human-readable date format",
domain="frontend")
# Agent proposes a related test update
changes(action="propose",
file_path="/src/utils/date.test.ts",
old_content="expect(formatDate(new Date('2024-03-14'))).toBe('2024-03-14T00:00:00.000Z');",
new_content="expect(formatDate(new Date('2024-03-14'))).toBe('Mar 14, 2024');\nexpect(formatDate(new Date('2024-03-14'), 'de-DE')).toBe('14. M\u00e4r. 2024');",
description="Update test for new locale-aware format",
domain="frontend")
# You review both proposals
changes(action="list", status="pending", domain="frontend")
# Apply the ones you agree with
changes(action="apply", proposal_id="prop_abc123")
changes(action="apply", proposal_id="prop_def456")
# Or reject with feedback
changes(action="reject",
proposal_id="prop_abc123",
reason="Use Intl.DateTimeFormat instead for better browser support")
Next Steps
- changes Reference — Complete parameter reference for all proposal actions