The administration console
CIND3R3LLA is operated from one console, not from a pile of environment variables and a log file. This page walks through the areas that exist, what each one actually does, and where a page tells you honestly that there is nothing behind it yet.
One console, six areas
The console is a server-rendered Fastify application bound to 127.0.0.1. Public nginx TLS sits in front of it at the admin hostname, so the process itself never listens on a public interface. Passkeys are the primary authentication, with an operator-toggleable Argon2id break-glass path behind them.
The navigation has six top-level areas: Dashboard, Content, Interaction, AI Control, Plugins and System. Each one expands into its own set of pages, and the shell carries a mobile navigation as well as the desktop one, because an operator who has to answer a report at eleven at night is holding a phone, not sitting at a desk.
There is no separate configuration file that quietly overrides what the console shows. Live settings are persisted in PostgreSQL and applied immediately. Boot settings that genuinely require a restart are shown read only, and secrets are never rendered at all, not even as masked previews.
Dashboard and runtime status
The dashboard answers one question first: is capture healthy right now. It shows the bot state as running, starting or failed, along with the error text if there is one, the groups she is in, the timestamp of the last captured message, and how long the process has been up.
Five counters sit above that: total messages, published messages, deleted messages, opted-in members and revoked consents. Below it, messages by type, the most recent errors, and the last ten audited admin actions with actor, action, target and time.
Two warning banners appear only when something is actually wrong, and the file-receipt indicator is always present: green while every expected media file has arrived, red the moment one has failed or gone past the alert threshold. Failed or at-risk file receipts are flagged against the roughly 48 hour XFTP expiry window, because a media file that has not arrived within the alert threshold is a file you can still chase and soon will not be able to. Unrecognised capture exclusions are flagged in amber: capture dropped an item whose chat scope it does not recognise, which is not a consent leak but is a gap in understanding. Media that could not be served or stripped is flagged too, so a withheld image never stays invisible.
Two of the three banners are silent when everything is fine, which is what makes them worth reading when they are not; the third stays visible and turns from green to red.
Content and moderation
Messages is the archive browser: filterable, paged, with takedown, restore, delete and undelete. Every one of those writes an audit record carrying the sender id, the message type, the sent time and whether the item was published at the moment you acted. A message the author already deleted inside the group cannot be restored into publication at all, the console refuses it rather than quietly complying.
Because publication is derived rather than stored as a flag, a correct action can leave the visible state unchanged, for example a takedown on a message whose author never opted in. The console prints a confirmation for exactly this reason, so a working control never reads as an inert one.
Consent is deliberately read only. Members grant and revoke it themselves, and the operator watches: status, opt-in time, revocation time, message count and published count per member. There is no button here that would let an operator opt somebody in.
Reports is the queue for content flagged by the public, filterable by status, with takedown, resolve and dismiss, each audited. Reporting on its own never hides anything. Only the operator's takedown does.
Evidence holds cover the harder case. A hold keeps an item from being destroyed while a report is reviewed, without hiding it and without publishing it. The page separates live from resolved holds, warns about holds expiring soon, and offers release, destroy and escalate. The hold period in days and the abuse threshold, after which a source whose reports keep getting dismissed stops creating holds, are both ordinary settings.
A hold never hides content and never publishes it. It only defers erasure.
Screening and custody In development
The Screening page exists and the custody path behind it is built, but no screening provider is connected. The provider table shows exactly that: provider name, configured yes or no, whether it transmits content, items screened, matches, errors and last activity. Today it reports the null provider, not configured, nothing leaves the host.
The page states its own limits before it states anything else. Hash comparison finds known material only. It does not find new or previously unseen material, and a result of no match means only that the item is not on the list. That is not a statement of safety and nothing in the product presents it as one.
A match preserves and quarantines, it never deletes, because destroying a match destroys what makes a prosecution possible. Quarantined media is moved outside the media tree to a separate quarantine root that nothing serves, and no path in the system can delete it. There is no preview of a quarantined item in the console, by design.
Reporting duties, retention periods and the point of contact are legal questions for a lawyer and are deliberately absent from the code rather than guessed at.
No screening provider is configured, the null provider transmits nothing, and the console says so on the page rather than in a footnote.
Interaction
How Cinderella is addressed and how she answers is configured across ten pages: Addressing, Guards, Follow-up, Language, Replies, Nicknames, Consent, Voice, Archiving and Diagnostics.
That covers wake words and natural addressing, the guards that decide when she stays quiet, follow-up behaviour, language handling, reply modes, the nicknames she answers to, the wording of the consent dialogue, voice handling, whether her own replies are archived alongside the member message that triggered them, and a diagnostics view for working out why a particular message did or did not reach her.
Every change is persisted and written to the audit log under interaction.update, so the question of who changed her behaviour and when has an answer.
AI control
Local inference runs through Ollama on a private endpoint, and the console treats that as an operational system rather than a checkbox. Runtime separates the stored setting from the effective state, probes the endpoint before activating, and refuses to activate when a selected model is not actually installed. If the model layer fails, resolution falls back to deterministic rules. There is no cloud fallback to fall back to.
Models lists what is installed, with family, parameter size, quantization level and file size as reported by Ollama, plus a refresh. Routing assigns models independently for the two lanes: one for intent classification, one for reply wording.
Hardware is deliberate about its own blind spots. It shows the catalog state, the runtime mode, the provider boundary and the footprint of the two selected models, and it marks GPU telemetry as not integrated. No utilization, temperature or VRAM figure is claimed, because none is measured.
Telemetry is content free. Both lanes record requests, successes, failures, fallbacks, average and last latency, and last success and last failure. The intent lane adds guard overrides and the last classified intent; the reply lane adds the last reply kind, mode and error category. All of it sits in a bounded buffer the operator can reset. Member text, prompts, names and generated replies are never stored there. Runtime toggles, routing changes and telemetry resets are audited as local-ai.toggle, local-ai.routing.update and local-ai.telemetry.reset.
The models classify and phrase. They do not execute actions, change consent, publish content or send arbitrary messages, and that boundary is enforced in application code rather than requested in a prompt.
A model failure returns to deterministic rules. It never returns to somebody else's cloud.
Pages that state what they do not do
Several AI Control pages are read-only status surfaces rather than control panels, and they say so on the page. Privacy and Safety shows a capability matrix with the technical reason for each row, listing cloud providers and automatic cloud fallback as disabled and per-room policy, classification policy and retention windows as not configured. Providers confirms the same from the other side: no credentials stored, external providers disabled, silent provider activation forbidden.
Knowledge and RAG reports zero indexed documents, no embedding model and no vector store. It is preparation, and it is labelled as preparation. Personality describes the layer that exists, which is guarded reply wording in German and English with the deterministic facts preserved, and marks a permanent personality profile as not configured.
Testing offers one thing that genuinely works, a probe of the active role models with latency and a clear yes or no on whether the selected models are present. Side by side model comparison is listed as disabled, because it is. The AI Audit page lists the action types already covered by the central audit log; a filtered AI audit browser with search, time range and actor is planned and is described as planned.
A page with nothing behind it says so, instead of offering a switch that does nothing.
AI bot setup and access control In development
AI Bot Setup is a guided assistant that presents one decision at a time: the bot's display name and internal key, how direct SimpleX contact requests are handled, how invitations are reviewed and which SimpleX role is expected, whether the bot may execute remote commands or save permanent changes, and a review step before saving. The advice on the page is to keep both capability switches off during the first connection and role tests.
Access Control assigns authority around those profiles: SimpleX identities with profile-level permissions, group assignments, and member roles within a group. Everything persists to PostgreSQL and writes audit records for creation, for enabling or disabling a profile or group, and for every authority assignment. There is no delete control on this page; a profile or group is disabled rather than removed.
What these two pages do not yet do is drive the embedded SimpleX core, and they say so themselves. The boundary note reads stored access policy only, with runtime marked not active and enforcement marked foundation only. Invitation handling, group joining, command execution and runtime enforcement are part of the multi profile runtime that is in active development. The configuration surface is real, the enforcement behind it is not connected yet.
Plugins and system configuration
Plugins has an overview plus one page per registered plugin, generated from the registry rather than hand-listed. Crypto Prices is the first working example, with its providers, its pinned symbol to asset mappings so that a ticker means the asset you actually meant, and its cache. Enabling a plugin and changing its settings are separate audited actions.
System holds Settings, Security, Embeds and Website. Settings covers the live values that apply without a restart: log level, file receive timeout, the file alert threshold in hours, the evidence hold period in days, and the hold abuse threshold. Boot configuration is shown for reference only, with secrets never rendered.
Security is where the console hardens itself, and every control there is persisted and audited. Passkey registration and removal, with a standing warning until at least two devices are enrolled, because losing your only passkey with break-glass disabled means lockout. The Argon2id break-glass path with an optional mandatory TOTP code. Session idle and absolute lifetimes, and step-up re-verification before sensitive actions such as a takedown or a configuration change. Login attempt limits, window, lockout duration and a global per-minute rate. IP allowlist or denylist, off by default and honestly labelled as a poor fit for a dynamic address. Content-Security-Policy, HSTS max-age with includeSubDomains and preload, Referrer-Policy and Permissions-Policy, with a one-click reset to the secure default. Argon2id cost parameters. An HTTPS webhook for security alerts.
Below the editable controls sits a read-only Enforced status block for the things an operator cannot weaken: trustProxy pinned to loopback, a signed session cookie with Secure, HttpOnly and SameSite=Strict, and CSRF required on every state change. A security event feed lists logins, failed logins, step-ups and rejected registrations, with anomalies highlighted. A lockout is delivered to the configured security webhook rather than to this feed.
Website governs the three opt-in building blocks of the public site, analytics, cookie banner and social share, all off by default and each one a deliberate decision by the operator rather than a default that happened to them.
The administration principle
Every operational capability in CIND3R3LLA is expected to have all eight of the following: a backend implementation, persistent settings, an administration control, a stored status and an effective status shown separately, audit coverage, automated tests, clear failure behaviour, and a documented boundary. A capability that cannot show all eight is not finished, and the console is expected to say so.
This cuts both ways. Nothing important hides in code behind an empty control panel, and any control that is not yet wired to backend behaviour is disabled or labelled on the page as stored-only, never presented as if it were live. Where the honest answer is not configured, the page prints not configured. Where the honest answer is stored but not enforced, the page prints that instead of implying enforcement.
Failure behaviour is part of the definition, not an afterthought. A caught error is never converted into a value that reads like a legitimate result, a degraded function never runs silently, and anything on the consent, capture, publication, media or plugin path that loses a guarantee is surfaced in the console rather than buried in a log file. Not configured, which is a choice, is distinguished from configured but failing, which is a fault. A fallback that could mask a fault is counted, and the count is shown.
The tests are not a promise either. The admin console, its navigation shell, the security settings, the profile pages, the public site, consent, revocation and holds, the job queue and the screening path each have their own verification harness, run against real PostgreSQL compiled to WebAssembly so the checks exercise actual SQL. The AI runtime, models, routing and telemetry harnesses run offline against an in-memory settings store and a stubbed HTTP client, so they never touch a database or a real endpoint, and the setup workflow harness checks the built markup rather than a database.
CIND3R3LLA does not hide important behaviour in code while presenting an empty control panel, and it does not present controls that are not connected to real backend behaviour.