Session 150 Infrastructure And Vision Report
Documentation for Architecture
Session 150 — Infrastructure, Research & Vision Report
Date: February 27, 2026 Author: Claude (Session 150, Coding Agent) Scope: Self-hosted sandbox infrastructure decisions, cost analysis, vendor comparison, and Vitto "Jarvis" memory architecture analysis
PART 1: Infrastructure Research & Decisions
1.1 Why We're Self-Hosting
E2B Cloud has hard limits that block our product vision:
| E2B Cloud Limitation | Our Self-Hosted Reality |
|---|---|
| 1h sessions (free), 24h (pro) | Unlimited — VM lives until destroyed or server restarts |
| $150+/month at 10 users | $53/month flat, regardless of users |
| No custom Chrome extensions in VM | Pre-installed in rootfs |
| E2B holds user browsing data | Full data sovereignty — our hardware |
| Generic VM template | Custom image with our tools pre-configured |
| Per-session only (no persistence) | Persistent per-user VMs with snapshots |
Break-even: ~8-10 active users. After that, self-hosted saves money every month AND enables capabilities E2B cannot offer at any price.
1.2 What Was Built (Session 150)
32 new files, 1 modified file. All builds pass clean.
Sandbox Orchestrator NestJS App (APIs/sandbox-orchestrator/)
A NestJS API that manages Firecracker microVM lifecycle on bare-metal hardware. This is the "other end" of the SelfHostedProvider HTTP client that was built in Session 144.
| Service | What It Does |
|---|---|
firecracker.service.ts |
Starts/stops Firecracker VM processes via UNIX API socket. Configures boot-source, drives, machine-config, network-interfaces. Copies rootfs (sparse copy), generates per-session SSH keys. |
network.service.ts |
IP address pool (172.16.0.2-254, 253 addresses). Creates/destroys TAP devices per VM. Attaches to bridge. |
vm-executor.service.ts |
SSH-based xdotool/scrot commands inside VMs. Replicates every E2B SDK method: screenshot, click, type, key, scroll, exec. |
sandbox-manager.service.ts |
Lifecycle orchestration: create → boot → waitForReady → running → destroy. Maintains sandbox state map. |
sandbox.controller.ts |
11 REST endpoints matching SelfHostedProvider's HTTP contract exactly. |
cleanup.service.ts |
TTL-based VM reaping: 30min idle, 60min max. Detects dead Firecracker processes. |
api-key.guard.ts |
X-API-Key header validation with constant-time comparison (crypto.timingSafeEqual). |
vnc-proxy.service.ts |
WebSocket ↔ TCP proxy for live desktop streaming. |
metrics.service.ts |
Prometheus text format: active VMs, capacity, create/screenshot durations, IP pool, uptime. |
health.controller.ts |
GET /health for SelfHostedProvider connectivity verification. |
VM Rootfs Image (deployment/sandbox-orchestrator/)
| File | What It Does |
|---|---|
Dockerfile.rootfs |
Ubuntu 22.04 + XFCE4 + Chrome + xdotool + scrot + x11vnc + SSH + fonts. Build reproducibly with Docker. |
vm-init.sh |
PID 1 inside VM. Parses kernel boot args (IP, resolution, VNC password, SSH pubkey). Starts Xvfb → desktop → Chrome → VNC → SSH. |
vm-network.sh |
Configures VM networking from kernel boot arguments (static IP, gateway, DNS). |
build-rootfs.sh |
Docker → ext4 conversion: docker build → docker export → mkfs.ext4 → tar extract. |
Dockerfile.orchestrator |
Node.js Alpine + SSH client + iproute2 for the NestJS orchestrator. |
sandbox-orchestrator.service |
systemd unit for auto-restart. |
nginx.conf |
Reverse proxy with SSL, WebSocket upgrade for VNC, rate limiting. |
Server Scripts (tools/scripts/sandbox/)
| Script | What It Does |
|---|---|
provision-server.sh |
Full server setup: Firecracker v1.7.0, KVM, Node.js 20, nginx, SSL, firewall. |
setup-network.sh |
Bridge network (br-sandbox 172.16.0.1/24), NAT masquerade, iptables, persistence. |
deploy-orchestrator.sh |
Build NX app → rsync to server → restart systemd → health check. |
Enhanced Existing File
| File | Change |
|---|---|
self-hosted.provider.ts |
Added API key header (X-API-Key from SANDBOX_API_KEY env), 2-retry with exponential backoff (1s, 3s), 60s health monitoring (critical alert after 3 failures, no auto-downgrade), 45s screenshot timeout. |
E2B SDK Method Mapping
| E2B SDK Call | Our Firecracker Implementation | Orchestrator Endpoint |
|---|---|---|
E2BSandbox.create({ resolution }) |
Firecracker VM boot + Xvfb + Chrome | POST /sandboxes |
sandbox.screenshot('bytes') |
DISPLAY=:99 scrot via SSH |
POST /sandboxes/:id/screenshot |
sandbox.moveMouse(x, y) |
xdotool mousemove via SSH |
POST /sandboxes/:id/click (moveOnly) |
sandbox.leftClick/rightClick/middleClick |
xdotool click 1/3/2 via SSH |
POST /sandboxes/:id/click |
sandbox.doubleClick() |
xdotool click --repeat 2 via SSH |
POST /sandboxes/:id/click (doubleClick) |
sandbox.write(text) |
xdotool type via SSH |
POST /sandboxes/:id/type |
sandbox.press(key) |
xdotool key via SSH |
POST /sandboxes/:id/key |
sandbox.scroll(dir, amt) |
xdotool click btn 4/5 via SSH |
POST /sandboxes/:id/scroll |
sandbox.commands.run(cmd) |
SSH exec | POST /sandboxes/:id/exec |
sandbox.kill() |
Kill Firecracker process + cleanup | DELETE /sandboxes/:id |
sandbox.stream.getUrl() |
x11vnc → WebSocket proxy | GET /sandboxes/:id (streamUrl) |
1.3 VM Model: Per-User Persistent (Recommended) vs Per-Session vs Dual-Layer
History
- Session 139: Per-user (
Map<userId, UserSandbox>) — one VM per user - Session 140: Changed to per-session (
Map<sessionId, SessionSandbox>) to solve parallel task conflicts (two tasks fighting over same mouse/focus) - Session 150: Recommendation to evolve to per-user persistent with Firecracker snapshots for the Jarvis vision
Comparison
| Factor | Per-Session (Current) | Per-User Persistent (Recommended v1) | Dual-Layer (v2) |
|---|---|---|---|
| Chrome saves logins | No — fresh every time | Yes — profile persists across tasks | Yes |
| Session time limit | No (we own the infra) | No | No |
| Parallel tasks | Yes (isolated VMs) | No (sequential queue) | Yes (fork from snapshot) |
| RAM per user (active) | 2GB per task | 2GB per user | 2GB home + ~500MB per fork |
| RAM per user (idle) | 0 (destroyed) | 0 (snapshotted to disk) | 0 (snapshotted to disk) |
| Snapshot storage | None | ~500MB-1.5GB per user | Same + temp fork snapshots |
| Jarvis score | 2/10 | 8/10 | 10/10 |
| Dev effort (additional) | Done | +2-3 days | +5-7 days on top |
Firecracker Snapshot Performance
- VMM restore: ~4-10ms (per Marc Brooker / AWS)
- Full system with app warmup: ~300-500ms
- Snapshot file size: Only dirty pages stored, not full 2GB. Typical ~500MB-1.5GB.
- Memory sharing: Clones share unchanged pages (MAP_PRIVATE demand paging)
- This is how AWS Lambda achieves sub-100ms cold starts.
Recommendation
Start with Per-User Persistent (Model B) on AX42. Tasks queue sequentially on the Home Machine. Add ephemeral Task VM forking (Model C) when parallel execution demand is proven.
1.4 SSH Performance: ControlMaster
What It Does
Normal SSH: every command opens new TCP → TLS handshake → authenticate → execute → close (~50-100ms). ControlMaster: first command opens normally. Every subsequent command reuses the same TCP connection (~2-5ms).
Impact
| Metric | Without | With | Improvement |
|---|---|---|---|
| First command | 50-100ms | 50-100ms | 0% |
| Subsequent commands | 50-100ms each | 2-5ms each | ~95% |
| 20-step session total SSH overhead | ~1.5s | ~130ms | ~91% |
Cost & Effort
- Monetary cost: Zero
- Implementation: ~30 minutes — add 3 lines to SSH_BASE_ARGS in
vm-executor.service.ts - Risk: Near-zero. ControlMaster socket cleanup on VM destroy.
Recommendation
Implement immediately. Pure upside, no downside.
1.5 Managed Cloud vs Self-Hosted Bare Metal
Can We Use AWS or Google Cloud Instead?
Firecracker needs bare-metal access to /dev/kvm. Regular cloud VMs don't expose this.
| Provider | Configuration | RAM | Monthly Cost | KVM/Firecracker |
|---|---|---|---|---|
| Hetzner AX42 | Ryzen 7 PRO 8700GE | 64 GB | $53 | Native bare metal |
| Hetzner AX102 | Ryzen 9 7950X3D | 128 GB | $112 | Native bare metal |
| AWS i3.metal | Xeon, 36 vCPU | 488 GB | $3,644 | Native bare metal |
| AWS i3.metal (1yr reserved) | Same | 488 GB | ~$2,300 | Native bare metal |
| GCP N2 (nested virt) | 8 vCPU | 64 GB | ~$300-400 | Nested KVM (slower) |
| GCP sole-tenant | 8+ vCPU | 64+ GB | ~$500+ | Nested + 10% premium |
AWS i3.metal costs 69x more than Hetzner AX42 for capacity we won't use (488GB when we need 64GB). GCP nested virtualization adds latency and costs 6-8x more.
When Cloud Makes Sense
Only if you need sandbox servers in 10+ global regions simultaneously for latency. For US/EU users, Hetzner Ashburn (VA) and Falkenstein (DE) cover everything.
1.6 Hetzner vs Other Bare Metal Providers
| Provider | Model | CPU | RAM | Storage | Price/mo | Bandwidth | KVM | Locations |
|---|---|---|---|---|---|---|---|---|
| Hetzner EX44 | i5-13500 | 14c/20t | 64 GB | 2×512GB NVMe | €39 | 20 TB | Yes | DE, FI, US, SG |
| Hetzner AX42 | Ryzen 7 PRO 8700GE | 8c/16t | 64 GB | 2×512GB NVMe | €49 | 20 TB | Yes | DE, FI |
| Hetzner AX52 | Ryzen 7 7700 | 8c/16t | 64 GB | 2×1TB NVMe | €64 | 20 TB | Yes | DE, FI |
| Hetzner AX102 | Ryzen 9 7950X3D | 16c/32t | 128 GB | 2×1.92TB NVMe | €104 | 20 TB | Yes | DE, FI |
| OVH Advance-2 | EPYC 4584PX | 16c/32t | 64 GB | 2×960GB NVMe | $123 | Unlimited | Yes | US, EU, APAC |
| Contabo Ryzen 12 | Ryzen 9 7900 | 12c/24t | 64 GB | 1TB NVMe | €86 | Unlimited | Yes | DE, US, UK, AU, JP, SG |
Provider Assessment
Hetzner — Price leader. €39-49 for 64GB NVMe bare metal. Zero setup fees. Excellent docs and rescue system. Limited to 5 locations. 2026 price increases of 3-10% effective April 1.
OVH — 30+ locations worldwide. Unlimited bandwidth. Strong DDoS protection. 2-2.5x more expensive than Hetzner. Mixed support reputation since 2021 Strasbourg fire.
Contabo — 6 regions including Asia-Pacific. Unlimited bandwidth. Network quality noticeably worse than Hetzner/OVH. Slow support. VDS products may not expose KVM.
Hetzner Model Decision Tree
| Need | Pick | Why |
|---|---|---|
| Absolute cheapest | EX44 (€39) | Intel i5-13500, near-AX102 single-thread, no ECC |
| Best balance | AX42 (€49) | Ryzen 7 PRO, ECC RAM, modern, €10 more than EX44 |
| Most storage headroom | AX52 (€64) | 2×1TB NVMe, highest PassMark at 64GB |
| Scale-up | AX102 (€104) | 128GB RAM, enterprise NVMe, doubles capacity |
Note: AX42/AX52/AX102 had a motherboard defect in Q1-Q3 2024 production units. Hetzner is replacing affected boards. Orders placed Feb 2026+ get post-fix hardware. The EX44 (Intel) was unaffected.
Migration (AX42 → AX102)
Trivial. Run provision-server.sh on new server, rsync rootfs + snapshots, update DNS, cancel old server. ~30 minutes total, ~5 minutes downtime. Zero code changes needed.
1.7 Mac as Sandbox Server
Why Mac Doesn't Work for This
Firecracker does not run on macOS. It requires Linux KVM. Mac uses Apple's Hypervisor.framework (UTM/QEMU) — different API, different snapshot model, different networking. Using a Mac would require rewriting the entire orchestrator.
Mac Hosting Costs (For Reference)
| Provider | Model | RAM | Price/mo |
|---|---|---|---|
| My Remote Mac | M4 | 16GB | $75 |
| Macly.io | M4 | 16GB | $100 |
| Scaleway | M4 Pro | 64GB | €335 |
| MacStadium | M4 Pro | 64GB | $399 |
At $360-399/month for 64GB, a hosted Mac is 7-8x more expensive than Hetzner AX42 ($53) with no advantage for our use case.
When Mac Makes Sense (Future)
If Vitto needs to control macOS-specific apps (Xcode, Keynote, Final Cut) or automate iOS development workflows. That's a genuine future opportunity but not v1.
1.8 Final Infrastructure Decision
| Decision | Choice | Cost |
|---|---|---|
| Hardware | Hetzner AX42 (€49/mo) → AX102 (€104/mo) when scaling | €49/month |
| VM Model | Per-User Persistent with Firecracker snapshots | +2-3 days dev |
| SSH Optimization | ControlMaster (implement now) | 30 minutes dev |
| Year 1 total cost | ~€588 ($636) |
PART 2: Can Vitto Be "Jarvis"? — Honest Analysis
2.1 The Vision (Restated for Clarity)
Vitto is a 24/7 AI assistant that:
- Knows the user — preferences, history, work style, credentials
- Knows the space — projects, code, data, team members, goals
- Remembers everything — conversations from 6 months ago, that one time you changed the API key, the fact you prefer dark mode
- Acts in the real world — browses the web, logs into Gmail, files an LLC, deploys code
- Gets smarter over time — learns from outcomes, adapts to the user, shares wisdom across the platform
- Works 24/7 — not per-session, not per-conversation. Vitto is always "on"
Is This Possible?
Yes, with caveats. Let me be precise about what works, what's hard, and what's unsolved.
2.2 What We Already Have (Honestly Assessed)
After exploring the entire codebase, Vitto already has a surprisingly robust memory architecture:
The Three-Tier Memory System
TIER 1: HOT (In-Memory)
├── 50 most recent memories per user
├── Keyword matching, instant retrieval
└── 30-min TTL, evicted on overflow
TIER 2: WARM (MongoDB + Vector Search)
├── vitto-memories: vector-embedded (1536-dim, OpenAI text-embedding-3-small)
├── execution-traces: full task history (90-day TTL)
├── strategy-memories: what approach works best per task type
├── $vectorSearch with cosine similarity, threshold 0.7
└── Text search fallback when vectors unavailable
TIER 3: COLD (Platform Intelligence)
├── golden_decisions: cross-platform decision history
├── core_rules: 10+ distilled, always-apply rules
├── learned_patterns: task-specific patterns with success rates
└── Retrieved via API from backend-ai-api
What Gets Stored Today
| Event | What's Saved | Where |
|---|---|---|
| User says "remember I prefer TypeScript" | Explicit memory (confidence 1.0) | vitto-memories |
| User completes a chat message | LLM-extracted facts, preferences, skills | vitto-memories |
| Vitto completes a task | Execution trace + outcome + lessons learned | execution-traces + vitto-memories |
| Task succeeds/fails | Strategy memory updated (success rate recalculated) | strategy-memories |
| Pattern observed 3+ times with 80% success | Promoted to core rule | core_rules |
What Gets Injected into Every LLM Call
- User identity (name, email, roles, subscription) — ~100 tokens
- User memories (preferences, skills, facts) — ~500 tokens
- Core rules (always-apply patterns) — ~500 tokens
- Relevant patterns (task-specific) — ~300 tokens
- Similar past decisions — ~300 tokens
- Knowledge distribution — variable
Total context overhead: ~2,000-3,000 tokens per call.
Honest Grade: B+
The foundation is solid. Vector search for semantic recall, tiered storage, automatic memory extraction, pattern promotion. But there are real gaps.
2.3 The Hard Problems (Where Jarvis Breaks)
Problem 1: Context Window Is Finite
The fundamental constraint. Claude Opus has a 200K token context window. That sounds large, but:
- A 30-message conversation history: ~5,000-10,000 tokens
- System prompt + context injection: ~3,000 tokens
- User's current request + response: ~2,000 tokens
- Remaining for "memory": ~185,000 tokens
185K tokens is a lot — roughly 300 pages of text. But a user who's worked with Vitto daily for 6 months has generated:
- ~1,000 conversations
- ~500 task executions
- ~5,000 memories
- ~50,000 lines of context
You cannot fit all of this into one prompt. This is the core challenge everyone in the industry faces.
What Competitors Do (And Their Limits)
| Approach | Who Uses It | Limit |
|---|---|---|
| RAG (retrieve relevant chunks) | Everyone (OpenAI, Claude, Gemini) | Only finds what you query for. Misses tangential relevance. |
| MemGPT/Letta (OS-style memory management) | Letta | Agent manages its own memory via tools. Adds latency. Self-editing can corrupt memories. |
| Knowledge graphs (entities + relationships) | Cognee, Google | Structured, queryable. But building/maintaining the graph is expensive. |
| Conversation summarization | ChatGPT, Claude | Lossy — nuance is lost. "You mentioned preferring TypeScript" but not "you mentioned it in the context of migrating from Java." |
| Full context window stuffing | Claude 200K, Gemini 1M | Works for single sessions. Doesn't scale across months of history. |
None of these fully solve the problem. They all trade off between recall accuracy and token efficiency.
Problem 2: Semantic Search Misses Tangential Relevance
Vector search is great for "find memories about TypeScript preferences." It's bad for "I'm building an e-commerce checkout — what did I say 3 months ago about payment processing?"
The second query requires understanding that "checkout" relates to "payment processing" which relates to a conversation about Stripe where you mentioned preferring their newer API. The semantic connection is 3 hops deep. Current vector search catches maybe 1 hop.
Problem 3: Memory Staleness
Vitto remembers you prefer React. Three months later, you switch to Svelte. The old "prefers React" memory is still in the database with high importance. Unless Vitto explicitly detects the contradiction and updates the memory, it will keep injecting stale context.
Our current system has no contradiction detection. Importance never decays. Old memories don't get challenged.
Problem 4: Cross-Space Context Leaking
If a user works on Space A (medical app) and Space B (gaming app), Vitto's memories are partially space-scoped (spaceId field) but many memories are user-scoped. Medical terminology could leak into gaming recommendations.
Problem 5: The "Always On" Illusion
LLMs are stateless. Every API call starts from zero. The "always on" feeling is an illusion built from:
- Injecting memories into the system prompt (makes it seem like Vitto "remembers")
- Resuming conversation history (makes it feel continuous)
- Proactive actions (Vitto checks your inbox even when you're not asking)
The illusion breaks when the context window can't fit everything that matters.
2.4 What Would Actually Make Vitto Groundbreaking
Here's where I'll be inventive. Most competitors do RAG + conversation history. Here's what could genuinely differentiate Vitto:
Idea 1: The "Mind Map" — Structured Memory Graph (Not Just Vectors)
Instead of flat vector embeddings, build a knowledge graph per user where:
User → owns → Space "MyApp"
│ ├── uses → Tech: Angular, NestJS, PostgreSQL
│ ├── deployed_on → Railway
│ └── has_feature → Auth (uses → JWT, preferred → Passport.js)
│
├── prefers → TypeScript over JavaScript
├── dislikes → CSS-in-JS
├── works_at → peak hours 9am-1pm
│
└── did_task → "Set up Stripe checkout" (3 months ago)
├── used → Stripe API v2023-10-16
├── chose → embedded checkout over hosted
└── lesson → "Webhooks need idempotency keys"
Why this is better than vectors alone: When Vitto is asked to "add payment processing to Space X," it can traverse the graph:
- Look up Space X → find tech stack (Angular + NestJS)
- Find related past task → "Set up Stripe checkout"
- Pull the lesson → "Webhooks need idempotency keys"
- Know the user's preference → embedded checkout over hosted
This is 3-hop reasoning that vector search cannot do. It requires structured relationships, not just semantic similarity.
Implementation: Use MongoDB's $graphLookup (already available in our stack) or a dedicated graph layer. Nodes are memories, edges are typed relationships. Build the graph incrementally as memories are created.
Estimated effort: 2-3 weeks for a basic graph with entity extraction + relationship building. Can use Claude itself to extract entities and relationships from conversations.
Idea 2: "Cognitive Load Budgeting" — Smart Context Assembly
Instead of stuffing everything into the context window, Vitto should plan what to remember for each request:
User asks: "Help me add Stripe to my checkout"
Step 1: CLASSIFY the request → payment integration, web development
Step 2: BUDGET the context → 3,000 tokens for memories, 2,000 for patterns
Step 3: RETRIEVE strategically:
- User's payment preferences (200 tokens)
- Space tech stack (100 tokens)
- Past Stripe task summary (300 tokens)
- Stripe patterns from platform knowledge (500 tokens)
- Recent conversation context (1,000 tokens)
- Core rules (500 tokens)
- SKIP: user's CSS preferences (irrelevant)
- SKIP: memories about their gaming project (wrong space)
Step 4: ASSEMBLE context with priority ordering (most relevant first)
Why this matters: The key insight from LLM research is that models show a U-shaped performance curve — they attend better to information at the beginning and end of the context, with a "lost in the middle" effect. Smart assembly means putting the most critical memories first.
We partially do this today (tiered recall, importance scoring). The gap is there's no request-aware budgeting — we inject the same user context regardless of whether the user is asking about TypeScript or asking about their weekend.
Idea 3: "Memory Metabolism" — Active Forgetting and Consolidation
Human brains don't store every detail — they consolidate, generalize, and forget. Vitto should do the same:
DAY 1: "User said they prefer tabs over spaces" → Store as memory (importance 0.7)
DAY 7: Memory consolidation runs. This memory accessed 0 times. → Decay importance to 0.5
DAY 30: Still not accessed. → Decay to 0.3
DAY 90: → Archive (remove from warm tier, keep in cold)
vs.
DAY 1: "User's API key for Stripe is sk_live_xxx" → Store (importance 0.9)
DAY 7: Accessed 3 times during Stripe integration → Boost to 0.95
DAY 30: Accessed 1 more time → Stays 0.95
DAY 90: Not accessed in 60 days → Decay to 0.8 (still high — credentials don't expire)
We have consolidation (7-day conversation merging in MindService.runMemoryConsolidation()). But we don't have importance decay. Every memory stays at its initial importance forever. This means after 6 months, the hot cache is dominated by old high-importance memories that haven't been relevant in months.
Fix: Add an accessedAt timestamp, decay formula: effectiveImportance = baseImportance * (0.95 ^ daysSinceLastAccess). Simple exponential decay. Keeps frequently-accessed memories alive, lets unused ones fade.
Idea 4: "Contextual Persona" — Pre-Computed User Summaries
Instead of assembling context from raw memories on every call, maintain a living document per user that summarizes who they are:
USER BRIEF (auto-generated, refreshed daily)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Name: Paco
Active spaces: MyApp (Angular/NestJS), GameProject (Unity)
Working style: Morning person, peak 9am-1pm. Prefers detailed explanations.
Tech preferences: TypeScript, Angular, NestJS, PostgreSQL. Dislikes CSS-in-JS.
Recent focus: Stripe payment integration (past 2 weeks)
Open tasks: 3 pending code reviews, 1 deployment blocked on env vars
Credentials on file: Gmail, GitHub, Stripe (all stored in VM profile)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
This is ~200 tokens and gives Vitto 80% of the "I know you" feeling. It's regenerated daily (or on significant events) by summarizing the full memory store. The LLM sees this brief + the most relevant specific memories, not a dump of 500 memories.
No one is doing this well. ChatGPT has "Memory" but it's just a flat list of facts. Letta/MemGPT self-edits a "core memory" block but it's limited and can corrupt. A properly maintained User Brief that's regenerated from the full memory graph is more reliable and more comprehensive.
Idea 5: The VM as Memory Extension
This is the truly unique angle that no competitor has:
Vitto's persistent VM IS a form of memory. Chrome cookies are memory. Bookmarks are memory. Browsing history is memory. Saved passwords are memory.
When Vitto logs into Gmail on the user's VM, that login session persists. Next time Vitto needs to check email, there's no "remember the password" step — the browser remembers. This is physical-world memory that exists outside the LLM's context window entirely.
Traditional AI assistant:
"Check my Gmail" → Look up credentials → Log in → Navigate → Read → Log out
Vitto with persistent VM:
"Check my Gmail" → Open Chrome tab → Already logged in → Read
Time: 30 seconds vs 5 seconds
User friction: Zero vs "enter your 2FA code"
This is what makes the Hetzner + Firecracker + per-user persistent VM decision so important. It's not just about cost savings over E2B. It's about making the VM an extension of Vitto's memory — a physical, browser-based memory layer that doesn't consume context window tokens.
2.5 What's Actually Fine (Don't Over-Engineer)
Being honest about what doesn't need fixing:
Vector search for recall is good enough for 90% of queries. Don't build a full knowledge graph before validating that users actually have multi-hop recall needs.
2,000-3,000 tokens of context overhead is acceptable. Claude's 200K window has plenty of room. Don't obsess over token optimization until you're genuinely hitting limits.
The Intelligence Pyramid (core rules → patterns → decisions) is a solid architecture. Pattern promotion based on success rate is a genuinely good idea that most competitors don't have.
Memory extraction from conversations works. The regex + LLM extraction pipeline catches explicit memories reliably. It misses some implicit ones, but that's acceptable.
The tiered recall (hot → warm → cold) with fallback is well-designed. The architecture handles the "I don't remember but let me check" case gracefully.
2.6 Honest Risk Assessment
| Risk | Severity | Likelihood | Mitigation |
|---|---|---|---|
| Context window overflow (too many memories) | High | Medium (at scale) | Cognitive load budgeting + user brief |
| Stale memories polluting context | Medium | High (guaranteed over time) | Importance decay + contradiction detection |
| Vector search misses tangential relevance | Medium | Medium | Knowledge graph for multi-hop reasoning |
| Cross-space context leaking | Low | Medium | Strict spaceId filtering (already exists) |
| Memory corruption (LLM self-edits incorrectly) | High | Low (we don't self-edit) | Keep human-authored memories immutable |
| Chrome profile security (persistent logins) | High | Low (Firecracker isolation) | At-rest encryption, jailer, ephemeral SSH keys |
| Users expect Vitto to remember EVERYTHING | Medium | High | Set expectations: "I remember what matters" not "I remember everything" |
2.7 Recommended Roadmap
Phase 1: Foundation (Now → 2 weeks)
- Deploy Hetzner AX42 with per-user persistent VMs
- Implement SSH ControlMaster
- Implement importance decay on memories
- Build User Brief (auto-generated daily summary per user)
Phase 2: Intelligence (2-4 weeks)
- Cognitive load budgeting (request-aware context assembly)
- Contradiction detection (new memory conflicts with old → prompt user)
- Proactive memory refresh (re-embed old memories with updated context)
Phase 3: Differentiation (1-2 months)
- Knowledge graph per user (entity extraction + relationship building)
- Multi-hop recall via graph traversal
- VM-as-memory integration (Chrome state as queryable context)
- Cross-space intelligence sharing (with user consent)
Phase 4: Scale (3+ months)
- Dual-layer VMs (Home + ephemeral task forks)
- Multi-server orchestration
- Team memory sharing (shared knowledge graph per space)
- Proactive task suggestions based on patterns
2.8 The Bottom Line
Can Vitto be Jarvis? Yes — with the right memory architecture.
The LLM is not the bottleneck. Claude is smart enough. The bottleneck is what context you give it. The difference between a mediocre AI assistant and Jarvis is not the model — it's the memory system that decides what the model knows about you when it starts thinking.
What we have today is a B+. The gaps are:
- No importance decay (memories get stale)
- No request-aware context budgeting (same context injected regardless of task)
- No multi-hop reasoning (vector search is 1-hop only)
- No User Brief (no pre-computed "who is this person" summary)
- No VM-as-memory integration (Chrome state isn't queryable)
Fix those five things, and you have something no competitor offers: an AI that genuinely knows you, remembers your work, has a physical machine ready to act, and gets smarter every day.
The persistent VM on Hetzner is the missing physical layer. MCP + MongoDB + vector search is the digital layer. The knowledge graph would be the reasoning layer. Together, they give Vitto three forms of memory that reinforce each other — and that's architecturally unique in the market.
Sources
- Firecracker Snapshot Documentation
- Marc Brooker on Lambda SnapStart
- Seven Years of Firecracker
- SSH 10x Speedup with ControlMaster
- SSH Connection Multiplexing Guide
- Hetzner AX Server Matrix
- Hetzner AX102
- Hetzner 2026 Price Adjustments
- Achromatic Hetzner Comparison with Benchmarks
- AX42/52/102 Motherboard Issue
- AWS i3.metal Pricing
- GCP Nested Virtualization
- GCP Sole-Tenant Pricing
- OVH Dedicated Server Prices
- Contabo Dedicated Servers
- Scaleway Apple Silicon Pricing
- MacStadium Pricing
- Letta/MemGPT Agent Memory Architecture
- Design Patterns for Long-Term Memory in LLM Architectures
- LLM Context Window Management 2026
- MCP Knowledge Graph Memory Server
- Agent-Recall: SQLite Knowledge Graph for Claude
- Cognee: MCP + LLM Memory
- Top 10 AI Memory Products 2026