AI-powered coding assistant for local-first development workflows.
CLI, TUI, desktop app, embeddable server, web UI, ACP adapter, and reusable SDK packages — all in one Bun monorepo.
Otto Canvas is a native desktop app (Tauri + React) that gives you a persistent, tiled workspace for AI-powered development. It is the flagship way to use otto and the primary interface going forward.
Canvas turns your screen into a composable surface where every block is a first-class tool:
| Block | What it is | Powered by |
|---|---|---|
| Terminal | Native terminal with full GPU rendering | Ghostty libghostty via Tauri |
| Browser | Inline web preview for localhost or any URL | Native macOS WKWebView |
| Otto | AI chat with full tool access to your repo | otto serve runtime per workspace |
| Claude Code | Launch Claude Code in a Ghostty surface | Ghostty command preset |
| Codex | Launch OpenAI Codex in a Ghostty surface | Ghostty command preset |
| Otto TUI | Run the otto TUI inside Canvas | Ghostty command preset |
| OpenCode | Launch OpenCode in a Ghostty surface | Ghostty command preset |
| Custom command | Run any shell command in a terminal block | Ghostty command preset |
- Multi-workspace — each workspace is linked to a project path; Canvas auto-starts an
otto serveruntime per workspace - Tabbed canvas with splits — create Canvas tabs with horizontal/vertical splits, or open any block type as a standalone tab
- Keyboard-first —
⌘Nadd block,⌘Tnew tab,⌘Dsplit right,⌘⇧Dsplit down,⌘1-9switch tabs,Ctrl+H/J/K/Lvim-style focus navigation - Workspace file — export/import your layout, tabs, and automation as
otto.yamlso teammates share identical surfaces - Native performance — Ghostty terminal blocks run via libghostty with native macOS rendering; browser blocks use WKWebView — no Electron overhead
- Per-workspace otto runtime — each workspace auto-launches
otto serve --no-openso every Otto block has full tool access scoped to that project - macOS vibrancy — transparent, blur-backed window chrome via
NSVisualEffectMaterial
cd apps/canvas
bun install
bun tauri devOr build a distributable .app / .dmg:
bun tauri buildotto is a local-first coding assistant that runs on your machine, connects to multiple AI providers, and gives models controlled access to your repo through built-in tools like file IO, search, patching, git, terminals, web fetch, skills, and task tracking.
It ships in several forms:
- Canvas (primary) — native Tauri desktop app with tiled terminals, browsers, AI chat, and multi-agent surfaces
- CLI —
ottofor interactive or one-shot usage - TUI — terminal-first interface used by the default CLI flow
- Web UI — browser client for the local otto server
- Desktop app — lightweight Tauri wrapper around the web UI
- Embeddable server — Hono-based API you can host inside your own app
- SDK packages — auth, config, providers, tools, prompts, API client, web UI assets
- ACP adapter — integrate otto with ACP-capable editors and tools
The compiled CLI bundles the server, database, web UI assets, and runtime into a single executable.
curl -fsSL https://install.ottocode.io | shOr install the npm helper package with Bun:
bun install -g @ottocode/installThat downloads the correct prebuilt binary for your platform.
otto # start interactive TUI (default)
otto --web # start local API + web UI and open browser
otto "explain this stack trace"
otto "write tests" --agent build
otto "review the architecture" --agent plan
otto "research this codebase" --agent research
otto --last "continue"
otto serve # run API + web UI explicitly
otto serve --port 3000 # API on :3000, web UI on :3001
otto serve --network # bind API/web UI for LAN accessUseful companion commands:
otto setup
otto auth login
otto auth list
otto doctor
otto sessions
otto models
otto agents
otto tools
otto mcp list
otto scaffoldotto supports multiple providers through AI SDK v6 and first-party adapters.
Common environment variables:
export ANTHROPIC_API_KEY="sk-ant-..."
export OPENAI_API_KEY="sk-..."
export GOOGLE_GENERATIVE_AI_API_KEY="..."
export OPENROUTER_API_KEY="..."
export OPENCODE_API_KEY="..."
export SETU_PRIVATE_KEY="..." # Solana wallet private key (base58)
export MOONSHOT_API_KEY="..."
export MINIMAX_API_KEY="..."
export ZAI_API_KEY="..."
export ZAI_CODING_API_KEY="..."See docs/environment.md for the verified env var list.
Current exported presets from @ottocode/server:
| Agent | Purpose | Default tool profile |
|---|---|---|
build |
code changes, fixes, implementation | full patch/search/shell flow |
plan |
analysis and planning | mostly read/search/task tools |
general |
mixed-purpose assistant | broad default workspace tools |
research |
cross-session and web research | read/search/web + research DB tools |
All runtime agents also include progress_update, finish, and skill.
Project/global overrides live in:
.otto/agents.json~/.config/otto/agents.json
Prompt files scaffold to flat paths like .otto/agents/<name>.md.
Core runtime tool surface includes:
This is the full built-in tool universe. Individual agents only get the subset they need via their preset or config overrides.
| Category | Tools |
|---|---|
| File system | read, write, ls, tree, pwd, cd, glob |
| Search | ripgrep, websearch |
| Editing | apply_patch |
| Shell/runtime | bash, terminal |
| Git | git_status, git_diff, git_commit |
| Agent control | update_todos, progress_update, finish, skill |
| Research | query_sessions, query_messages, get_session_context, search_history, get_parent_session, present_action |
otto supports MCP servers over stdio, HTTP, and SSE.
Started MCP servers expose tools like server__tool at runtime. Those tools are
separate from the built-in agent presets and come from the connected MCP server.
otto mcp add helius --command npx --args -y helius-mcp@latest
otto mcp add linear --transport http --url https://mcp.linear.app/mcp
otto mcp list
otto mcp auth linearSee docs/mcp.md.
Custom tools are plugin folders discovered from either:
.otto/tools/<tool-name>/tool.js.otto/tools/<tool-name>/tool.mjs~/.config/otto/tools/<tool-name>/tool.js~/.config/otto/tools/<tool-name>/tool.mjs
Example:
// .otto/tools/file-size/tool.js
export default {
name: 'file_size',
description: 'Return the byte size for a file path',
parameters: {
path: {
type: 'string',
description: 'Path to inspect',
},
},
async execute({ input, fs }) {
const content = await fs.readFile(input.path, 'utf8');
return { bytes: Buffer.byteLength(content, 'utf8') };
},
};The skill tool loads markdown instruction bundles on demand.
Skill sources:
- built-in bundled skills
.otto/skills/.agents/skills/~/.config/otto/skills/~/.agents/skills/
Compatibility aliases also supported:
.agenst/skills/~/.agenst/skills/
Use otto skills to inspect available skills.
Global config lives under ~/.config/otto/.
Project config lives under .otto/.
Secrets do not live in the global config directory anymore. Auth is stored in secure OS-specific locations:
| Platform | Secure auth path |
|---|---|
| macOS | ~/Library/Application Support/otto/auth.json |
| Linux | $XDG_STATE_HOME/otto/auth.json or ~/.local/state/otto/auth.json |
| Windows | %APPDATA%/otto/auth.json |
See docs/configuration.md for the full layout.
Current workspaces under apps/:
apps/canvas— Otto Canvas (primary desktop app — Tauri + Ghostty + React)apps/cliapps/desktopapps/intro-videoapps/landingapps/launcherapps/mobileapps/preview-apiapps/preview-webapps/tuiapps/web
Current workspaces under packages/:
@ottocode/acp@ottocode/ai-sdk@ottocode/api@ottocode/database@ottocode/install@ottocode/openclaw-setu@ottocode/sdk@ottocode/server@ottocode/web-sdk@ottocode/web-ui
SST currently wires these modules from infra/:
infra/scriptinfra/landinginfra/preview-apiinfra/preview-webinfra/og
See docs/architecture.md.
The server exposes:
/— root text response/openapi.json— generated OpenAPI document/v1/*— operational API routes
Example route groups include ask, auth, config, doctor, files, git, mcp, provider-usage, research, sessions, setu, shares, skills, terminals, and tunnel.
See docs/api.md. packages/api/openapi.json is the source of truth for clients.
Use the server directly:
import { createEmbeddedApp } from '@ottocode/server';
import { serveWebUI } from '@ottocode/web-ui';
const api = createEmbeddedApp({
provider: 'anthropic',
model: 'claude-sonnet-4',
apiKey: process.env.ANTHROPIC_API_KEY,
agent: 'build',
});
const web = serveWebUI({ prefix: '/ui' });
Bun.serve({
port: 3456,
idleTimeout: 240,
async fetch(req) {
return (await web(req)) ?? api.fetch(req);
},
});git clone https://github.com/nitishxyz/otto.git
cd otto
bun install
bun lint
bun test
bun run typecheck
bun run compileUseful dev commands:
bun run dev:cli
bun run --filter @ottocode/tui dev
bun run dev:web
bun run dev:desktop
bun sst devSee docs/development.md and docs/development-guide.md.
- Getting Started
- Usage Guide
- Configuration
- Agents & Tools
- MCP
- API
- Architecture
- Embedding Guide
- Development
- Docs Index
See AGENTS.md.
Key repo conventions:
- Bun for installs, scripts, builds, and tests
- Biome for lint/format checks
bun:testfor tests- TypeScript strict mode
- minimal focused changes