Daeseon Yoo
Back to project
·Tech retro·3 min

The control gate, proven live — and the 411 that almost hid it

The propose→approve→execute gate ran end-to-end on a real machine and a real Google Calendar — but only after fixing an HTTP 411, stopping the agent from reaching for its own Calendar connector, and untangling a dev-environment that made the dev build look slow.

The whole product thesis is one sentence: the AI does the work, you stay in control. Today that stopped being an architecture claim and became a thing that happened on a real machine.

In a packaged build, I typed — in plain language, to my own Claude in a pane — "put lunch tomorrow 1pm on the calendar." The agent did not create the event. It called propose.calendar, which staged a proposed_action node. It appeared in the 📥 Approvals inbox. I clicked Approve. The app ran the gated executor and the event landed in my real Google Calendar: "✅ Approved & executed."

Propose → approve → execute → receipt, end to end, on a real account. That was the goal. Getting there surfaced three honest problems.

1. The agent reached for the wrong tool

The first live attempt failed in a revealing way: the pane showed "Called Google Calendar" and then "authenticate via /mcp claude.ai Google Calendar." My Claude had reached for claude.ai's own Google Calendar connector, not Talkak's propose.calendar. That connector bypasses the approval gate and the founder's already-connected account — it would have defeated the entire point.

The fix was to make the pane directive explicit: for any email/calendar/document action, you MUST use the mcp__dalkkak__* propose tools and NEVER claude.ai's Gmail/Calendar/Drive connectors or any other integration. "There's a tool literally named Google Calendar" is not a good enough reason for an agent to route around your control plane.

2. HTTP 411 — the empty-body POST

With the right tool, Approve fired — and Google answered 411 Length Required. The quickAdd endpoint is a POST with the text in the query string and an empty body, and ureq's .call() sends no Content-Length header. Google rejects that. One line: .send_bytes(&[]) sends an empty body with Content-Length: 0. Then it worked. The gate logic was never the problem; an HTTP header was.

3. "Your dev build is slow" was a misdiagnosis

In between, the dev build felt sluggish and I blamed the machine — swap, load average, reboot. The founder corrected me, sharply and correctly: the production app he uses daily was perfectly fine on the same machine; only the thing I launched was slow. He was right. The slowness was dev mode — an unoptimized debug binary plus a vite dev server, esbuild, file watchers, and recompiles-while-I-edited — not the features (the new panels have zero polling loops) and not a broken machine. Relaunching pnpm tauri dev several times to chase a config bug also left behind a pile of build artifacts that the OS file daemons then churned through indexing. Lesson banked: production .app for using it, dev mode only for building it — and never tell a founder his machine is the problem when his own evidence says otherwise.

There was also a genuinely nasty wrinkle underneath: several worktrees (ddalkkak, -cpx, -integrate) share one ~/Library/Application Support/DalkkakAI/bin config, and whichever app instance ran ensure_wrapper last clobbered it — so the pane kept getting an old worktree's MCP server (no propose tools) and an old directive. The stopgap was to write the correct config and chmod 444 it so a stale instance's write silently fails. In production, with one app and no worktrees, this can't happen; in a multi-session dev setup it absolutely can.

What's verified

cargo test --lib 258/0, the local MCP server 46/0, tsc and vite build clean, the MCP server confirmed bundled inside the packaged .app (Resources/local-mcp-server/dist/..., exposing the propose tools), and — the one that counts — the gate executing a real calendar event on Approve. Commit ef93b38 carries the 411 fix and the directive hardening.

The moat was never the model. It's the gate: the agent proposes, you decide, and only then does anything touch the outside world. As of today, that's not a diagram.