The kernel and approvals
Every tool call, from any model and any loop, passes one function in Zyx’s kernel: decide(). It
answers allow, refuse, or hold for a person. If it is unsure, it holds. The kernel is plain
TypeScript with no AI framework inside it, so a change of model or runtime does not change the rules.
What decide() checks, in order
Section titled “What decide() checks, in order”- Content (the privacy gate). Every outgoing payload is checked.
- Passwords and keys are blocked. The token rules come from the open-source gitleaks rule set (220 rules), plus a rule for a random-looking string right after a word like “Passwort” or “Token”.
- Personal data has Zyx’s own rules: labelled identity fields, IBAN, tax and ID numbers, addresses. Checksums (Luhn, IBAN) cut false alarms. Company register numbers and customer numbers pass.
- Names in web calls. A small local model (GLiNER multi-PII) reads a web search’s query (the built-in web search and the Brave, Exa, Tavily, Perplexity and Firecrawl search tools), a web fetch’s URL and the URL the browser opens. A private name or address there becomes a card. If the model cannot answer, that is a card too.
- Private paths. Zyx’s own state, the secrets file,
.ssh,.envfiles and similar are always refused, never asked. - Folder confinement. A person, a schedule or a trigger reads and writes only the folders it may. A person’s read elsewhere is a card. A scheduled run’s read elsewhere is refused, because nobody is there to answer.
- Whose turn. A turn the owner did not start may use only the tools it was granted.
- The wall. Every shell command runs in a Docker sandbox, one per session, with nothing of the server in it and no credential. Files cross only through named copy steps. If Docker is down, the command is refused with the fix; there is no fallback to the server itself.
- The question: ask or not. Whether a call needs a person is judged per call, by risk.
What always asks
Section titled “What always asks”Sending mail always asks. No rule, no standing approval and no routine turns this card off.
| Always a card | Judged per call | Never allowed |
|---|---|---|
| Sending mail | everything else that changes something | reading keys, .ssh, Zyx’s own state |
| Anything on the company’s own ask-first list | writing outside the allowed folders | |
| A connected app’s tool that sends or pays | ||
| Pictures, video and sound from fal.ai (each call, with its price) | ||
| Moving a file where more people can read it (the card names them) | ||
git push, merges, unknown GitHub writes |
||
| A tool the kernel has never judged | ||
| A change in a chat that outside content has reached |
The risk judge is a small model. It fails closed: unsure or too slow means ask. The company’s ask-first list is a file the owner edits on the Permissions screen.
The card
Section titled “The card”A card shows the exact call: what will run, with which input. The owner or the right person presses
Approve, and that one call runs at most once. A mail card also offers “Hold, I read it first”
and lets the person edit the subject and body before approving; the edited version is what runs.
Before the send, the card warns about any address that no source in the chat names: the model may
have made it up. A privacy mask such as [REDACTED:phone-de] is never sent; a call that carries one is
refused, and the model writes the real value from its source or leaves it out.
Who may decide a card follows the company’s rules: a department’s card goes to its lead, a money threshold goes to the owner, nobody approves their own turn’s card, and a four-eyes class needs a second, different person.
On the way back
Section titled “On the way back”decideResult() checks every tool result before the model sees it or the chat stores it:
credentials are blocked, personal data is redacted, and every result from outside (a web page, a
mail, an app) is marked as untrusted data. That marking is the defence against a page or a mail
telling the model what to do.
Every action that changes something declares how it is undone: exactly, by a compensating action (with its cost shown), or not at all (with the reason shown). A change with no undo answer fails Zyx’s own tests. The History screen lists what can be undone. A sent mail cannot be undone: an approved mail offers no Undo, and its line says so.
Earned trust
Section titled “Earned trust”Each kind of tool sits on a ladder: shadow, suggest, approve, audit. Clean approvals can promote it; one rejection, undo or bad vote demotes it at once. Sending mail, and anything on the never-auto list, never leaves “approve”. “Not now” on a mail card is no rejection of mail itself: it never switches mail sending off.
Coding work
Section titled “Coding work”A coding job gets its own git worktree and branch, may write only there, and ends in a diff. Pushing is its own card. Zyx never merges; a person does.
Paid pictures, video and sound
Section titled “Paid pictures, video and sound”Zyx can make a picture, a video or a sound with fal.ai and save it in the company folder. It first offers a free way (Pictures, video and sound). Every paid call is its own approval that shows the price, written as “about”. No standing approval covers it, in a chat or in a routine. A model without a price is refused, so nothing is spent on a guess. The owner sets a monthly budget on the Usage screen. A call that would cross it is refused before a card exists, and two cards approved at once cannot both pass. The prompt goes through the privacy gate first, so personal data never reaches fal.ai.