The pattern
Three nouns, two arrows: agent → grid → human → grid → agent.
- The agent writes a batch of candidate actions to a grid — refunds to approve, emails to send, tickets to escalate. Each row is one decision.
- A human opens the grid (
https://instadash.io/<handle>/<slug>) and reviews. They tick anapprovedcolumn or edit areply_textcell. Edits are persisted server-side, immediately. - The agent polls
/edits?source=human&since=<timestamp>and gets back a flat list of changed cells. It filters to the approved rows and acts on them.
No queue, no Slack bot, no email digest. The grid IS the review surface and the integration surface.
Setup
Push the candidate rows with an actions schema that includes an approved checkbox column:
await fetch('https://instadash.io/ingest', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.INSTADASH_API_KEY}`,
'Content-Type': 'application/json',
'X-Grid-Slug': 'refunds-pending-review',
'X-Grid-Editable': 'true',
},
body: JSON.stringify(
refundCandidates.map(r => ({
customer_id: r.customer_id,
amount: r.amount,
reason: r.reason,
approved: false, // human flips this
})),
),
})Send the URL to whoever reviews:
https://instadash.io/<handle>/refunds-pending-review
Read back the human's decisions
After review, the agent reads /edits:
const r = await fetch(
`https://instadash.io/<handle>/refunds-pending-review/edits?source=human&since=${lastChecked}`,
{ headers: { Authorization: `Bearer ${process.env.INSTADASH_API_KEY}` } },
)
const { edits } = await r.json()
// edits: [{ row, col, value, source: 'human', timestamp }, …]
const approvedRowIds = edits
.filter(e => e.col === 'approved' && e.value === true)
.map(e => e.row)
for (const rowId of approvedRowIds) {
await issueRefund(rowId)
}The agent keeps a lastChecked timestamp in its own state to avoid double-processing.
Framework integrations
- LangGraph — drop the read-edits step into a graph node, route to "act" only when approvals are present. See
/recipes/langgraph-instadash. - CrewAI — model the reviewer as an external resource the crew waits on. See
/recipes/crewai-instadash. - Custom — any agent that can make HTTP requests can use this pattern.
When this beats other approaches
A Slack bot for approvals works for one-off cases. A spreadsheet works until you need an audit trail. An admin dashboard works until you want to wire a different agent in.
The grid is the shared substrate: human-friendly UI, agent-friendly API, immutable history. The reviewer doesn't need a developer to ship an approval flow, and the next agent that needs the same human signal reuses the same grid.