Your AI knows how to think. Dillo gives it a backend.
You already have an AI. What it doesn't have is a backend — somewhere to put things, rules about who sees what, functions it can call. Dillo is that backend. Your agent connects with a scoped key — and this demo shows the safe way to run one: the key's prefix, scopes, and expiry are public, but the secret itself is never shown, anywhere. It can read and write what you allow, nothing more.
The permissions are the app. This is the whole data model — schema.ts, the first of the app's three files (its import line, not shown, brings these names in from "create-dillo/schema"):
// The schema the live backend serves today (span2/live-schemas filing, re-verified at deploy).
export default schema({
Audit: table({
action: string().max(80),
authorization: string().max(200),
principalId: string().max(160),
principalType: string().max(40),
requestId: string().max(200),
resourceId: string().max(200),
}).permissions({ view: owner, edit: nobody }),
Document: table({
content: file().accept('application/pdf', 'text/plain').maxBytes(262144),
title: string().min(1).max(120),
}).permissions({ view: owner, edit: owner }),
Grant: table({
decision: string().min(1).max(16).default('pending'),
documentId: relation('Document'),
expiresAt: string().datetime(),
fileId: string().min(1).max(160),
readsLeft: integer().min(0).max(5).default(5),
recipientId: relation.user(),
revoked: boolean().default(false),
title: string().min(1).max(120),
tokenHash: string().min(64).max(64),
}).permissions({ view: owner, edit: nobody }),
Note: table({
text: string().min(1).max(1000),
}).permissions({ view: owner, edit: owner }),
Person: table({
name: string().min(1).max(120),
userId: relation.user(),
}).permissions({ view: owner, edit: owner }),
});