Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

564 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Vibes

UX Tests CI

A mobile-friendly web UI for coding agents, written in Go. Ships as a single static binary (~24 MB) with zero runtime dependencies.

Supports four ACP agents and Pi native RPC. Built for personal use over Tailscale.

Demo

This is the Go port β€” single binary, embedded frontend, pure-Go SQLite.
The original Python implementation is on the python branch.


Features

  • Streaming chat β€” real-time SSE with Markdown, KaTeX, and Mermaid rendering
  • Workspace explorer β€” file tree with previews, drag-and-drop upload, folder downloads (ZIP)
  • Code editor β€” tabbed CodeMirror 6 editor (13 languages, Vim mode, search/replace, pop-out windows)
  • Agent controls β€” approve/deny tool calls, queue follow-ups, mid-turn steering, slash commands
  • Rich media β€” paste images, attach files, OpenGraph link previews
  • SQLite storage β€” messages, media, and full-text search in a single file
  • PWA β€” installable, dark/light themes, responsive from phone to desktop
  • Single binary β€” no Python, no Node.js, no virtualenv, no runtime dependencies
  • Extension system β€” backend routes, SSE events, and frontend UI panels
  • Multi-agent β€” switch between Copilot, Codex, Claude, OpenCode, and Pi at runtime

Verified ACP agents

Agent Binary Version Status
GitHub Copilot copilot-language-server --acp --stdio v1.472.0 βœ…
OpenAI Codex codex-acp v0.11.1 βœ…
Claude claude-agent-acp v0.29.2 βœ…
Pi pi-acp v0.0.26 βœ…
OpenCode opencode acp v1.14.31 βœ…

Capability matrix

Feature Copilot Codex Claude Pi OpenCode
Image support βœ… βœ… βœ… βœ… βœ…
Embedded context βœ… βœ… βœ… β€” βœ…
MCP support β€” βœ… (HTTP) βœ… (HTTP + SSE) β€” βœ… (HTTP + SSE)
Session list/close βœ… βœ… βœ… βœ… βœ…
Session fork/resume β€” β€” βœ… β€” βœ…
Prompt queueing β€” β€” βœ… β€” β€”
Free models β€” β€” β€” β€” βœ…
Auth GitHub OAuth ChatGPT / API key Pre-configured Terminal login opencode auth

All five implement ACP protocol v1 over stdio JSON-RPC. OpenCode provides free models (gpt-5-nano, hy3-preview-free, etc.) making it ideal for CI testing. Pi also supports a richer native RPC mode with streaming drafts, thinking traces, tool events, and live model control.


Quick start

# Build
git clone https://github.com/rcarmo/vibes.git && cd vibes
make build

# Run with GitHub Copilot (default)
./vibes

# Override detected ACP backends if needed
VIBES_CODEX_AGENT="codex-acp" ./vibes
VIBES_COPILOT_AGENT="copilot-language-server --acp --stdio" ./vibes

# Run with Pi native RPC selected by default (richer features)
VIBES_DEFAULT_AGENT=pi ./vibes

# Open in browser
open http://localhost:8080

Installation

From source (recommended)

make build    # frontend bundle + embedded Go binary

This produces a fully self-contained binary with all HTML, CSS, JS, fonts, and icons embedded at compile time via //go:embed.

Cross-compile

make build-linux-arm64    # Raspberry Pi, ARM Proxmox
make build-darwin-arm64   # macOS Apple Silicon
make build-all            # all platforms

Docker

# Local build
docker build -t vibes .
docker run -p 8080:8080 vibes

# Prebuilt release images from GHCR
docker pull ghcr.io/rcarmo/vibes:vX.Y.Z
docker run -p 8080:8080 ghcr.io/rcarmo/vibes:vX.Y.Z

The Dockerfile produces a scratch-based image (~24 MB) β€” just the binary + CA certificates. Release tags publish multi-arch images (linux/amd64, linux/arm64) to GHCR.

Agent binaries

Install the ACP agents you want to use:

npm install -g @github/copilot-language-server    # GitHub Copilot
npm install -g @openai/codex                       # OpenAI Codex (includes codex-acp)
npm install -g @agentclientprotocol/claude-agent-acp  # Claude
npm install -g pi-acp                              # Pi (ACP adapter)
npm install -g opencode-ai                         # OpenCode (free models)
npm install -g @mariozechner/pi-coding-agent       # Pi (native, for RPC mode)

