Server Memory
Know what's actually running on each of your servers — without the backend ever seeing what's actually running.
What is Server Memory?
Every time Servonaut probes a server, it writes a small structured record of what it found — kernel version, installed runtimes, listening ports, running services, web stack, databases, containers, disk usage. That record is your memory of that server. It's what powers the at-a-glance snapshot on each server's dashboard in the TUI, the context the AI chat uses to understand "how this box is configured", and the drift timeline on your account dashboard.
On Free, memory stays on your machine. Servonaut stores it
under ~/.servonaut/memory/ and that's it. Nothing ever reaches
our servers.
On Solo and Teams, you can sync memory to
servonaut.dev so your fleet view, drift alerts, team sharing,
and weekly digests all work across machines. We never see the
plaintext.
What if a Free user tries to sync?
The CLI sends the request, the server checks your plan, and the sync
endpoint returns 403 Forbidden with
{"error":{"code":"forbidden_entitlement","message":"Your plan does not include this feature."}}.
The CLI surfaces that as an "upgrade to Solo or Teams to enable sync"
notice and keeps your local memory intact — nothing is lost, nothing is
uploaded, the local probe store keeps working exactly as before.
Using it in the TUI
The TUI (launched with plain servonaut) is the easiest way to
build and browse memory:
- First connect — the first time you open a server that
has no memory yet, a banner offers to build it: press
y to probe now or n to dismiss. (If you dismissed
it one time too many,
servonaut memory reset-promptsbrings the banner back.) - At a glance — clicking any instance opens its Server Actions dashboard, whose detail pane shows the memory snapshot: OS, disk, web stack, databases, runtimes, containers.
- Full view — press m on an instance (from the instance list or its Server Actions dashboard) to open that server's Memory screen: every module, observed vs declared values, and how stale each one is. For a fleet-wide overview across every server, open Fleet Memory (🧠) from the sidebar's Tools section — see Keeping memory current automatically.
Inside a server's Memory screen:
- r — refresh all modules for the server
- m — refresh just the module under the cursor
- p — pin a declared value (the summary then shows observed and declared when they differ)
- c — clear a module (with confirmation)
- a — open the server's annotations in
$EDITOR - e — export the memory summary to Markdown
- S — sync this server's memory to your account now
- A — generate an AI summary of this server
Hotkeys are case-sensitive: lowercase a annotates, capital A runs an AI summary.
The built-in AI chat panel (F2) automatically injects the active server's memory into the conversation, with a staleness banner so you know how fresh the snapshot is.
Enabling sync from the TUI (Solo & Teams)
Open Memory Sync in the sidebar's Tools section. It's the single hub for the whole sync lifecycle: first-time enrolment (you set your memory passphrase here), unlocking after a restart, and checking sync status. Sync now pushes every cached server's memory modules to your account as encrypted envelopes; drift detection and cross-device history come with it.
Per-feature sync settings — digest cadence, live push updates, and AI consent — live at the bottom of the Settings screen.
Keeping memory current automatically
Fresh memory is what makes the fleet view, drift alerts, and weekly digests meaningful — a snapshot from three weeks ago tells you very little. Two background workers keep it current so you don't have to remember to run anything, and both keep going after you leave the panel that started them.
Background fleet auto-scan re-probes your servers on a
schedule. Open Fleet Memory (🧠) from the sidebar for the
fleet-wide view and press a to toggle it, or use the
Background fleet auto-scan switch in
Settings → Memory with its Auto-scan interval
(seconds) field — default 86400 (24 hours),
minimum 60. By default it only re-probes servers whose memory is
stale or missing, so a daily cycle keeps everything current without hammering
boxes that haven't changed. While it's on, the Fleet Memory screen shows a
live status line — “● Auto-scan on · next in ~Xh” — that reads
“○ Auto-scan off” when disabled.
The same Fleet Memory screen also probes on demand: s runs Scan All and f refreshes only the stale servers. Scan All runs in the background too — “Scanning N instance(s) in the background — you can leave this panel and it will finish.” Re-open the screen mid-run and you'll see “Fleet scan in progress…”; when it finishes a banner reports “Fleet scan complete — X succeeded, Y failed (total)”.
Auto-sync is the other half. With sync unlocked, the Auto-sync memory to cloud switch in Settings → Memory Sync drains the encrypted-envelope queue in the background, so the server-side copy stays current between manual Sync now runs — this is what keeps your weekly fleet digests working off fresh data. Auto-sync is a Solo & Teams feature: it needs an active paid plan and an enrolled device. The preference is stored on your account (not just locally), so it follows you across every machine you sign in from.
Staying unlocked across restarts
Memory Sync is protected by your passphrase, and the decrypted key lives only in memory — so historically every launch meant typing it again. You can now opt to have Servonaut remember it on a trusted device.
When you unlock or enrol on a machine with a supported OS keychain, the modal offers a “Remember on this device (auto-unlock)” switch. Turn it on and Servonaut stores the passphrase in your operating system's keychain and silently re-unlocks Memory Sync on the next launch — no prompt. The private key is still wrapped locally; the server never sees it. The Memory Sync screen (☁) shows the current state in an auto-unlock status row: “on (re-prompt in Nd)”, “on (expired — will re-prompt)”, or “off”.
Remembering lasts 30 days, after which silent unlock is refused and you're prompted again — but not at boot. The prompt is deferred until the next time you actually open a memory section, so startup is never blocked by a modal. To clear a remembered passphrase, use “Forget on this device” on the Memory Sync screen; you'll get “Passphrase forgotten — you will be prompted on next launch.” A successful unlock shows “Memory Sync unlocked.”; dismiss the prompt and it's “Memory Sync locked — open Memory Sync to unlock.”
The “Remember on this device” option only appears when a usable OS keychain backend is present. On machines without one, Memory Sync still unlocks the same way — you'll just enter your passphrase each session.
Automating with the CLI
Everything above is scriptable for cron jobs, CI runners, and headless
boxes via servonaut memory:
# Probe one instance, or the whole fleet
servonaut memory build web-prod-1
servonaut memory build --all
# Re-probe regardless of freshness
servonaut memory refresh web-prod-1 --modules services runtimes
# Read what's stored: bounded summary (default), full Markdown,
# raw JSON, one module, or only the stale modules
servonaut memory show web-prod-1 --format json
servonaut memory show web-prod-1 --module databases
servonaut memory show web-prod-1 --stale
# Declare a value the probe can't know
servonaut memory pin web-prod-1 services.nightly_job "billing export, 03:00"
# Notes (opens $EDITOR), Markdown export, deletion
servonaut memory annotate web-prod-1
servonaut memory export web-prod-1 --out ./web-prod-1.md
servonaut memory clear web-prod-1 --all
--json on build gives machine-readable output, and
the memory command tree has a documented exit-code table, so
scripts can branch on outcomes instead of parsing text. build --all
probes your whole fleet while throttling concurrent SSH connections.
Ctrl+C cancels any running command cleanly with exit code 130 — never a
traceback.
For AI agents
Server memory is designed to be the first thing an agent reads before it
touches a box. The MCP server (servonaut --mcp) exposes:
get_server_memory— fetch the snapshot in summary, Markdown, or full form. Passformat='context_block'to get an envelope shaped for dropping straight into model context — the same shape Servonaut's own chat client uses.list_server_memories— see which servers have memory and how fresh it is.build_server_memory/refresh_server_memory— create or update a snapshot on demand.remember_server_finding/recall_server_findings— persist and recall agent discoveries (see below).
Injected memory is explicitly framed as untrusted reference data in agent prompts: it can contain text emitted by the machine or written by other operators, so agents are instructed never to treat its contents as instructions. See the MCP Server docs for the full tool list and guard levels.
Zero-knowledge in plain English
Servonaut encrypts each module (os, runtimes,
services, etc.) locally on your machine, with a key derived
from your memory passphrase using Argon2id. Only the ciphertext
plus a tiny allow-listed metadata surface (server display name, provider,
probe timestamp, hash of the ciphertext, a handful of scalar counters)
reaches us. The only thing the backend ever computes over your data is a
SHA-256 hash of the ciphertext — it never holds a key that could decrypt
the contents.
When you look at a server on the account dashboard, the decryption happens in your browser: your passphrase-derived key is computed locally, your private key is unwrapped locally, and neither is ever cached or sent to us. The backend streams you opaque bytes and your browser turns them into readable text.
We also double-wrap your keypair on our side: the encrypted private-key blob you upload for device recovery is wrapped a second time — AES-256-GCM under a key held only by the application, never stored alongside the data. A database-only leak (backup, SQL injection in an unrelated feature) is useless — the attacker still needs both your passphrase and access to the running application to decrypt anything.
What the backend can read
| Field | Visible to us? |
|---|---|
| Your server's display name — whatever string you typed (e.g. "web-prod-1" or "web-prod-1.example.com") | Yes — it's the text you entered |
| Which cloud provider (aws / ovh / gcp / azure / custom) | Yes |
| Probe timestamp | Yes |
| Hash of the ciphertext (for drift detection) | Yes |
| Scalar counts (disk %, port count, service count) | Yes — for anomaly rules |
| Hostnames, IPs, process lists, config file contents inside the probe payload | Never |
| Your annotations, notes, and agent findings | Never |
| Command output | Never |
A note on display names: the display name field is plain
text that you choose. If you name a server web-prod-1.example.com
or 10.0.0.4-app, that exact string is what we store and show
in your account dashboard. If you want hostnames and IPs to stay off our
servers entirely, name your servers generically (web-prod-1,
db-eu-2) — the probe payload itself is encrypted regardless.
Drift detection works purely off the ciphertext hash — if the encrypted bytes for (server, module) change between two probes, a drift event lands in your inbox. Servonaut (or your browser) fetches both versions and shows you the actual diff locally; the digest cadence is configurable in the TUI's Settings screen. Authored content — annotations and agent findings (below) — is exempt: an edit to a note is an edit, not drift, so it never raises an alert.
Annotations & agent findings
Not everything worth remembering about a server comes out of a probe. Two authored module types ride the same encrypted sync as probed state:
- Annotations — notes you write about a server by hand
("this box runs the nightly billing job — don't reboot before 3am").
Write them with a on the TUI's memory screen or
servonaut memory annotate <instance>; they appear verbatim in the memory summary. - Findings — discoveries an AI agent persists during a session: a misconfigured cron, a hidden dependency, a root cause a fresh probe wouldn't show. The next agent that opens the box inherits them instead of re-discovering from scratch.
Both are end-to-end encrypted like every other module — we store ciphertext and never see the contents. With sync enabled, annotations and findings follow you across machines and (on Teams) across your team, so tribal knowledge written on one device is available everywhere; transient sync conflicts retry quietly. Because authored content is written rather than probed, drift and anomaly detection skip it entirely. On the Teams plan, findings are shareable per server through the same grants as the rest of memory — share all modules, or scope a grant down to findings only.
Agents read and write findings through the
Server Memory MCP tools
(remember_server_finding / recall_server_findings).
Recalled findings are always labelled as agent-authored, unverified
reference material — agents are instructed to treat them as leads to
re-verify, never as instructions.
Team sharing Teams plan
On the Teams plan, you can explicitly share a server's memory with your team. When you do, Servonaut generates a one-time key per envelope and wraps that key once per eligible team member using their public key (X25519 sealed boxes). Only those members can decrypt. We never hold a team-wide key.
Soft-revoking a share hides it from the dashboard but keeps wraps around so
you can undo. Purging deletes the wraps — downstream team members get a
404 access_revoked on next read.
AI summaries — the one place plaintext leaves your browser Teams plan
On the Teams plan, you can optionally ask the backend to run a one-off AI summary of a server. This is the only path where decrypted bytes cross to our side, and even then only for up to 60 seconds. Solo and Free plans don't include this hosted summary path — they use client-side mode (see below) if they want AI on a memory snapshot.
Default: off. You explicitly enable it per server, per
modules you pick, and you acknowledge that the AI provider (displayed by
name in the consent dialog) will see the prompt for the duration of its
retention window. The plaintext is scrubbed on the way out —
IPv4/IPv6 addresses, emails, URL hosts, .local names, and
cloud-default internal DNS names are replaced with placeholders before the
prompt is sent to the AI provider. The AI-consent setting also lives in the
TUI's Settings screen, so you can review or withdraw it any time.
If that trade-off isn't acceptable — or you're on Free or Solo — pick client-side mode: Servonaut calls your own LLM with your own API key, and our backend never sees the plaintext at all.
Compliance export Teams plan
Teams-plan users can export a signed .tar.gz covering any
window — metadata + encrypted envelopes + chain of custody + our Ed25519
signature. Auditors can fetch our public signing key from
/api/v1/memory/export-signing-key without credentials and
verify the manifest hasn't been tampered with.
Plan matrix at a glance
| Capability | Free | Solo | Teams |
|---|---|---|---|
| Local memory (probes + diff in TUI/CLI) | Yes | Yes | Yes |
| Sync to backend (encrypted) | No | Yes | Yes |
| Drift alerts & weekly digest | No | Yes | Yes |
| Team sharing | No | No | Yes |
| Hosted AI summary (server-side, scrubbed) | No | No | Yes |
| Client-side AI summary (your own key) | Yes | Yes | Yes |
| Compliance export (signed bundle) | No | No | Yes |
Retention
- Free: no backend storage — your local files only.
- Solo & Teams: the backend keeps a rolling snapshot history per server/module; the exact window depends on your plan and is shown on your account's billing page.
- We always keep the latest snapshot per server/module so the fleet view works even if you go on holiday.
Turning it off
Per-server: in ~/.servonaut/config.json, put
the override under memory.per_server_overrides, keyed by
server id:
{
"memory": {
"enabled": true,
"per_server_overrides": {
"srv_abc123": { "memory_disabled": true }
}
}
}
Servonaut will stop probing that box and the backend will purge any stored
envelopes on the next sync. You can also toggle this from the account
dashboard. To clear what's already stored locally, use c on the
TUI's memory screen or servonaut memory clear <instance> --all.
Account-wide: set memory.enabled = false in
~/.servonaut/config.json. Nothing syncs. You can still use
every other Servonaut feature.
More
- Technical threat model + envelope shape: see the API reference.
- Agent tool list, guard levels, and the remote relay: see the MCP Server docs.