VITTO VS OPENCLAW
Documentation for Sessions
Vitto vs OpenClaw: Honest Assessment & Usage Guide
Session 116 | February 2026 This document is a candid engineering assessment, not marketing material.
TL;DR
Vitto is a multi-service AI agent platform with 13 NestJS modules, 90+ MCP tools, multi-agent handoffs, tiered vector memory, multi-LLM routing, and a layered security system. OpenClaw is a single-binary personal AI assistant with 4 core tools, 565+ community skills, and direct OS access.
They solve different problems. OpenClaw is a power-user's personal assistant. Vitto is an enterprise platform for teams running agents at scale with audit trails, cost control, and security.
What's real vs aspirational is detailed below. Read the "Honesty Check" column carefully.
Feature Comparison
Core Agent Capabilities
| Feature | OpenClaw | Vitto | Honesty Check |
|---|---|---|---|
| Autonomous task execution | Yes (4 core tools + bash) | Yes (10 tools, 4-phase ANALYZE-PLAN-EXECUTE-VERIFY) | Both real. Vitto's phased approach is more structured but slower per task. |
| Multi-model LLM support | Claude, GPT-4, Ollama, MiniMax | Claude, GPT-4, Gemini, Ollama | Both real. Vitto adds SmartRouter with cost-based auto-routing. |
| Persistent memory | Markdown files, basic context | Vector-embedded tiered recall (hot cache + Atlas $vectorSearch + platform APIs) | Vitto wins clearly. 1536-dim embeddings with semantic recall vs flat files. |
| Self-extending skills | Agent writes its own extensions, hot-reloads | Skill CRUD + marketplace + versioning + rollback | Different approaches. OpenClaw's is more dynamic (agent self-modifies). Vitto's is more controlled. |
| Proactive operation | Cron jobs, heartbeats, reminders | ProactiveMonitorService with @Cron scheduling | Both real. Vitto's is integrated into the NestJS lifecycle. |
| Sub-agents / delegation | Single agent only | DelegationManagerService + SubAgentService + MCP handoffs | Vitto wins. Multi-agent mesh with handoff protocol is production-tested. |
| Cost visibility | None ($300+/day reports) | CostTrackerService + CostGuardService (25 iter, 100K token, 5min limits) | Vitto wins on guards. BUT: spending persistence is NOT wired (see gaps). |
Messaging / Channels
| Feature | OpenClaw | Vitto | Honesty Check |
|---|---|---|---|
| Yes (core) | Yes (inbound + outbound wired) | Both real. | |
| Telegram | Yes (core) | Yes (Bot API, webhook receiver wired) | Both real. Vitto added in Phase 2. |
| Discord | Yes (core) | Yes (webhook + PING verification wired) | Both real. |
| Slack | Yes (core) | Yes (HMAC-SHA256 verified, full reply loop) | Both real. |
| No | SendGrid HTTP API adapter | Vitto only. But untested in production. | |
| iMessage | Yes (AppleScript on macOS) | No | OpenClaw only. Platform-specific. |
| Signal | Yes | No | OpenClaw only. |
| Reply routing | Implicit (same thread) | Explicit routeTaskResponse() with context.replyTo |
Both work. Vitto's is channel-agnostic. |
Security
| Feature | OpenClaw | Vitto | Honesty Check |
|---|---|---|---|
| Tool sandboxing | None ("YOLO mode") | 3-tier: safe/guarded/dangerous with approval flow | Vitto wins dramatically. OpenClaw gives unrestricted bash access. |
| Prompt injection defense | None | 50+ regex patterns, 8 attack categories, channel-specific limits | Exists but NOT WIRED. scanForInjection() is never called in the execution path. Dead code. |
| Credential management | Plaintext in env | AES-256-GCM SecretVaultService | Vitto wins. But vault is only used for skill requiredSecrets, not system-wide. |
| Audit logging | None | MongoDB-persistent, 365-day retention, hot cache, CSV/JSON export | Fully wired and real. Every tool call is logged. |
| Network access control | Unrestricted | NetworkPolicyService (SSRF protection, endpoint allowlists) | Exists, partially wired. Called from validateSkillEndpoint() but NOT from http_request tool handler itself. |
| Rate limiting | None | Per-channel rate limits, loop detection, cost runaway detection | Exists but NOT WIRED. ChannelRateLimiterService is never called from engine or gateway. |
| Circuit breakers | None | CircuitBreakerService (CLOSED/OPEN/HALF_OPEN) | Exists but NOT WIRED. Never called from LLM providers or tool execution. |
| Dead letter queue | None | MongoDB-backed DLQ with exponential backoff | Exists but NOT WIRED. enqueue() is never called from task failure paths. |
| Container sandbox | None | Docker-based isolation (--cap-drop ALL, --network none) | Exists but NOT WIRED. Only exposed via /security/sandbox/status endpoint. run_command tool does NOT use it. |
| RBAC | None | RolesGuard with @Roles('admin') decorator | Wired on security controller endpoints. Works for compliance routes. |
Enterprise / Compliance
| Feature | OpenClaw | Vitto | Honesty Check |
|---|---|---|---|
| Tamper-evident audit | None | SHA-256 hash chain on audit entries | Exists but NOT WIRED. computeHash() is never called from SecurityAuditService.record(). Hash fields exist in schema but are always null. |
| Data retention | None | RetentionPolicyService (365/180/90/30-day tiers) | Wired via controller endpoint. Needs @Cron job to run automatically. |
| GDPR export | None | exportUserData() + deleteUserData() with tombstoning |
Wired via controller. Functional. |
| Team learning | None | shareLevel on memories, recallTeam() method |
Wired via controller. But no teams exist in the user model yet. |
| Skill versioning | None | Immutable snapshots + rollback | Wired. updateSkill() auto-creates snapshots. Rollback endpoint works. |
| Multi-tenant | No (single-user) | Yes (userId scoping throughout) | Vitto wins. Built for teams. |
Deployment
| Feature | OpenClaw | Vitto | Honesty Check |
|---|---|---|---|
| Setup time | "Minutes" (single binary) | Railway per-service deployment with Dockerfiles | OpenClaw wins on simplicity. Vitto requires 3+ services + MongoDB + env config. |
| Self-hosted | Yes (runs locally) | Yes (Docker/Railway) | Both. |
| Cloud deployment | Community-hosted | Railway with per-service branches, health checks, auto-restart | Vitto has proper production infra. |
| Background operation | Runs in terminal or as service | Requires running NestJS backend(s) | OpenClaw is simpler. Vitto needs infrastructure. |
What's ACTUALLY Working End-to-End
These features you can use RIGHT NOW with confidence:
- Submit a task via POST /engine/tasks and watch it execute through ANALYZE-PLAN-EXECUTE-VERIFY phases
- Send a Slack/WhatsApp/Telegram/Discord message and get a response routed back through the same channel
- Tool execution with security audit - every tool call is logged to MongoDB with sandbox level, duration, success/failure
- Semantic memory recall - ask Vitto about past interactions and get vector-similarity ranked results
- Multi-LLM routing - SmartRouter selects provider by complexity, with failover and history tracking
- Skill CRUD with versioning - create, update (auto-snapshot), rollback, publish with security vetting
- Cost guard limits - 25 iterations, 100K tokens, 5-minute max per task enforced
- SSE event streaming - real-time task progress via
GET /engine/events - Multi-agent handoffs - delegate tasks to other agents via MCP handoff protocol
- GDPR export/delete - export or tombstone all user data via security controller
What EXISTS But Is NOT Connected (Dead Code)
These services were built but never wired into the execution flow:
| Service | What It Does | What's Missing |
|---|---|---|
scanForInjection() |
Scans text for 50+ injection patterns | Never called before tool execution or LLM input. No caller. |
sanitizeOutput() |
Strips leaked system prompts, env vars | Never called on LLM/tool output. No caller. |
ChannelRateLimiterService |
Per-channel rate limits + loop detection | Never called from ChannelGateway or VittoEngine. No caller. |
CircuitBreakerService |
Provider failure circuit breaking | Never wraps LLM calls or tool execution. No caller. |
DeadLetterQueueService |
Failed task retry with backoff | Never called from task failure handlers. No caller. |
HashChainVerifierService.computeHash() |
Tamper-evident audit hashing | Never called from SecurityAuditService.record(). Chain is empty. |
ProcessSandboxService |
OS-level process isolation | Never called from run_command tool. Tool uses raw execAsync. |
ContainerSandboxService |
Docker container isolation | Only exposed via status endpoint. Never used for execution. |
NetworkPolicyService |
SSRF protection + endpoint allowlists | Only called from SkillManagerService.validateSkillEndpoint(), never from http_request tool. |
CostTrackerService.recordSpending() |
Persist spending to MongoDB | Never called from PhaseExecutor or AgentLoop after LLM calls. |
Impact: These represent approximately 40% of the Phases 1-5 code. The services are correctly built, registered in modules, and injectable. They just need callers.
How to Use Vitto Today
Prerequisites
- MongoDB running (local or Atlas)
.env.localwithANTHROPIC_API_KEY,OPENAI_API_KEY,MONGODB_URI- Backend running:
yarn serve:backend-vitto(port 3003)
Submit a Task
curl -X POST http://localhost:3003/vitto-api/engine/tasks \
-H "Content-Type: application/json" \
-d '{
"request": "Analyze the authentication flow in our codebase and suggest improvements",
"userId": "user-123",
"context": {
"layer": "developer",
"spaceId": "my-space"
}
}'
Stream Task Progress (SSE)
curl -N http://localhost:3003/vitto-api/engine/events
Recall Memories
curl "http://localhost:3003/vitto-api/engine/memories/search?query=authentication+flow&userId=user-123&limit=5"
Manage Skills
# Create a skill
curl -X POST http://localhost:3003/vitto-api/engine/skills \
-H "Content-Type: application/json" \
-d '{
"name": "code-reviewer",
"description": "Reviews code for security and quality issues",
"category": "developer",
"triggers": ["review code", "check code quality"],
"steps": [{ "action": "analyze", "params": { "focus": "security" } }]
}'
# Publish (runs security vetting)
curl -X POST http://localhost:3003/vitto-api/engine/skills/{id}/publish
# View version history
curl http://localhost:3003/vitto-api/engine/skills/{id}/versions
# Rollback
curl -X POST http://localhost:3003/vitto-api/engine/skills/{id}/rollback \
-d '{ "targetVersion": "1.0.0" }'
Check Security Dashboard
# Audit logs
curl "http://localhost:3003/vitto-api/security/audit?limit=20"
# Audit stats
curl http://localhost:3003/vitto-api/security/audit/stats
# Export for compliance
curl http://localhost:3003/vitto-api/security/audit/export/csv > audit.csv
# GDPR export
curl http://localhost:3003/vitto-api/security/compliance/gdpr/export/user-123
Configure Messaging Channels
# Slack: Configure webhook at POST /engine/integrations/slack/events
# Telegram: Set webhook to POST /engine/integrations/telegram/webhook
# Discord: Set webhook to POST /engine/integrations/discord/webhook
# WhatsApp: Configure Twilio webhook at POST /engine/integrations/whatsapp/webhook
Schedule Tasks
curl -X POST http://localhost:3003/vitto-api/engine/schedules \
-H "Content-Type: application/json" \
-d '{
"name": "daily-health-check",
"cronExpression": "0 9 * * *",
"taskType": "prompt",
"taskConfig": {
"prompt": "Run health checks on all services and report status",
"layer": "developer"
}
}'
Architectural Strengths (What's Genuinely Good)
Module isolation is excellent. 13 NestJS modules with clean dependency graph. No circular imports. SecurityModule exports everything downstream needs. Zero DI failures detected.
Audit logging is solid. Every tool call hits
recordAudit()with sandbox level, input/output, timing, and success/failure. 365-day retention with TTL indexes. Hot cache for fast dashboard reads. This is real SOC 2 foundation.Memory system is sophisticated. Vector embeddings with Atlas $vectorSearch, tiered hot/warm/cold recall, importance scoring that evolves with access frequency. This is genuinely better than OpenClaw's flat Markdown files.
Multi-agent handoffs work. MCP-based handoff protocol with WebSocket push, REST fallback, offline queuing, and sentinel reconnection. Tested across Cursor, Claude Code, VSCode, and Chrome extension.
Skill versioning is well-designed. Immutable snapshots before every update, semver bumping, full rollback with pre-rollback safety snapshots. The data model is sound.
SmartRouter is smart. Cost-based routing with provider failover, routing history, and decision persistence. The in-memory-first + MongoDB-secondary pattern is the right tradeoff for latency.
Critical Gaps to Fix (Prioritized)
P0 — Wire the Dead Code
These are the highest-leverage fixes. The code exists and is tested, it just needs callers:
| # | Fix | Effort | Impact |
|---|---|---|---|
| 1 | Call scanForInjection() in ToolRegistryService.executeTool() before passing input to handler |
5 lines | Activates prompt injection defense |
| 2 | Call rateLimiter.check() in ChannelGatewayService.normalizeInbound() |
5 lines | Activates rate limiting + loop detection |
| 3 | Wrap LLM calls in SmartRouterService.route() with circuitBreaker.execute() |
10 lines | Activates circuit breaking on provider failures |
| 4 | Call dlq.enqueue() in VittoEngineService when a task fails after max retries |
5 lines | Activates dead letter queue |
| 5 | Call hashChain.computeHash() in SecurityAuditService.record() and store on the document |
5 lines | Activates tamper-evident audit chain |
| 6 | Call costTracker.recordSpending() in PhaseExecutorService after each LLM call |
5 lines | Activates spending persistence |
Total effort: ~35 lines of glue code. This would activate 6 major security features.
P1 — Missing Integration Points
| # | Gap | Why It Matters |
|---|---|---|
| 7 | run_command tool does not use ProcessSandboxService |
Commands run with full process.env access (secrets are stripped, but no resource limits) |
| 8 | http_request tool does not call NetworkPolicyService.validate() |
Any URL can be fetched, including private IPs (SSRF) |
| 9 | No @Cron job for RetentionPolicyService.enforceRetention() |
Retention policy exists but never runs automatically |
| 10 | Team learning has no team model | shareLevel and teamId exist on memories but no team entity exists in the system |
P2 — Architecture Gaps vs OpenClaw
| # | Gap | Why It Matters |
|---|---|---|
| 11 | No self-modification capability | OpenClaw's killer feature: agent writes/reloads its own skills at runtime |
| 12 | No desktop daemon for background operation | Vitto requires running backend services; OpenClaw runs as a single process |
| 13 | No frontend onboarding wizard | Setup requires manual env config + service startup |
| 14 | BullMQ/Redis task queue not implemented | Plan called for BullMQ but current task scheduler is in-memory + MongoDB |
Verdict
Vitto's foundation is strong. The module architecture, memory system, multi-agent handoffs, and audit logging are production-grade. The security services are well-designed and correctly registered.
The main problem is integration, not implementation. ~40% of the security code (Phases 1-5) exists as standalone services that aren't called from the execution flow. Fixing this requires ~35 lines of glue code, not new features.
vs OpenClaw:
- Vitto wins on: security, audit, memory, multi-agent, cost control, multi-tenant, skill versioning
- OpenClaw wins on: simplicity, self-modification, setup speed, community/skills ecosystem, desktop integration
- Neither wins on: both have unfinished edges; Vitto's are documented here, OpenClaw's are security holes
Bottom line: Wire the dead code (P0 items 1-6), and Vitto goes from "impressive architecture with gaps" to "enterprise-ready AI agent platform."