Skip to content
Notis
One State Layer for an AI Assistant: How Notis Uses Supabase

One State Layer for an AI Assistant: How Notis Uses Supabase

Conversations, documents, automations and durable agent sessions all live in one Supabase project — and why the file-sharing trade-off is worth defending out loud.

The hardest thing about building an assistant is not the model. It's that "remember this" and "where is that file" and "keep doing that every Monday" all have to survive a restart, and they all have to agree with each other.

At Notis, that job belongs to Supabase. Database, file storage, and auth — one platform holding the state that makes an assistant feel continuous instead of amnesiac.

One State Layer for an AI Assistant: How Notis Uses Supabase — figure 1

The state an assistant actually has

People imagine an AI product as a model with a prompt. In practice, most of the interesting engineering is bookkeeping.

Our public schema carries the things Notis has to be sure about:

  • users — identity, plan, settings, timezone. The thing every other row hangs off.
  • interactions — the conversation itself, across every channel it arrived on.
  • documents — native Notis documents, the reports and notes the assistant produces.
  • automations — recurring work the assistant runs on a schedule or a trigger.
  • spawn_agent_sessions — durable records for delegated agent work that outlives a single request.
  • rewardful_affiliates — the referral mapping behind personal affiliate links.

Look at that list again. None of it is "AI." All of it is the difference between an assistant and a chat window.

The spawn_agent_sessions table is the one I'd point at if someone asked what changed when Notis grew up. A delegated agent might run for twenty minutes on a Cloud Computer while the person who asked is asleep. The HTTP request that started it is long gone. If that session only lives in process memory, one deploy kills it and the user gets nothing. Putting it in Postgres is unglamorous and it's the whole reason "go work on this and tell me when it's done" is a real feature.

Why one platform instead of three good ones

I could have run Postgres somewhere, object storage somewhere else, and an auth provider on top. Plenty of teams do, and for a large team it's the right call.

For a founder-led product shipping constantly, the coupling is the point. Auth and rows in the same place means row-level policies reference the authenticated user directly rather than through a synchronisation job. Storage in the same project means a file and the document row that describes it share a lifecycle. One dashboard, one set of credentials, one migration story.

The trade-off is real and I won't pretend otherwise: you're consolidating risk. Supabase is in our Help Centre's platform providers overview precisely because it holds the main database and file storage, and users deserve to know that in plain language rather than discovering it in a subprocessor list.

One State Layer for an AI Assistant: How Notis Uses Supabase — figure 2

The file-sharing decision I'd defend in a room full of security people

Notis moves files constantly. You send a voice note on WhatsApp, it becomes an audio file, a transcript, maybe a document, maybe a PDF that gets emailed back. Those artefacts have to be reachable from WhatsApp, Telegram, iMessage, email, Notion, and a browser — systems that share no authentication story at all.

We use public Supabase Storage buckets with unguessable URLs. Every link contains a user identifier plus randomised components, so the address space is far too large to enumerate.

Is that "secure by authentication"? No. It's secure by unguessability, and I say so directly in the Help Centre rather than implying otherwise.

The alternative — signed URLs with short expiry — breaks the actual use case. A Notion page that embeds an audio file needs that file to still resolve next month. A WhatsApp thumbnail needs to render when someone scrolls back. Every team that tries signed URLs for cross-channel sharing ends up building a proxy, and the proxy becomes the thing that goes down.

For genuinely sensitive material we tell people to encrypt before sharing or use Notion's own permissions. Being honest about a trade-off is better than pretending you don't have one.

Working with Postgres when your product is an agent

Two habits that helped.

Read-only schema introspection is a feature. I can ask an agent to check what tables exist and what columns they carry without ever touching row contents. That's how the list above was verified — a query against information_schema, no customer data retrieved. When your assistant can query its own backing store, the boundary between "inspect the schema" and "read user records" has to be drawn on purpose.

Migrations are the product's memory of itself. Every schema change lands as a migration, in the repo, reviewable. Not because a process document said so, but because the first time you hotfix a column in a dashboard and then can't reproduce staging, you learn.

What I'd tell someone starting today

If you're building an assistant, a copilot, or anything that's supposed to remember:

  • Write down your state model before your prompt. What must survive a restart? What must survive a deploy? Those two answers define your schema.
  • Put long-running agent work in a table, not in memory. The moment your product does anything that takes longer than a request, this stops being optional.
  • Decide your file-sharing story early, because it's downstream of every channel you support and it's very expensive to change later.
  • Don't be clever about auth. Use the one that's already coupled to your rows.

Notis has grown from voice-to-Notion capture into connected tools, memory, automations and delegated agents. Every one of those additions was really a question about state — and the answer kept being a table.

Supabase has been holding that state the whole way. If you're starting something, it's a good first decision.

is the founder of Mind the Flo, an Agentic Studio specialized into messaging and voice agents.

Related posts