2026 03 19 Vitto Unified Autonomy Engine

Documentation for Plans

Vitto Unified Autonomy Engine — Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Wire VM execution, adaptive trust, proactive intelligence, and crash recovery into a unified autonomy layer for Vitto.

Architecture: Three independent services (TrustScoringService, TierResolverService, TriggerEngineService) feed a read-only AutonomyContext assembled by an AutonomyGateService. VM execution uses the existing per-user snapshot infrastructure via a new VmApiClientService chain through backend-ai-api to sandbox-orchestrator. Trust scores are materialized in MongoDB, updated event-driven on outcomes. Proactive triggers live in a dedicated collection. Task recovery uses genome-based checkpoints.

Tech Stack: NestJS, MongoDB/Mongoose, Firecracker VMs, Angular 20+ (standalone, signals, OnPush), NGXS-free (signals + flash-persistence), RxJS Observables (no Promises)

Spec: docs/superpowers/specs/2026-03-19-vitto-unified-autonomy-engine-design.md


File Structure

New Files (Backend)

APIs/backend-vitto-api/src/app/engine/
  autonomy/
    autonomy-context.ts                    # AutonomyContext interface + TaskEvaluation
    autonomy-gate.service.ts               # Gate: assembles context from 3 services
    autonomy-gate.service.spec.ts          # Unit tests
    trust-scoring.service.ts               # Adaptive trust engine (0-100, domain-scoped)
    trust-scoring.service.spec.ts          # Unit tests
    tier-resolver.service.ts               # Dynamic tier selection + VM acquisition
    tier-resolver.service.spec.ts          # Unit tests
    schemas/
      trust-score.schema.ts                # Mongoose schema for vitto-trust-scores
  vm/
    vm-api-client.service.ts               # HTTP client to ai-api sandbox endpoints
    vm-api-client.service.spec.ts          # Unit tests
    sandboxed-tool-proxy.service.ts        # Routes tool calls to VM (structured API)
    sandboxed-tool-proxy.service.spec.ts   # Unit tests
    vm-session-manager.service.ts          # Per-user VM lifecycle (snapshot-based)
    vm-session-manager.service.spec.ts     # Unit tests
    vm-credential-injector.service.ts      # Deploy key injection via structured API
  recovery/
    task-recovery.service.ts               # Genome-based checkpoint save/recover
    task-recovery.service.spec.ts          # Unit tests
    schemas/
      task-recovery.schema.ts              # Mongoose schema (24h TTL)

APIs/backend-vitto-api/src/app/proactive/
  trigger-engine.service.ts                # Learned trigger detection and execution
  trigger-engine.service.spec.ts           # Unit tests
  schemas/
    trigger-pattern.schema.ts              # Mongoose schema for vitto-triggers

APIs/backend-ai-api/src/app/infrastructure/
  controllers/
    sandbox-proxy.controller.ts            # 9 new endpoints proxying SelfHostedProvider
    sandbox-proxy.controller.spec.ts       # Unit tests

APIs/sandbox-orchestrator/src/app/sandbox/
  file-ops.controller.ts                   # write-file, read-file, inject-ssh-key
  file-ops.controller.spec.ts              # Unit tests

deployment/sandbox-orchestrator/
  Dockerfile.rootfs-developer              # Headless developer VM image
  vm-init-developer.sh                     # SSH-only init script

Existing Files to Modify (Backend)

APIs/backend-vitto-api/src/app/engine/
  sub-vitto-orchestrator.service.ts:20,110,146-156  # MAX_DEPTH, orchestrate, browser fallback
  agent-loop.service.ts:132                         # run() add VM-aware tool routing
  autonomy.service.ts:206-258                       # shouldProceed read dynamic trust
  trust-escalation.service.ts:31-324                # Deprecate, migrate to TrustScoringService
  vitto-engine.service.ts:134,183                   # Add checkpoint hooks

APIs/backend-vitto-api/src/app/strategy/
  cost-guard.service.ts:38-59                       # Add depth-aware budget inheritance

APIs/backend-vitto-api/src/app/proactive/
  proactive-dispatcher.service.ts:55                # Wire trigger execution

APIs/backend-vitto-api/src/app/types/
  vitto.types.ts:23,100,102-114                     # Add new interfaces, extend SubVittoTask

APIs/backend-vitto-api/src/app/mind/
  outcome-feedback.service.ts:32                    # Wire trust score updates

Frontend Files to Create/Modify

libs/libs-ai/vitto-chat/src/lib/components/tool-renderers/renderers/
  sub-vitto-orchestration-renderer/                 # Update: VM status, tier badge, degradation