Configuration

All configuration is via environment variables with VIBES_ prefix:

Variable Default Description
VIBES_HOST 0.0.0.0 Bind address
VIBES_PORT 8080 Port
VIBES_DB_PATH database/vibes.db SQLite database
VIBES_DEBUG false Verbose logging
VIBES_COPILOT_AGENT copilot-language-server --acp --stdio Copilot ACP command
VIBES_COPILOT_ENABLED true Enable Copilot backend discovery
VIBES_CODEX_AGENT codex-acp Codex ACP command
VIBES_CODEX_ENABLED true Enable Codex backend discovery
VIBES_DEFAULT_AGENT acp Default backend (acp is treated as copilot for compatibility)
VIBES_PI_ENABLED true Enable Pi native RPC discovery/probing (set false to disable)
VIBES_PI_AGENT pi Pi binary path
VIBES_PERMISSION_TIMEOUT 30 Permission request timeout (seconds)
VIBES_PERMISSION_AUTO_APPROVE false Auto-approve all tool calls
VIBES_DISCONNECT_TIMEOUT 300 Agent keepalive after last SSE client disconnects
VIBES_ACP_DEBUG false Wire-level ACP logging
VIBES_ACP_MCP_SERVERS_JSON (unset) JSON array of ACP MCP servers to pass to ACP sessions (stdio supported; http/sse filtered by negotiated agent capabilities)
VIBES_EXTENSIONS_DIR extensions Extension scan directory
VIBES_CORS_ALLOW_ORIGIN (unset) Enable CORS for a specific origin (or *)
VIBES_API_TOKEN (unset) Optional API token for sensitive/mutating routes (X-API-Token or Authorization: Bearer)
VIBES_ENABLE_TERMINAL false Enable terminal WebSocket endpoint (/terminal/ws)
VIBES_ENABLE_PPROF false Enable pprof endpoints under /debug/pprof (guarded by token when set)

See docs/CONFIGURATION.md for full reference, including ACP MCP server JSON examples and current ACP client-service limitations.

Security hardening (recommended for remote deployments)

# Require token auth on sensitive/mutating endpoints
export VIBES_API_TOKEN="change-me"

# Restrict browser CORS to your UI origin
export VIBES_CORS_ALLOW_ORIGIN="https://your-ui.example"

# Keep dangerous debug/shell surfaces disabled unless needed
export VIBES_ENABLE_TERMINAL=false
export VIBES_ENABLE_PPROF=false

Architecture

System diagram

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         Browser (SPA)                            β”‚
β”‚  Preact + HTM β”‚ CodeMirror 6 β”‚ KaTeX β”‚ Mermaid β”‚ SSE client     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚ HTTP + SSE
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                       Go HTTP Server (chi)                        β”‚
β”‚                                                                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”‚
β”‚  β”‚ Timeline β”‚ β”‚  Media   β”‚ β”‚Workspace β”‚ β”‚  Agents  β”‚           β”‚
β”‚  β”‚  Routes  β”‚ β”‚  Routes  β”‚ β”‚  Routes  β”‚ β”‚  Routes  β”‚           β”‚
β”‚  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜           β”‚
β”‚       β”‚             β”‚            β”‚             β”‚                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚              SQLite (WAL, FTS5, JSON columns)               β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚   SSE Broker  │◄──────►│         Agent Registry             β”‚  β”‚
β”‚  β”‚  (per-client  β”‚        β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”‚  β”‚
β”‚  β”‚   buffered    β”‚        β”‚  β”‚   ACP   β”‚  β”‚   Pi    β”‚         β”‚  β”‚
β”‚  β”‚   fanout)     β”‚        β”‚  β”‚Provider β”‚  β”‚Provider β”‚         β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜         β”‚  β”‚
β”‚                            β”‚       β”‚            β”‚               β”‚  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”‚  β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”         β”‚  β”‚
β”‚  β”‚  Extensions   β”‚        β”‚  β”‚  Subprocess Manager   β”‚         β”‚  β”‚
β”‚  β”‚  (registry)   β”‚        β”‚  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                    β”‚ stdio (JSON-RPC / NDJSON)
                   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                   β–Ό                β–Ό                β–Ό
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚copilot-lang- β”‚  β”‚  codex-acp β”‚  β”‚claude-agentβ”‚
          β”‚server --acp  β”‚  β”‚            β”‚  β”‚   -acp     β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                    β”‚
                            β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
                            β”‚   pi --mode    β”‚
                            β”‚     rpc        β”‚
                            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Request flow: user message β†’ agent response

