Spegling exists to make what an AI did checkable afterwards. A product built on that claim has no business being vague about its own posture. So this page says how the thing actually works, and then lists what it does not do yet. The second list is the one worth reading.
Accurate as of 6 August 2026. Single operator, one server, no employees.
Spegling is a personal and small-team system holding one person's working material: notes, documents, a patterns corpus, journal sessions, and the record of what agents did with them. It connects to mail and calendar on request, and it calls hosted language models.
What it is built to resist:
What it is not built to resist, stated plainly:
These are the things that have to be true for the rest of the page to hold. They are assumptions, not guarantees, and they are worth stating because most security pages quietly depend on them without saying so.
Sign-in is Google OAuth against an email allowlist. There is no password to steal because there is no password. A successful sign-in returns a JWT signed HS256: the access token lasts 14 hours, the refresh token 30 days. The server refuses to start in production with the default signing secret or an empty allowlist.
Machine callers use enclosure API keys. Only the SHA-256 digest is stored, so the database never holds a usable key. A key is bound to one hat, and that binding wins over anything the request body asks for.
Isolation is enforced in application code: every query carries an enclosure scope resolved from the caller's credentials, never from the request. Sixteen boundaries currently have a dedicated test that provisions two real tenants against a live database and asserts the second sees nothing: ask, files, tags, related, research, synthesis, footprint, rate limits, document ingest, dev intents, capability calls by hat, agent action audit, the MCP audit trail, the trust-scope wall, the project lens that reads through it, and provider scoping. Other surfaces carry the assertion inside their own suite. That is a real discipline and it is also a weaker guarantee than the database enforcing it, which is in the limitations list below.
OAuth access and refresh tokens for connected accounts, and file-vault blobs, are encrypted with Fernet before they touch the database. Revoking a connected account nulls the ciphertext rather than leaving it behind. The credential paths log account ids, provider and address, never token material.
Governed runs write a hash-linked chain. Each phase row carries the previous row's hash, plus digests of the maker's output, the reviewer's reasoning and its structured checks. Verification happens on the server and reports three properties separately, because conflating them is how a verifier ends up lying:
Linkage. Does each row point at the one before it.
Row. Does each row's hash still recompute from its own fields.
Content. Does the stored text still match the digest that was sealed.
Plus a count check against the run's declared phase count, because linkage alone cannot notice that every row was deleted.
A run also records the configuration it executed under: which models in which roles, the review questions, the thresholds, the token budgets. The hash of that configuration is a key into a table that holds the configuration itself, not an opaque stamp, so "these two runs were judged by the same rules" is a question with an answer.
One thing the verifier says about itself, in the response it returns: recomputation proves the record is internally consistent. It does not prove the operator left it alone. Nothing self-hosted can prove that, and a verifier that implied otherwise would be worse than none.
Search, document ingest, file upload and corpus flagging carry per-caller rate limits keyed to the enclosure or user. nginx adds per-IP limits in front. These are cost brakes and they fail open: if the cache is down, requests proceed. Governance gates are the opposite and fail closed.
Nightly database dumps, owned by root and group-readable by the application user, which can read them but cannot write or delete them. That asymmetry is deliberate: an agent that damages the live database must not be able to reach the archives. Thirty days on the host. A separate nightly job encrypts each dump with GPG AES-256 and pushes it to object storage, so the storage provider only ever holds ciphertext.
One Hetzner server in Helsinki, Finland. Postgres runs on the same host and binds to loopback only, so the database is not reachable from the network at all. TLS is Let's Encrypt, issued and renewed by certbot. HSTS is set with a two-year max-age.
| Goes to | What | When |
|---|---|---|
| Nebius AI Studio | Prompt content and the text being embedded | Every model call and every indexing pass |
| Brave Search | The search query | Only on an explicit web search |
| OAuth exchange; mail and calendar reads on request | Only for accounts you connect | |
| GitHub | OAuth exchange; repository reads for linked workspaces | Only for repositories you link |
| Anthropic | Prompt content for coding sessions | Only when a coding agent is run |
No analytics vendor, no advertising network, no session recorder, no third-party fonts on the application itself. Page-view counts are written to our own database.
This is the part that decides whether Spegling is right for you, so it is not buried. Everything here is a known gap, not a maybe.
There is no consent gate, no break-glass ceremony, no cryptographic control that keeps me out of your enclosure. Access is logged, and logging is not prevention.
The mechanism is chosen (redaction with a tombstone), and the schema work is deployed: the maker's output can be dropped, the reviewer's reasoning has a stored digest so removing the text reads as an erasure rather than a tamper, and the verifier reports erased content as unverifiable instead of broken. The map of every store holding subject data is complete and checked against the live schema on every change, and the operator runs erasure through a tested command rather than by hand. What does not exist is self-serve: a request still goes through a person. Ask before you rely on it.
Postgres row-level security is not in use. A new query that forgets its enclosure scope is a real class of bug that tests catch rather than the database refusing. The tests are per-boundary and they run on every change, but that is a weaker promise and it should read as one.
The JWT is kept in localStorage, a deliberate trade for
having no cookies and therefore no CSRF surface. The cost is that a
successful cross-site scripting bug would yield a token good for up to
14 hours. The studio does send a content security policy, but it allows
inline script, so it would not stop injected code from running. What it
does restrict is where that code could send anything:
connect-src is limited to our own two API hosts. Values
interpolated into markup are escaped at every point, which is a
discipline rather than a structural guarantee. The API itself sends a
deny-everything policy, which matters less because it only serves JSON.
They fail open by design. Treat them as protection against a runaway loop and an accidental bill, not as protection against a determined attacker.
Content sent for inference is governed by each provider's published terms. I have not negotiated a data processing agreement with any of them, and I will not claim EU-only inference until I can show the paperwork. If your material cannot go to a hosted model, Spegling in its current form is not the answer.
No penetration test, no SOC 2, no ISO 27001. One person wrote this system and one person reviews it, with a fresh-context review pass on changes rather than a second pair of human eyes. Small teams often stay quiet about this. It is the single largest gap on the page.
If I am unavailable, nobody else operates this. There is no on-call rotation and no successor arrangement. Backups exist and are restorable; an organisation depending on Spegling should hold its own export.
On-host dumps are protected by file permissions only. Encryption is applied to the copies that leave the machine. Someone with root on the host reads them either way, which is why this sits under limitations rather than under backups.
Mail hannu@varjosoft.com. There is no bug bounty and I will not pretend otherwise. What I will do is reply within three working days, tell you honestly whether it is being fixed or accepted as a known trade, and credit you if you want it. If a fix ships, this page changes with it.
Spegling is operated by Varjosoft Oy, Finland. One controller, EU hosting, named provider. If a claim on this page turns out to be wrong, that is a bug and it gets the same treatment as any other.