libs/libs-ai/vitto-chat/src/lib/components/activity-cards/cards/
  vm-execution-card.component.ts                    # NEW: VM task progress card
  vm-execution-card.component.html
  vm-execution-card.component.scss
  trust-update-card.component.ts                    # NEW: Trust score change card
  trust-update-card.component.html
  trust-update-card.component.scss
  proactive-trigger-card.component.ts               # NEW: Learned trigger suggestion card
  proactive-trigger-card.component.html
  proactive-trigger-card.component.scss

libs/libs-ai/vitto-hub/src/lib/components/
  observatory-panel/trust-dashboard/                # Update: domain-scoped trust, trajectory

libs/libs-ai/agent-mind/src/lib/components/
  autonomy-slider/autonomy-slider.component.ts      # Update: show adaptive trust score

libs/libs-ai/gograb-ai-lib/src/lib/types/
  vitto.types.ts                                    # Update: add VM, trust, trigger types

libs/libs-ai/vitto-core/src/lib/types/
  observatory-dtos.ts                               # Update: domain-scoped TrustScore

libs/libs-ai/vitto-core/src/lib/services/
  vitto-api.service.ts                              # Update: add trust/trigger API methods

libs/libs-ai/vitto-core/src/lib/utils/
  autonomy-level-mapper.ts                          # NEW: backend to frontend level mapping

Phase 0: Configuration & Prerequisites

Task 0.1: Environment Variables and MongoDB Collections

Files:

# Trust Engine
VITTO_TRUST_DEFAULT_SCORE=25
VITTO_TRUST_MAX_ESCALATION_PER_WEEK=1
VITTO_TRUST_FAILURE_PENALTY=5
VITTO_TRUST_CRITICAL_PENALTY=15

# VM Execution
VITTO_VM_DEVELOPER_TEMPLATE=developer
VITTO_VM_REUSE_ACTIVE=true
VITTO_VM_SNAPSHOT_ON_RELEASE=true

# Triggers
VITTO_TRIGGER_MIN_OCCURRENCES=3
VITTO_TRIGGER_DETECTION_WINDOW_DAYS=14
VITTO_TRIGGER_AUTO_EXECUTE_CONFIDENCE=0.8
VITTO_TRIGGER_DISABLE_THRESHOLD=0.3

# Checkpoints
VITTO_CHECKPOINT_ENABLED=true
VITTO_CHECKPOINT_TTL_HOURS=24

# Nesting
VITTO_MAX_NESTING_DEPTH=2
VITTO_DEPTH2_BUDGET_RATIO=0.5
VITTO_DEPTH2_MAX_TOOLS=5
// vitto-mind database
db.createCollection('vitto-trust-scores');
db.getCollection('vitto-trust-scores').createIndex({ userId: 1, domain: 1 }, { unique: true });

db.createCollection('vitto-triggers');
db.getCollection('vitto-triggers').createIndex({ userId: 1, enabled: 1, confidence: 1 });

db.createCollection('vitto-checkpoints');
db.getCollection('vitto-checkpoints').createIndex({ savedAt: 1 }, { expireAfterSeconds: 86400 });
db.getCollection('vitto-checkpoints').createIndex({ taskId: 1 }, { unique: true });

Phase 1: Sandbox-Orchestrator Structured Endpoints (Session 1)

Task 1.1: Structured File Operations Controller

Files:

describe('FileOpsController', () => {
  describe('POST /sandboxes/:id/write-file', () => {
    it('should write file content via SFTP without shell interpolation', async () => {
      const mockExecutor = { execSftp: jest.fn().mockResolvedValue(undefined) };
      const mockManager = { getSandbox: jest.fn().mockReturnValue({ vmIp: '172.16.0.2', status: 'running' }) };
      const controller = new FileOpsController(mockManager as any, mockExecutor as any);
      const result = await controller.writeFile('sandbox-1', { path: '/home/user/test.txt', content: 'hello world' });
      expect(mockExecutor.execSftp).toHaveBeenCalledWith('172.16.0.2', 'write', { path: '/home/user/test.txt', content: 'hello world' });
      expect(result).toEqual({ success: true, path: '/home/user/test.txt' });
    });
  });

  describe('POST /sandboxes/:id/read-file', () => {
    it('should read file content via SSH cat', async () => {
      const mockExecutor = { execSftp: jest.fn().mockResolvedValue('file contents') };
      const mockManager = { getSandbox: jest.fn().mockReturnValue({ vmIp: '172.16.0.2', status: 'running' }) };
      const controller = new FileOpsController(mockManager as any, mockExecutor as any);
      const result = await controller.readFile('sandbox-1', { path: '/home/user/test.txt' });
      expect(result).toEqual({ success: true, content: 'file contents' });
    });
  });

  describe('POST /sandboxes/:id/inject-ssh-key', () => {
    it('should inject SSH key via tmpfs without shell history', async () => {
      const mockExecutor = { injectSshKey: jest.fn().mockResolvedValue(undefined) };
      const mockManager = { getSandbox: jest.fn().mockReturnValue({ vmIp: '172.16.0.2', status: 'running' }) };
      const controller = new FileOpsController(mockManager as any, mockExecutor as any);
      const result = await controller.injectSshKey('sandbox-1', { keyContent: 'key-data', repoUrl: '[email protected]:org/repo' });
      expect(mockExecutor.injectSshKey).toHaveBeenCalledWith('172.16.0.2', 'key-data', '[email protected]:org/repo');
      expect(result).toEqual({ success: true });
    });
  });
});