1. User types message in compose box
2. Frontend POSTs to /agent/default/message
3. Server stores user message in SQLite
4. Server broadcasts "new_post" via SSE
5. Server spawns prompt on the active AgentProvider (async)
6. Agent streams events on stdout:
   - ACP: session/update notifications (draft/thought/tool_call)
   - Pi: NDJSON events (text_delta/thinking_delta/tool_execution)
7. Provider routes events β†’ SSE broker β†’ all connected clients
8. Frontend renders streaming draft/thought/status panels
9. Agent completes turn β†’ final response stored in SQLite
10. Server broadcasts "agent_response" via SSE
11. Frontend renders final message in timeline

Data flow: SSE event types

Server β†’ Client (text/event-stream):

  connected          Connection established
  new_post           User posted a message
  agent_draft        Streaming text from agent
  agent_thought      Agent thinking/reasoning stream
  agent_status       Tool call / status update
  agent_session_update  ACP session metadata/usage update
  agent_response     Final agent response (turn complete)
  agent_request      Permission request (approve/deny)
  agent_request_timeout  Permission timed out
  agent_error        Agent error
  interaction_updated    Post metadata changed
  interaction_deleted    Post removed

Implementation choices

Why Go

Concern Python (original) Go (this port)
Deployment virtualenv + pip + Python runtime Single static binary
Memory ~80 MB baseline (Python + aiohttp) ~15 MB baseline
Boot time 2–3s (Python import chain) <100 ms
Cross-compile Not practical Makefile targets such as make build-linux-arm64
Concurrency asyncio (single thread) Goroutines (multi-core)
SQLite binding C extension (requires build tools) Pure Go (modernc.org/sqlite)
Asset delivery Separate static directory Embedded via //go:embed
Container ~200 MB Python image ~24 MB scratch image

Why chi (not Gin/Fiber/Echo)

  • stdlib net/http compatible β€” works with any middleware
  • Minimal API surface, no framework lock-in
  • Context-based routing with URL parameters
  • No reflection, no code generation

Why modernc.org/sqlite (not go-sqlite3)

  • Pure Go β€” no CGo, no C compiler needed at build time
  • Enables CGO_ENABLED=0 for truly static binaries
  • Enables cross-compilation without C toolchain
  • Same SQLite feature set (WAL, FTS5, JSON functions, virtual columns)
  • ~10% slower than CGo version β€” acceptable for a single-user app

Why embed.FS (not external static directory)

  • Single binary deployment β€” copy one file, run it
  • No "missing static files" errors in production
  • Atomic updates (binary = code + assets together)
  • Same pattern as rcarmo/webterm
  • Trade-off: rebuild binary to update frontend (use make build)

ACP library: keepmind9/acp-sdk-go

  • Full typed schema for all ACP types (content blocks, tool calls, sessions)
  • ClientSideConnection with notification/request handlers
  • transport.Spawn for subprocess lifecycle
  • Contrib helpers: ToolCallTracker, PermissionBroker, SessionAccumulator
  • The only Go ACP SDK with schema parity as of April 2026

Extension system design

Inspired by piclaw's extension architecture:

type Extension interface {
    ID() string
    Name() string
    Version() string
    Init(ctx context.Context) error
    Shutdown(ctx context.Context) error
    Routes() []Route           // HTTP routes to mount
    EventTypes() []string      // SSE event types emitted
    StaticDir() string         // Static assets (/ext/{id}/)
    Manifest() *Manifest       // Frontend UI panels
}

type Manifest struct {
    Panels []PanelDef  // sidebar, main, overlay, toolbar
    CSS    []string    // CSS to inject
    JS     []string    // JS to load
}

Extensions can:

  • Register backend API routes (mounted on chi router)
  • Emit custom SSE event types
  • Serve static assets under /ext/{id}/
  • Declare frontend UI panels (sidebar, toolbar, overlays, main area)

