144 Work Report
Documentation for Sessions
Session 144 — Work Summary (February 26, 2026)
What Was Done
Session 144 closed 4 "gaps" from the Vitto Super-Agent roadmap (Gaps 9-12). Here's what each one means in plain English.
Gap 12 — A2A Protocol Tests (DONE)
What is A2A? Google's Agent-to-Agent protocol — a standard way for AI agents to discover each other and send tasks. We already had a working A2A implementation in backend-vitto-api. What was missing: tests.
What was built: 5 test files covering every public method:
- Discovery (agent card shape, required fields)
- Task lifecycle (submit -> status -> completion)
- Error handling (missing tasks, cancel flow, DB failures)
- Status mapping (all 9 Vitto->A2A status translations)
- SSE events (event shape, stream closure)
Location: APIs/backend-vitto-api/src/app/a2a/__tests__/
Status: Complete. Zero production code changed — tests only.
Gap 10 — Sandbox Provider Abstraction (DONE)
The problem: Our Computer Use system (where an AI controls a browser/desktop) was hardcoded to use E2B Cloud. If we wanted to use our own servers instead, we'd have to rewrite the entire loop.
What was built: A Strategy pattern that lets us swap sandbox providers without touching the core logic.
ComputerUseLoopService
-> SandboxProviderFactory (picks the right one automatically)
|-- E2BCloudProvider <- wraps existing E2B Desktop SDK
|-- SelfHostedProvider <- HTTP client for our future server
|-- PlaywrightProvider <- local browser fallback
How it picks a provider (env vars):
- If
SANDBOX_SERVER_URLis set -> SelfHostedProvider - If
E2B_API_KEYis set -> E2BCloudProvider (this is what we use today) - Neither -> PlaywrightProvider (free, local, limited)
What changed in the codebase:
- New
sandbox/directory with 6 files (interface, 3 providers, factory, barrel export) computer-use-loop.service.tsno longer importsE2BDesktopServicedirectly- All
e2bSandboxvariable names renamed tosandboxHandle
Location: APIs/backend-ai-api/src/app/infrastructure/services/sandbox/
Status: Complete. E2B Cloud works exactly as before. Self-hosted provider is scaffolded (HTTP client code exists, but there's no server to connect to yet — see Gaps section below).
Gap 11 — Observability Dashboard (DONE)
The problem: We had no unified view of system health. Each backend had its own /health endpoint, but nothing aggregated them or tracked LLM spending.
What was built:
Backend (3 new files)
LLM Cost Tracker (
llm-cost-tracker.service.ts)- Records every LLM API call: model, tokens in/out, cost, user
- Rolling 24-hour window (in-memory, no database overhead)
- Model-specific pricing (Claude Opus 4.6: $15/$75 per 1M tokens, etc.)
- Called automatically after every Anthropic API call in Computer Use
Observatory Service (
observatory.service.ts)- Checks health of all 4 backends every 30 seconds (cached)
- Aggregates into a single dashboard JSON
- Also generates Prometheus-format text metrics
Observatory Controller (
observatory.controller.ts)GET /infrastructure/observatory/dashboard— full dashboard JSONGET /infrastructure/observatory/metrics— Prometheus text formatGET /infrastructure/observatory/llm-spend— 24h token summaryGET /infrastructure/observatory/llm-daily— daily cost history
Frontend (4 new files)
- Observatory Data Service — Angular service that polls the dashboard endpoint
- Observatory Dashboard Component — Shows backend health cards, LLM spend breakdown, agent/system metrics
- Observatory Page updated with tab system: "Agent Monitor" (existing) + "System Dashboard" (new)
Location:
- Backend:
APIs/backend-ai-api/src/app/infrastructure/ - Frontend:
libs/libs-ai/gograb-ai-lib/src/lib/components/observatory-dashboard/ - Page:
apps/gograb-ai/src/app/pages/observatory/
Status: Complete. Navigate to /observatory and click "System Dashboard" tab.
Gap 9 — Vitto Mobile App (SCAFFOLDED)
What is it? A native mobile wrapper around our existing Angular app, exactly like vitto-desktop wraps it with Tauri — but using Capacitor for iOS/Android instead.
What exists today
| Item | Status |
|---|---|
apps/vitto-mobile/capacitor.config.ts |
Created |
apps/vitto-mobile/project.json (NX targets) |
Created |
apps/vitto-mobile/package.json (metadata) |
Created |
CapacitorBridgeService (Angular service) |
Created |
| Auth guard mobile detection | Added |
| App initializer hook | Added |
ios/ native directory |
Not created |
android/ native directory |
Not created |
| Capacitor npm dependencies installed | No |
| CI/CD pipeline | No |
| Tested on device/simulator | No |
Tech Stack
- Framework: Capacitor v6 (by Ionic team)
- App ID:
space.gograb.vitto.mobile - Web directory: Points to the same Angular build output:
dist/apps/gograb-ai/browser - Bridge service: Uses
window.Capacitor.Plugins['Name']for runtime access (no compile-time dependencies needed) - Planned plugins: Push Notifications, Haptics, Splash Screen, Status Bar, Browser (OAuth)
How it works (same pattern as Tauri desktop)
Angular App (gograb-ai)
|-- Tauri wrapper -> Vitto Desktop (macOS/Windows/Linux)
|-- Capacitor wrapper -> Vitto Mobile (iOS/Android) <- NEW
The Angular app builds once. Both wrappers load the same dist/ output. Each wrapper provides native capabilities through a bridge service (TauriBridgeService for desktop, CapacitorBridgeService for mobile). Both services are no-ops when running in a regular browser.
Is it ready to use?
No. It's a scaffolding — the NX project and configuration exist, but you can't run cap sync or open it in Xcode/Android Studio yet because:
- Capacitor packages aren't installed in root
package.json - No
npx cap add ios/npx cap add androidhas been run - No native directories exist
- No signing certificates configured
What's needed to make it work
# 1. Install Capacitor
yarn add @capacitor/core @capacitor/ios @capacitor/android
yarn add -D @capacitor/cli
# 2. Install plugins
yarn add @capacitor/push-notifications @capacitor/haptics \
@capacitor/splash-screen @capacitor/status-bar @capacitor/browser
# 3. Build Angular app
nx build app-gograb-ai
# 4. Add native platforms
cd apps/vitto-mobile
npx cap add ios
npx cap add android
npx cap sync
# 5. Open in IDE
npx cap open ios # Opens Xcode
npx cap open android # Opens Android Studio
Current State of E2B / Sandbox Infrastructure
What works RIGHT NOW
| Component | Status | Details |
|---|---|---|
| E2B Cloud | Active | E2B_API_KEY is set in .env.local. Firecracker VMs spin up on demand via @e2b/desktop SDK |
| Playwright fallback | Active | Used when E2B key is missing or for targetType: 'desktop' goals |
| Provider abstraction | Active | SandboxProviderFactory selects provider based on env vars at startup |
| LLM cost tracking | Active | Every Computer Use API call now records tokens/cost |
| Per-session sandboxes | Active | Each Computer Use session gets its own isolated VM (30min idle, 55min max) |
What is SCAFFOLDED (not working yet)
| Component | Status | What's missing |
|---|---|---|
| Self-hosted provider | HTTP client exists | No server to connect to. The SelfHostedProvider will send HTTP requests to SANDBOX_SERVER_URL, but we haven't built the Sandbox Orchestrator server yet |
| Sandbox Orchestrator | Plan document only | The 6-phase plan is at docs/english/Plans/self-hosted-e2b.plan.md (420 lines). Zero implementation |
| Custom Firecracker images | Plan only | Need Ubuntu rootfs with XFCE, Chrome, x11vnc, xdotool pre-installed |
| Hetzner server | Not provisioned | Plan targets AX41-NVMe ($46/mo) with KVM support |
In simple terms
We currently pay E2B for cloud VMs. The abstraction layer is done, so when we're ready to run our own VMs, we just:
- Build the Sandbox Orchestrator server (NestJS service on Hetzner)
- Set
SANDBOX_SERVER_URL=https://sandbox.gograb.spacein.env.local - The system automatically switches to self-hosted. No changes to the Computer Use loop.
The break-even point is ~10 active users (E2B Pro is $150/mo + usage vs self-hosted at $46/mo fixed).
Files Created This Session
| File | Purpose |
|---|---|
APIs/backend-ai-api/.../sandbox/sandbox-provider.interface.ts |
SandboxProvider interface + SandboxHandle type |
APIs/backend-ai-api/.../sandbox/e2b-cloud.provider.ts |
Wraps existing E2BDesktopService |
APIs/backend-ai-api/.../sandbox/self-hosted.provider.ts |
HTTP client for future orchestrator |
APIs/backend-ai-api/.../sandbox/playwright.provider.ts |
Wraps BrowserAutomationService |
APIs/backend-ai-api/.../sandbox/sandbox-provider.factory.ts |
Env-based provider selection |
APIs/backend-ai-api/.../sandbox/index.ts |
Barrel export |
APIs/backend-ai-api/.../llm-cost-tracker.service.ts |
In-memory LLM spend tracking |
APIs/backend-ai-api/.../observatory.service.ts |
Health aggregation + Prometheus metrics |
APIs/backend-ai-api/.../controllers/observatory.controller.ts |
4 REST endpoints |
libs/libs-ai/.../observatory-data.service.ts |
Frontend data service |
libs/libs-ai/.../observatory-dashboard/ (3 files) |
Frontend dashboard component |
apps/vitto-mobile/capacitor.config.ts |
Capacitor configuration |
apps/vitto-mobile/project.json |
NX project with mobile targets |
apps/vitto-mobile/package.json |
Package metadata |
apps/gograb-ai/.../capacitor-bridge.service.ts |
Runtime bridge to Capacitor plugins |
APIs/backend-vitto-api/.../a2a/__tests__/ (5 files) |
A2A protocol integration tests |
Files Modified This Session
| File | Change |
|---|---|
computer-use-loop.service.ts |
Removed E2BDesktopService dependency, added LLM cost tracking |
infrastructure.module.ts |
Registered observatory services and controller |
observatory-page.component.* (3 files) |
Added tab system |
desktop-auth.guard.ts |
Added isMobile check |
app.config.ts |
Added CapacitorBridge initializer |
libs/libs-ai/.../components/index.ts |
Exported ObservatoryDashboardComponent |
libs/libs-ai/.../services/index.ts |
Exported ObservatoryDataService |
Remaining Gaps / Next Steps
Self-Hosted Sandbox Orchestrator — The biggest remaining piece. Need to build the NestJS service that runs on Hetzner and manages Firecracker VMs. Plan is written, implementation is zero.
Vitto Mobile -> Real Device — Install Capacitor packages, run
cap add ios/android, test on simulator, set up signing and CI/CD.A2A Tests -> Run them — Tests were written but should be verified with
nx test backend-vitto-api --testPathPattern=a2a.LLM Cost Persistence — Currently in-memory only (resets on server restart). Could add MongoDB persistence for historical trends.
Prometheus Scraping — The
/metricsendpoint exists but no Prometheus/Grafana instance is set up to scrape it.