Run: cd APIs/sandbox-orchestrator && npx jest file-ops --no-coverage Expected: FAIL with "FileOpsController not defined"

import { Controller, Post, Param, Body, UseGuards, NotFoundException } from '@nestjs/common';
import { ApiKeyGuard } from '../auth/api-key.guard';
import { SandboxManagerService } from './sandbox-manager.service';
import { VmExecutorService } from './vm-executor.service';

@Controller('sandboxes')
@UseGuards(ApiKeyGuard)
export class FileOpsController {
  constructor(
    private readonly manager: SandboxManagerService,
    private readonly executor: VmExecutorService,
  ) {}

  @Post(':id/write-file')
  async writeFile(@Param('id') sandboxId: string, @Body() body: { path: string; content: string }) {
    const sandbox = this.manager.getSandbox(sandboxId);
    if (!sandbox || sandbox.status !== 'running') throw new NotFoundException(`Sandbox ${sandboxId} not found or not running`);
    await this.executor.execSftp(sandbox.vmIp, 'write', body);
    return { success: true, path: body.path };
  }

  @Post(':id/read-file')
  async readFile(@Param('id') sandboxId: string, @Body() body: { path: string }) {
    const sandbox = this.manager.getSandbox(sandboxId);
    if (!sandbox || sandbox.status !== 'running') throw new NotFoundException(`Sandbox ${sandboxId} not found or not running`);
    const content = await this.executor.execSftp(sandbox.vmIp, 'read', body);
    return { success: true, content };
  }

  @Post(':id/inject-ssh-key')
  async injectSshKey(@Param('id') sandboxId: string, @Body() body: { keyContent: string; repoUrl: string }) {
    const sandbox = this.manager.getSandbox(sandboxId);
    if (!sandbox || sandbox.status !== 'running') throw new NotFoundException(`Sandbox ${sandboxId} not found or not running`);
    await this.executor.injectSshKey(sandbox.vmIp, body.keyContent, body.repoUrl);
    return { success: true };
  }
}

Add to APIs/sandbox-orchestrator/src/app/sandbox/vm-executor.service.ts:

async execSftp(vmIp: string, operation: 'read' | 'write', params: { path: string; content?: string }): Promise<string | void> {
  const sshKeyPath = this.getSshKeyPath(vmIp);
  if (operation === 'write') {
    const tmpFile = `/tmp/sftp-upload-${Date.now()}`;
    await fs.promises.writeFile(tmpFile, params.content || '');
    try {
      await execFilePromise('scp', ['-i', sshKeyPath, '-o', 'StrictHostKeyChecking=no', tmpFile, `user@${vmIp}:${params.path}`]);
    } finally {
      await fs.promises.unlink(tmpFile).catch(() => {});
    }
  } else {
    const { stdout } = await execFilePromise('ssh', ['-i', sshKeyPath, '-o', 'StrictHostKeyChecking=no', `user@${vmIp}`, 'cat', params.path]);
    return stdout;
  }
}

async injectSshKey(vmIp: string, keyContent: string, repoUrl: string): Promise<void> {
  const sshKeyPath = this.getSshKeyPath(vmIp);
  // Key is piped via stdin, never appears in command args or shell history
  await execFilePromise('ssh', [
    '-i', sshKeyPath, '-o', 'StrictHostKeyChecking=no', `user@${vmIp}`,
    'bash', '-c', 'cat > /dev/shm/dk && chmod 600 /dev/shm/dk && eval $(ssh-agent -s) && ssh-add /dev/shm/dk && rm -f /dev/shm/dk',
  ], { input: keyContent });
}

Phase 2: Backend-AI-API Sandbox Proxy (Session 1-2)

Task 2.1: Sandbox Proxy Controller (9 endpoints)

Files:


Phase 3: VM Execution Layer in Vitto-API (Sessions 2-3)

Task 3.1: VmApiClientService

Files:

Task 3.2: VmSessionManagerService

Files:

Task 3.3: SandboxedToolProxyService

Files:

Task 3.4: VmCredentialInjectorService

Files:

Task 3.5: Wire VM into SubVittoOrchestrator + AgentLoop

Files:


