-
Notifications
You must be signed in to change notification settings - Fork 1
Architecture
siamakerlab edited this page May 23, 2026
·
19 revisions
┌─────────────────────────────────────────────────────────────┐
│ Docker container (Ubuntu 24.04 LTS noble) │
│ │
│ ┌────────────────────────────────────┐ │
│ │ Ktor server (vibe-coder-server) │ │
│ │ • Port 17880 │ │
│ │ • Netty engine │ │
│ │ • Routes (admin SSR + JSON API) │ │
│ │ • SQLite via Exposed │ │
│ │ • WebSocket log hub │ │
│ └─────────────┬──────────────────────┘ │
│ │ spawns │
│ ┌───────┼────────┬────────┐ │
│ ▼ ▼ ▼ ▼ │
│ claude gradlew git vibe-doctor │
│ (per- (per- (read- (Android SDK, │
│ project build) only) MCP install) │
│ persistent │
│ child) │
└─────────────────────────────────────────────────────────────┘
All external commands are wrapped in a TaskQueue + LogHub so progress
streams uniformly to WebSocket clients (browser / Android).
vibe-coder-server/
├── shared/ # JVM library (DTOs, ApiPath, WsFrame)
│ └── src/main/kotlin/.../shared/
│ ├── ApiPath.kt # All REST/WS routes as constants
│ ├── ws/WsFrame.kt # Sealed class hierarchy for WS frames
│ └── dto/Dtos.kt # @Serializable request/response types
│
└── server/ # Ktor app body
└── src/main/kotlin/.../server/
├── ServerMain.kt # Bootstrap, DI wiring
├── Module.kt # Routing + plugin install
├── auth/ # Bearer + session + setup
├── claude/ # ClaudeSessionManager (stream-json)
├── env/ # EnvSetupService, MCP, Claude auth
├── git/ # GitReader, GitCloneService, credentials
├── projects/ # ProjectService, KeystoreGenerator
├── build/ # BuildService (Gradle assembleDebug)
├── artifacts/ # APK storage
├── files/ # Upload routes
├── admin/ # SSR routes + HTML templates
├── tasks/ # TaskQueue (background work)
├── ws/ # LogHub (WebSocket broadcaster)
└── db/ # VibeDb (SQLite via Exposed)
-
Client sends
POST /api/projects/{id}/claude/console/promptwith text. -
ConsoleRoutes finds or spawns the
claudechild for that project (ClaudeSessionManager.spawnSession). Stream-json mode (--output-format stream-json --input-format stream-json). - The user prompt is written as a stream-json frame to the child's stdin.
- Claude responds line-by-line on stdout.
ClaudeStreamParserdecodes each line and turns it into aWsFramesubtype:console_session_started-
console_assistant(withisPartial) -
console_tool_use/console_tool_result -
console_done/console_error
-
LogHubbroadcasts the frame to all WS subscribers on/ws/projects/{id}/console/logs. - Browser console UI renders incrementally. Android client does the same with the same JSON shape.
All persistent state lives under one host directory (v0.7.0+). See Data Volumes & Backup for the full mapping.
./vibe-coder-data/
├── workspace/ # project sources + APKs
├── server/ # SQLite DB + server logs
├── dev-tools/ # Android SDK, Gradle, npm-global (MCP), npm cache, ...
└── claude/ # Claude OAuth credentials + MCP registrations
The image itself contains only the server body (~600 MB) and is replaced on upgrade. Every persistent path is a bind mount; no Docker named volumes are used by default.
-
First boot: empty DB →
/setupform creates admin (orVIBECODER_ADMIN_USERNAME/PASSWORDenv auto-bootstrap). -
Login:
/api/auth/loginreturns bearer token +vibe_sessioncookie. -
Subsequent requests: either auth header (
Authorization: Bearer ...) or the cookie. Both paths converge in the sameinstallAuthplugin. - Passwords: BCrypt cost 12 hash. 10 failures → 15-min lock. Timing-safe dummy verify on missing users.
shared/ is the contract between server and Android client. All wire
changes (ApiPath / DTO / WsFrame) must be reflected in the Android
companion repo's shared/ copy. CHANGELOG marks them with Wire change:
Yes/No.