The right way to hand your AI agent a spreadsheet
Somewhere in your company there is a Google Sheet doing a real job. It tracks orders, or leads, or who owes what, and a couple of people update it by hand every morning. Eventually someone asks the obvious question: can an AI agent just read this and keep it current? The answer is yes — and the way most people wire it up is exactly where the trouble starts.
The quick way, and what it quietly costs you
The quick way is a pre-built connector or a Zapier step: point it at the sheet, grant OAuth, drop it into a chatbot. Fifteen minutes, and the demo works. Then it meets a real week. Someone renames a column and the flow silently breaks. You want the agent to write, not just read, and the connector only does half of that. You want to change what it can touch, and now you are editing someone else's flow, inside someone else's rate limits, hoping they handle your Google token responsibly.
The deeper cost is quieter: you handed a third party a key to your Google account, and a black box you don't control now sits between an AI and your live data. That is fine for a toy. It is not what you want running unattended against the numbers your business actually uses.
What you actually want
You don't want to give an agent "Google Sheets access." You want to give it a short list of exact things it may do to one sheet — running on infrastructure you own, with the credential held server-side and every write written down. That is the whole difference between renting a connection and owning one. It's the same move we make for databases in connecting Postgres without handing over raw SQL: don't give the agent the door, give it a few labelled buttons.
// The agent sees three verbs -- not your spreadsheet, not your login.
get_rows(range) -> read a bounded range
append_row(values) -> add one row
update_cell(cell, value) -> write one cell, if policy allows
How to do it on OBTO
Four steps take you from "it worked in the demo" to something you can leave running.
1. Wrap the sheet in named tools, not access
Each verb above is a small server script that calls the Sheets API and is published as an MCP tool. The agent never sees a spreadsheet or an API; it sees append_row and get_rows. Because a tool is the boundary, the agent can only ever do the handful of things you defined — there is no "and also delete the tab" hiding in a broad grant. If the term is new, what an MCP server is covers the basics.
2. Keep the Google credential server-side
The service-account key lives in the server, never in the prompt and never in the agent's context. The agent calls append_row; the server attaches the credential and makes the request. So a jailbroken agent has nothing to leak — it was never holding the key. This is the same rule as why your agent should never hold its own secrets, applied to a spreadsheet.
3. Put the limits in front of the write
A server-side policy decides before any write runs: this range is read-only, appends are fine, overwriting the totals row needs a person. Because it runs on the server, it holds no matter what the prompt said or how the model was talked into asking — the same argument as guardrails that live in front of the action, not in the prompt. A confused agent can propose clobbering the sheet all it likes; the policy is what actually answers.
4. Let the agent extend its own tool — safely
Here's the part most stacks can't do. Mid-task, the agent finds it needs an operation you never built — say, roll a column up into a summary tab. On a normal pipeline that's a ticket: a human writes the function, opens a pull request, waits for CI, deploys. On OBTO the agent can create that tool itself, at runtime, against the live server. The catch that makes it safe is structural, not a matter of trust: a new tool is refused unless its bytes hash to exactly what was promised, and a change to an existing one is refused unless the anchor text still matches what's live. That integrity check is doing the job a human code review does in a standard deploy. So the agent grows its own toolset without a deploy loop — and without becoming a way to smuggle arbitrary code into production.
And none of it happens off the books. Every read, every append, and the tool the agent just built land on the Glass Receipt: what ran, with which arguments, allowed or refused. When you're deciding whether to trust the agent with a little more, that record is the whole basis — there's more on it in building an audit trail your agent can't skip.
{
"run_id": "run_7f2a",
"tool": "append_row",
"args": { "range": "Orders!A:E", "values": ["A-9931", "Acme", 1840.00, "net-30", "2026-07-14"] },
"policy": "totals_row_is_read_only",
"decision": "allowed",
"executed": true
}
Why bother owning it
Because the demo was never the hard part. Reading a clean sheet once is easy, and anyone's glue can do it. The hard part is the ten-thousandth run: the column got renamed, a second app wants the same tool, finance needs to know exactly what the agent wrote last Tuesday, and nobody wants a bill that scales per task. A connector you own — scoped, server-side, receipted, and extensible — is what survives all four. The rented version survives the applause and not much after it. If that trade-off sounds familiar, it's the same one behind connecting Slack to an agent the durable way rather than the fast one.
The short version
Don't rent the wire between your agent and your spreadsheet. Give it a few exact verbs, keep the Google key on the server, put the limits in front of the write, and let it extend itself under an integrity check. That's the difference between an agent that can read your sheet in a demo and one you can leave alone with it. The getting-started guide walks the first tool end to end in about ten minutes, and every tier in OBTO's pricing includes the policy layer and the Glass Receipt — the safe part isn't the upsell.