Phase 4: Adaptive Trust Engine (Sessions 3-4)

Task 4.1: Trust Score Schema + AutonomyContext Types

Files:

Task 4.2: TrustScoringService

Files:

Task 4.3: TierResolverService

Files:

Task 4.4: AutonomyGateService

Files:

Task 4.5: Wire Trust into AutonomyService + OutcomeFeedback + SubVitto Outcomes

Files:


Phase 5: Proactive Intelligence (Sessions 5-6)

Task 5.1: Trigger Pattern Schema + TriggerEngineService

Files:

Task 5.2: Wire Triggers into Task Completion + Dispatch

Files:


Phase 6: Checkpoint Recovery + Agent Nesting (Sessions 6-7)

Task 6.1: TaskRecoveryService

Files:

Task 6.2: Wire Recovery into Agent Loop + Engine

Files:

Task 6.3: Agent Nesting (Depth-2)

Files:


Phase 7: E2E Tests (Sessions 8-9)

Task 7.1: VM Execution E2E

Files:

Task 7.2: Trust Scoring E2E

Files:

Task 7.3: Proactive Trigger E2E

Files:

Task 7.4: Checkpoint Recovery E2E

Files:

Task 7.5: Agent Nesting E2E

Files:


Phase 8: Frontend NX Libs, UI Components, and Deprecation Cleanup (Sessions 9-12)

Task 8.1: Verify Backend Types (Additive to Task 4.1)

Note: Task 4.1 already adds ActionDomain, LEVEL_ORDER, and extends SubVittoTask. This task only adds types NOT covered in Phase 4.

Files:

Task 8.2: Update Frontend Types

Files:

Task 8.3: Create AutonomyLevel Mapper Utility

Files:

Two AutonomyLevel definitions exist:

export const BACKEND_TO_FRONTEND: Record<string, string> = {
  OBSERVE: 'manual', SUGGEST: 'guided', DIRECT: 'collaborative', AUTONOMOUS: 'autonomous',
};
export const FRONTEND_TO_BACKEND: Record<string, string> = {
  manual: 'OBSERVE', guided: 'SUGGEST', collaborative: 'DIRECT', autonomous: 'AUTONOMOUS',
};
export function mapBackendToFrontend(level: string): string { return BACKEND_TO_FRONTEND[level] || 'manual'; }
export function mapFrontendToBackend(level: string): string { return FRONTEND_TO_BACKEND[level] || 'OBSERVE'; }

Task 8.4: Update VittoApiService

Files:

Task 8.5: Update Sub-Vitto Orchestration Renderer

Files:

Task 8.6: Create VM Execution Activity Card

Files:

Task 8.7: Create Trust Update Activity Card

Files:

Task 8.8: Create Proactive Trigger Card

Files:

Task 8.9: Update Trust Dashboard

Files:

Task 8.10: Update Autonomy Slider

Files:

Task 8.11: Wire SSE Events for New Event Types

Files:

Task 8.12: Deprecation Cleanup — TrustEscalationService

Files:

Task 8.13: Deprecation Cleanup — WorkflowSSEClientService

Files:

Task 8.14: Deprecation Cleanup — Legacy chat-input-bar

Files:

Task 8.15: Developer Rootfs Image Build

Ordering note: This is placed in Phase 8 because Phases 1-7 use mocked VMs in unit and E2E tests. For real VM integration testing, deploy this rootfs to Hetzner after Phase 8 and run manual integration tests. The rootfs is NOT a blocking dependency for the test phases.

Files:

Task 8.16: Final Integration Verification

grep -r "TrustEscalationService" libs/ APIs/ --include="*.ts" -l
grep -r "WorkflowSSEClientService" libs/ --include="*.ts" -l
grep -r "chat-input-bar" libs/ --include="*.ts" -l

Each should return 0 results (or only the deprecated file itself with @deprecated annotation).


Summary

Phase Tasks Sessions Focus
0. Configuration & Prerequisites 1 0.5 Env vars, MongoDB collections/indexes
1. Sandbox-Orchestrator Endpoints 1 1 Structured file ops + SSH key injection
2. Backend-AI-API Proxy 1 1 9 endpoints proxying SelfHostedProvider
3. VM Execution Layer 5 2 VmApiClient, SessionManager, ToolProxy, wiring
4. Adaptive Trust 5 2 TrustScoring, TierResolver, AutonomyGate, wiring
5. Proactive Intelligence 2 1 TriggerEngine, pattern detection, dispatch
6. Checkpoint + Nesting 3 1 TaskRecovery, depth-2 nesting
7. E2E Tests 5 2 VM, trust, triggers, recovery, nesting E2E
8. Frontend + Deprecation Cleanup 16 3 Types, components, cards, SSE, deprecation removal
Total 39 ~13.5