Workspaces
Each row is one isolated tenant environment — its own users, cases, and documents, walled off from every other workspace. Users and Cases count what currently lives inside it. Suspend blocks every user in that workspace immediately; Restore reverses it. To see or manage the individual people inside a workspace, use the Users sub-tab and filter by its name.
Loading…
Users
Loading…
Create Account
Edit Account —
Login History
Select a user to see their login history.
Site access
No new sign-ups closes account creation — the email/password register form and the first-time Google sign-in path — and shows the message below on the login pages. Existing users sign in exactly as normal, whether they have a live session or not. The admin panel is unaffected, so you can always get back in to turn it off.
🟢 OpenAI (Whisper)
Manage API credits for Whisper audio transcription. Add billing credits here when transcription fails with "credit_balance_exhausted".
Balance: —
OpenAI — Billing ↗🔵 Google Gemini
Two independent API keys route every Gemini call (modules/geminiKeyRouter.js): free-tier is tried first (zero cost, limited quota), paid-tier is the fallback (billed, higher quota). Tenants are billed the SAME rate regardless of which one actually answered — this only affects what WE pay Google, never what a tenant is charged.
🆓 Free tier
Today's usage: —
💳 Paid tier
Balance: —
🟠 Anthropic Claude
Manage API keys, view rate limits, and top up credits in the Anthropic Console.
Balance: —
Anthropic Console — Dashboard ↗ Anthropic Console — Billing ↗🟦 DeepSeek
Manage API keys, view rate limits, and monitor token usage on the DeepSeek platform.
Balance: —
DeepSeek Platform — API Keys ↗ DeepSeek Platform — Usage ↗🟡 OpenRouter
Hosted-model gateway: the knowledge miner (KNOWLEDGE_MINE_MODEL=or:…, modules/knowledgeLearning.js) and the voice "fix it" diagnoser call through it. Key lives in .env as OPENROUTER_API_KEY; the balance is live from OpenRouter's credits endpoint.
Balance: —
OpenRouter — API Keys ↗ OpenRouter — Credits ↗🟣 Devin
Manage the personal access token (PAT) used by the voice "fix it" handoff (modules/voiceFeedback.js). No balance API — the card only reports whether the token is configured.
Token: —
Devin — API Tokens (PATs) ↗🟩 Ollama (self-hosted)
Local LLM used by the auto-router classifier and trivial-tier answers. No external balance — billed to workspaces at the DeepSeek rate as compute recovery, so the figure below is month-to-date recovered spend.
Host: —
This month: —
🟤 Brave Search (Authority Scout)
Web discovery for the Authority Scout citation resolver (port 3013): finds where an unresolved citation lives when it is not on TNA, and corroborates unreported cases across independent sources. Key lives in .env as BRAVE_SEARCH_API_KEY; the card only reports whether it is set.
Key: —
Service: —
Brave Search API — Dashboard ↗Authority Scout — fetch policy
Before the scout fetches any page a search result points at, it checks this
host list and (if enabled) the site's robots.txt. Locked
rows cannot be changed here — BAILII and the forums are refused
regardless of the robots toggle (BAILII's terms prohibit robots; forum posts
are unauthenticated user content). Everything else is pointer-only: URL,
snippet and hash are stored, never judgment text.
Loading…
Authority Scout — citation queue
Every citation Find Authorities could not match locally, plus every neighbouring case the scout spotted on a corroborating page (discovered). The scout stores pointers only — links and snippets — never judgment text. Resolve now re-runs the full TNA → legislation.gov.uk → Brave pipeline for one row.
Loading…
Token Pricing
Rates are USD per 1,000,000 tokens, stored internally as
integer micro-USD so sub-cent calls are never rounded away. Keyed on the
resolved model the provider actually served — not the
claude/gemini/deepseek alias the app
requests, because the fallback chain chooses the model.
Loading…
Add or update a rate
Currency
The live GBP/USD rate is fetched hourly from the European Central Bank (via Frankfurter API) and stored automatically. The buffer is subtracted from the live pair rate so the workspace gets slightly less credit per pound — protecting the platform against GBP strengthening. The effective rate is what every balance display and checkout uses. Internal accounting stays in micro-USD.
AI Engine
Sets the model pre-selected in every workspace's engine picker, and the fallback for
server-initiated calls that name no model. A workspace can still override it per request,
and a user's own saved choice is remembered in their browser — so changing this mainly
affects new users and anyone who has never picked a model.
There is deliberately no temperature control. Anthropic does not support
the temperature parameter on Claude 4.7+ models (it returns a 400), and Gemini and
DeepSeek are already pinned at 0.2 in the gateway — so the only thing such a control
could do is make output less deterministic.
Workspace Credits
Balances are integer micro-USD internally. Reserve debits immediately and the unused portion is refunded when the call settles, so a balance is deliberately pessimistic while work is in flight. A negative hard-stop floor lets a trusted firm run into arrears rather than have a hearing-prep session die mid-way.
Loading…
Credit Packs
What a workspace can buy. Price and credit are set independently
and on purpose — the credit is NOT derived from the display FX
rate, so editing gbp_per_usd never silently changes what a
pack gives. The suggested figure below is only a prompt; the stored value
is whatever you set.
Loading…
Purchases
Every checkout attempt, including abandoned and failed ones — a row is written before the buyer is sent to PayPal, so a workspace reporting "I paid and nothing happened" can always be traced. Revenue counts completed orders only; a refund moves an order out of that state.
Loading…
Observed Spend
Raw provider cost from real metered calls. No markup is applied yet — the per-workspace multiplier and credit ledger arrive in the next chunk.
Bailiff & Enforcement Agent Numbers
Phone numbers extracted from uploaded correspondence by the
bailiff-scan microservice. Hit count = how many
distinct documents the number appeared on. A number seen on 3+ documents
is treated as verified (shown with a badge). Numbers are classified by the
local Ollama (qwen2.5:3b) — false positives can be deleted.
Loading...
Email Accounts
Mailboxes on mta01 (mail.vindex.legal) — served by the mailctl
agent over the WireGuard net. A mailbox is a real inbox with its own
IMAP/SMTP login; an alias only forwards an address into an existing
mailbox.
Mailboxes
Loading…
Aliases (address → mailbox)
Loading…
System & Customer Logs
Workspace-attributed view over request_log. Metadata only — no
request/response bodies or AI content. Severity is derived:
critical = 5xx / network failure,
error = any failed request (incl. provider 4xx
like credit exhaustion — a failed analysis is a real customer impact),
info = success. Rows with no workspace are
platform jobs (e.g. case-law sync) shown as System / unattributed.
Click the Logs tab to load…
Server Logs
PM2 console output from the legal-analyser process — the tagged lines
([tts], [AI Gateway], [folders], etc.)
that the log-monitor microservice ingests into the
server_logs table. Auto-refreshes every 30s.
Click the Server Logs tab to load…
Usage analytics
Client console feed (browser_console_log) — anonymous
usage telemetry. "Installs" are pseudonymous browsers, not named
users; identified rows appear only where a user explicitly turned
diagnostics on.
Top endpoints ([fetch] lines)
Top errors
Daily health digest
Permanent rollup (daily_health) — one row per company
per completed day, kept after the raw console rows purge.
Anonymous pool = pseudonymous console rows with no
company attribution. Chat/request/rung columns come from the
permanent tables, so history backfills past the feed's start.
Loading…
Sessions
Newest activity first. Click a session to replay its journey below.
Loading…
Sentinel
Per-principal abuse detection — scores request behaviour
(velocity, endpoint sweeps, error ratios, failed logins, geo
anomalies) and writes sentinel_incidents. In
shadow mode nothing is blocked;
signals.wouldAction records what would have fired.
Blocks take effect via the in-app gatekeeper's 5s cache.
Click the Sentinel tab to load…
Banbo devices
Endpoint agents reporting over the WireGuard tunnel (ingest :3019, peer-only). Silent heartbeat + fresh WG handshake = dead agent alert; stale handshake = transport.
—
LAN devices (via router watch)
—
Device events
—
Incidents
—
Blocks
—
Config
—
ALSA Corrections
When a user tells ALSA an answer is wrong, the complaint is checked against the live interface before it reaches you. Corrections that are provable from the interface (ALSA named a tab or window that does not exist) are applied automatically and do not appear here. What is listed below is what the interface cannot settle on its own: needs review = both sides refer to real controls, so the disagreement is about the order or the choice of step; rejected = the correction itself refers to something that does not exist, so the user is probably mistaken. Approving applies the correction to everyone; rejecting discards it. Corrections change the answer only — never a prompt, never the workflow, never code.
Click the Corrections tab to load…
Recently decided
The last 50 decisions, including the ones applied automatically. Shown so a wrong call can be spotted and reversed — a decision here is one row, not a deployment.
Loading…
What ALSA understands
The phrasings ALSA recognises as ordinary conversation rather than as a question to answer — greetings, thanks, farewells, yes/no, stop, repeat. Before this list existed, a bare “morning” had no command verb in it, so the rules had nothing to match and ALSA replied “Are you talking to me?”. Adding a phrasing here fixes that kind of mistake without a code change.
Two things worth knowing before you add one. Only phrasings of four words or fewer are ever matched — that is deliberate, and it is what stops “good morning, I want to file an N244” being treated as nothing but a greeting. And the match is exact: the whole sentence must be the phrasing, not merely contain it. Longer speech skips this list entirely and goes to ALSA as a real question.
Click the Corrections tab to load…
What ALSA has taught herself
When ALSA refuses to act on something and the user immediately says it another way that does work, that pair is proof she was wrong the first time. The local model reads those pairs and decides which refusals were genuine instructions rather than the microphone mangling the words. The safe ones are added here automatically — nobody approves them first. That is a deliberate setting, and this list is where its mistakes become visible.
Each row shows the phrasing ALSA now accepts, what the user actually said that worked, and how confident the model was. A row that shows never used after a few days is probably noise and worth removing. Learning is capped per day so one bad run cannot flood the list.
Click the Corrections tab to load…
Support tickets
Tickets a user raised through ALSA — either by asking her directly or by saying yes to her offer after she kept failing to resolve the same problem. The context on each ticket is the captured evidence: the last chat turns including which rung answered (or failed), so you rarely need to ask what they were doing. Reply posts the answer back into their chat as an ALSA message — she told them she would get back to them, and this is her doing it.
Click the Support tab to load…
Where ALSA's answers came from
What do these categories mean?
Every question now climbs a ladder before anything is paid for. Case facts are read straight from the case record (a hearing date, an outstanding filing) — no model, no cost. Knowledge is the verified list below. Prior answer is the same question already answered for that folder, still valid because nothing in the folder has changed. Social is a greeting. Model is what still had to be paid for. The point of the list below is to move rows out of “model”.
Click the Knowledge tab to load…
Needs review
How this works — what the tags and buttons mean
Three different things collect here, and they do not carry the same weight. possible amendment is the serious one: the source page no longer contains the figure this row states, which is what happens when a rule is changed. disagreement means a paid model has just answered the same question with a different number from the one we hold — one of the two is wrong. needs verification is a fact mined from a paid answer; it is never served to anyone until it is approved here, because the reason this product exists is that models are confidently wrong about exactly these figures.
Approve starts serving the row with its citation from the next question asked. Reject keeps it, marked wrong, so the same claim is not re-proposed every time a model repeats it. Confirm means “I already know this value and it's still right” — it clears the flag without editing anything. Use Ask ALSA about this if you're not sure what a row means or what approving it will actually do.
Run history
Click to load past runs…
Click the Knowledge tab to load…
Learning queue
When a user asks a follow-up question that a local model judges to be about the SAME topic as something ALSA already answered from the list above, the follow-up's phrasing is proposed here — never applied automatically. A proposal can only ever add an extra way of asking an existing, already-verified answer; it can never change what ALSA says. Approve adds the phrasing to that fact so the next person asking it that way is answered for free. Reject discards it. Block does the same but also stops that exact phrasing being proposed again.
Click the Knowledge tab to load…
What ALSA knows
Verified facts, served with their citation and at no cost. Asked counts how often a row has actually answered a question — a row that never serves is dead weight, and a row that serves every day is why this table exists. Source is the state of the last automatic re-check against the citation; it runs weekly and it is deliberately not allowed to change a row on its own, because a court website reshuffling its own page must never silently stop ALSA answering.
Click the Knowledge tab to load…
Add a fact
A fact added here is verified immediately — you are the source. Give it the phrasings a user would actually say out loud: matching is on those phrasings, so a fact nobody asks for in those words will never be found. Put the number in Value on its own as well as in the answer — that is the field the weekly source check looks for, and a row with no number in it cannot be checked automatically.
Case findings — extract & cluster
What Extract and Cluster do, and why per-folder
Extract turns each document's critique prose into individual findings rows — deterministic, free, no AI call. Cluster then works out which findings from DIFFERENT engines on the SAME document describe the same issue, and whether those engines agree or contest it — this one DOES call the local model (Ollama), roughly 10-20s per comparison, so a folder with a lot of cross-engine overlap can take several minutes.
Multi-engine coverage is the ceiling on what Cluster can ever show for a folder: a document critiqued by only one engine has nothing to reconcile. Folders are sorted by coverage, highest first, so the ones worth running sit at the top. Nothing here is applied automatically across every folder — pick the ones you actually want checked.
Click the Knowledge tab to load…
Domain packs & linked knowledge
What a pack does, and what "linked knowledge" means
A pack is an area of law ALSA can recognise from a document's wording — the trigger terms below. When two or more of them appear, the pack's checklist and prompt guidance are added to the analysis automatically.
Linked knowledge is the verified facts from "What ALSA Knows" that are tagged to the pack. Before this existed, a fact was only used when a document quoted its exact citation — so a tenant who had not yet found the regulation never saw it. Now a linked, verified fact is sent with every case the pack recognises, for every tenant. verified rows are live; candidate rows are waiting in the Learning Queue and are NOT served until approved.
Click the Knowledge tab to load…