Project structure

vibes/
β”œβ”€β”€ cmd/
β”‚   β”œβ”€β”€ vibes/main.go                 # Entry point
β”‚   └── acp-test/main.go             # ACP agent verification tool
β”œβ”€β”€ internal/
β”‚   β”œβ”€β”€ app/app.go                    # Application wiring (chi + DB + agents + SSE)
β”‚   β”œβ”€β”€ config/config.go              # Environment-based configuration
β”‚   β”œβ”€β”€ db/
β”‚   β”‚   β”œβ”€β”€ db.go                     # SQLite open + WAL + connection management
β”‚   β”‚   β”œβ”€β”€ migrations.go            # Schema v1 (interactions, media, whitelist, FTS5)
β”‚   β”‚   β”œβ”€β”€ queries.go               # Typed CRUD + search + whitelist
β”‚   β”‚   β”œβ”€β”€ db_test.go               # 11 unit tests
β”‚   β”‚   └── db_fuzz_test.go          # 3 fuzz targets
β”‚   β”œβ”€β”€ agent/
β”‚   β”‚   β”œβ”€β”€ provider.go              # Provider interface + Registry
β”‚   β”‚   β”œβ”€β”€ provider_test.go         # Registry tests
β”‚   β”‚   β”œβ”€β”€ acp/client.go            # ACP client (wraps acp-sdk-go)
β”‚   β”‚   └── pi/
β”‚   β”‚       β”œβ”€β”€ client.go            # Pi native RPC client
β”‚   β”‚       └── client_test.go       # Event routing tests
β”‚   β”œβ”€β”€ server/sse/
β”‚   β”‚   β”œβ”€β”€ broker.go                # SSE connection management + fanout
β”‚   β”‚   └── broker_test.go           # Subscribe/broadcast/HTTP tests
β”‚   β”œβ”€β”€ routes/
β”‚   β”‚   β”œβ”€β”€ timeline.go              # GET/POST/DELETE timeline, thread, search
β”‚   β”‚   β”œβ”€β”€ media.go                 # Upload, serve, thumbnail, info
β”‚   β”‚   β”œβ”€β”€ workspace.go             # Tree, file CRUD, rename, download, upload
β”‚   β”‚   β”œβ”€β”€ agents.go                # List, status, message, whitelist
β”‚   β”‚   β”œβ”€β”€ commands.go              # Slash commands (/model, /shell, etc.)
β”‚   β”‚   β”œβ”€β”€ opengraph.go             # Link preview fetcher
β”‚   β”‚   β”œβ”€β”€ permissions.go           # Permission broker + follow-up queue
β”‚   β”‚   β”œβ”€β”€ routes_test.go           # 12 route tests
β”‚   β”‚   β”œβ”€β”€ routes_fuzz_test.go      # Path traversal + parsing fuzz
β”‚   β”‚   β”œβ”€β”€ commands_test.go         # Command dispatch tests
β”‚   β”‚   └── permissions_test.go      # Queue + shell + permission tests
β”‚   └── extensions/
β”‚       β”œβ”€β”€ registry.go              # Extension discovery + lifecycle
β”‚       β”œβ”€β”€ registry_test.go         # Registration + manifest tests
β”‚       └── registry_fuzz_test.go    # ID fuzzing
β”œβ”€β”€ static/                           # Frontend (embedded at compile time)
β”‚   β”œβ”€β”€ index.html                    # SPA entry point
β”‚   β”œβ”€β”€ manifest.json                 # PWA manifest
β”‚   β”œβ”€β”€ css/styles.css                # Main stylesheet/base rules
β”‚   β”œβ”€β”€ css/components/               # Per-component CSS split-outs
β”‚   β”œβ”€β”€ dist/app.{js,css}            # Bundled frontend (Bun)
β”‚   β”œβ”€β”€ js/                           # Source modules (Preact + HTM)
β”‚   β”‚   β”œβ”€β”€ app.js                    # Root SPA component
β”‚   β”‚   β”œβ”€β”€ api.js                    # API client
β”‚   β”‚   β”œβ”€β”€ components/               # UI components
β”‚   β”‚   β”œβ”€β”€ panes/                    # Popout editor
β”‚   β”‚   └── vendor/                   # Vendored Preact, CodeMirror, KaTeX
β”‚   └── fonts/                        # KaTeX math fonts
β”œβ”€β”€ tests/features/*.feature          # BDD user stories (Gherkin)
β”œβ”€β”€ tests/steps/*.spec.mjs            # Playwright implementations (46 scenarios)
β”œβ”€β”€ config/endpoints.json             # Custom action definitions
β”œβ”€β”€ docs/                             # Protocol and integration docs
β”œβ”€β”€ embed.go                          # //go:embed all:static
β”œβ”€β”€ Dockerfile                        # Multi-stage: builder β†’ scratch
β”œβ”€β”€ Makefile                          # build, test, fuzz, lint, e2e, cross-compile
β”œβ”€β”€ playwright.config.mjs
β”œβ”€β”€ go.mod / go.sum
β”œβ”€β”€ GO_PORT.md                        # Architecture deep-dive
└── LICENSE                           # MIT

API endpoints

Method Endpoint Description
GET /health Health check
GET /timeline Paginated posts (newest first)
POST /post Create post
DELETE /post/{id} Delete post (optional cascade)
GET /thread/{id} Get thread
POST /thread Reply to thread
GET /search?q= Full-text search
POST /media/upload Upload media file
GET /media/{id} Serve media
GET /media/{id}/thumbnail Serve thumbnail
GET /media/{id}/info Media metadata
GET /workspace/tree File tree
GET /workspace/file?path= Read file content (includes mtime)
PUT /workspace/file Write file (optional optimistic-lock mtime)
DELETE /workspace/file?path= Delete file
POST /workspace/create Create file/directory
POST /workspace/rename Rename/move
GET /workspace/raw?path= Raw file download
GET /workspace/download?path= Download file/dir (ZIP)
POST /workspace/upload Upload to workspace
GET /agents List agents and backend provider metadata
GET /agent/providers Backend discovery/capability map
GET/POST /thread/{id}/backend Read or switch thread backend affinity
GET /agent/status Current agent state
GET /agent/context Context window usage
GET /agent/commands List slash commands
POST /agent/{id}/message Send message to agent
GET /agent/whitelist List permission patterns
POST /agent/whitelist Add pattern
DELETE /agent/whitelist Remove pattern
POST /agent/respond Respond to permission request
GET /avatar/{kind} Agent/user avatar
GET /sse/stream SSE event stream
GET /terminal/ws Terminal WebSocket (only when VIBES_ENABLE_TERMINAL=true)
GET /debug/pprof/* pprof profiling endpoints (only when VIBES_ENABLE_PPROF=true)

Development

make help            # Show all targets
make build           # Full build (frontend + Go binary)
make dev             # Run from source with debug logging
make serve           # Build and run
make test            # Unit tests
make race            # Race detector
make coverage        # Coverage report
make fuzz            # All 9 fuzz targets
make check           # lint + test + coverage
make test-acp        # Verify ACP agent handshakes
make e2e             # Playwright BDD UX suite + PDF report
make build-all       # Cross-compile (linux-amd64, linux-arm64, darwin-arm64)
make clean           # Remove artifacts

Test suite

Layer Tests Coverage
internal/config 3 unit + 3 fuzz 100%
internal/agent 6 unit 100%
internal/agent/pi 4 unit 20%
internal/extensions 7 unit + 1 fuzz 96%
internal/server/sse 4 unit 85%
internal/db 11 unit + 3 fuzz 79%
internal/routes 20 unit + 2 fuzz 41%
Total 55+ tests, 9 fuzz targets 52%

Plus 46 Playwright BDD scenarios for end-to-end UX validation.


Keyboard shortcuts

Shortcut Action
Cmd/Ctrl+S Save current editor tab
Cmd/Ctrl+F Search/replace in editor
Escape Close active editor tab
Alt+V Toggle Vim mode
Alt+W Toggle whitespace visibility
↑ / ↓ Cycle compose history

Python version

The original Python implementation (aiohttp, 388 unit tests, 34 E2E tests) is on the python branch:

pip install -U git+https://github.com/rcarmo/vibes.git@python

The Go and Python versions share the same frontend, API, SSE events, and SQLite schema β€” they are interchangeable.


License

MIT

About

A simple mobile-focused chat app to talk to an agent via the ACP protocol

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages