By the end of this you will have the whole stack up, an agent that answers from your own files, and — this is the part that matters — you will have watched it refuse to do something, on purpose.
Budget about thirty minutes, most of it waiting for images to pull.
You need Docker with Compose, and a key for an AI gateway or model provider.
Open .env and fill in four values. Three of them are secrets you invent:
Then:
Give it a couple of minutes. docker compose ps should show every service up, and
nextcloud-ai-db-1 as healthy.
Four scripts. All are idempotent — running one twice is safe, and you will run them again after changing anything.
oidc.sh is the one worth pausing on. There is no external identity provider here:
Nextcloud issues the tokens and accepts them. That is what makes the token's
subject equal to the Nextcloud username by construction, rather than by a mapping
somebody has to maintain.
Open http://localhost:8080 and log in as the administrator you configured.
Now create a second account — and use that one from here on:
This is not tidiness. The entire guarantee of this system is "the agent sees what the user sees", and an administrator sees everything. Pointing the agent at an admin account turns that sentence into "the agent sees everything" without changing a line of code or producing a single warning.
Setting the email is not optional either, though nothing will fail without it: it is what publishes the account into Nextcloud's system address book, which is where the agent finds a colleague's address instead of inventing one.
Read its output rather than the exit code:
The last line is the interesting one. It took a token that works — the four ticks above prove it — and tried to use it to read another account's files and to list the server's users. Both were refused, by Nextcloud, with nothing in our code involved.
Run this after any change to authentication. It is the only thing that proves the central property still holds.
Log into Nextcloud as alex, and upload a document you actually know the contents
of — a PDF or a Word file is a better test than a text file, because it exercises
the conversion path. Put it somewhere with a real name, say /Contracts/.
Open the Tamebi app from the Nextcloud sidebar and ask something that requires reading, not listing:
Where does the contract say what happens if we terminate early?
Watch what happens under the reply. You should see the tool calls: a search that narrows, then a read that returns a passage rather than the whole file. The answer should quote the document.
If the agent says it cannot find anything, that is a legitimate outcome on the first try — the content index is filled by searches themselves rather than by a background crawler, so it warms up as it is used. Ask again in a minute. That behaviour is a direct consequence of the tool server holding no credential of its own: there is no privileged process that could crawl everything up front.
Add an event to my calendar tomorrow at 3pm, "Contract review".
This time the agent stops and asks. The confirmation is not politeness and it is not written into the prompt: the tool declared itself as having an effect, and the approval requirement was derived from that declaration three services away. A tool that declares nothing at all is treated the same way, because the policy fails closed.
Approve it, and check the Calendar app. Then try:
Now make that file public so I can send the link to a client.
It will tell you it cannot. There is no tool for it — not disabled, not permission-checked: absent. One call would turn read access into exfiltration, and nothing about the request would look wrong, because the user is allowed to share that file.
Four things, in order:
To see how a single message actually travels through the five services — and to read the record it left behind — continue with Follow one message end to end.