Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Development Commands

```bash
# Core development
bun install # install dependencies
bun dev # run opencode TUI (in packages/opencode dir)
bun dev <directory> # run against specific directory
bun dev . # run in repo root

# Type checking
bun turbo typecheck # typecheck all packages

# Building
./packages/opencode/script/build.ts --single # build standalone executable

# Web app (packages/app)
bun run --cwd packages/app dev # dev server at localhost:5173

# Desktop app (packages/desktop) - requires Tauri/Rust
bun run --cwd packages/desktop tauri dev # native app + dev server
bun run --cwd packages/desktop tauri build # production build

# SDK regeneration (after API changes)
./packages/sdk/js/script/build.ts # regenerate JS SDK
./script/generate.ts # regenerate SDK and related files
```

## Architecture

**Monorepo** using Bun workspaces with Turbo for task orchestration.

**Key packages:**
- `packages/opencode` - Core CLI, server, and TUI (main business logic)
- `packages/app` - Web UI components (SolidJS)
- `packages/desktop` - Native desktop app (Tauri v2 wrapping app)
- `packages/console` - Cloud SaaS (Cloudflare Workers, PlanetScale)
- `packages/sdk` - TypeScript SDK (@opencode-ai/sdk)
- `packages/plugin` - Plugin system (@opencode-ai/plugin)

**Client-Server model:**
- HTTP server (`packages/opencode/src/server/server.ts`) built on Hono
- TUI client (`packages/opencode/src/cli/cmd/tui/`) using SolidJS + OpenTUI
- Sessions, tools, and LLM requests flow through the server

**Agent system** (`packages/opencode/src/agent/`):
- `build` - default agent with full access
- `plan` - read-only for analysis/exploration
- `general` - subagent for complex searches (invoke with @general)

**Tool system** (`packages/opencode/src/tool/`): 40+ tools (bash, edit, read, grep, glob, write, lsp, etc.) with permission checks and plugin extensibility.

**Provider system** (`packages/opencode/src/provider/`): 20+ LLM providers via ai SDK (Claude, OpenAI, Google, Bedrock, etc.)

## Code Style

- Prefer `const` over `let`; use ternary or early returns to avoid mutation
- Avoid `else` statements; use early returns
- Avoid unnecessary destructuring; prefer `obj.a` over `const { a } = obj` for context
- Prefer `.catch()` over try/catch
- Single-word variable names when descriptive enough
- Use Bun APIs (e.g., `Bun.file()`) when available
- Avoid `any` type

## Git/PR Guidelines

- Default branch: `dev`
- All PRs must reference an existing issue (`Fixes #123` or `Closes #123`)
- Conventional commits: `feat:`, `fix:`, `docs:`, `chore:`, `refactor:`, `test:`
- Optional scope: `feat(app):`, `fix(desktop):`
- Keep PRs small and focused; no AI-generated walls of text
- UI changes need screenshots/videos

## Important Notes

- ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE
- After API/SDK changes in server.ts, run `./script/generate.ts`
- Tests run from individual packages, not root (`bun run test` from root will fail)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "AI-powered development tool",
"private": true,
"type": "module",
"packageManager": "[email protected].5",
"packageManager": "[email protected].6",
"scripts": {
"dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts",
"typecheck": "bun turbo typecheck",
Expand Down
32 changes: 32 additions & 0 deletions packages/opencode/IMPLEMENTATION_PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
title: Rotation plan
description: Steps for email checks and account switching

---

## Define config

Add `experimental.codex.rotation` with `first` (default) and `round-robin` in `src/config/config.ts`. Keep it relaxed and obvious in config docs or inline descriptions.

---

## Validate email

Require a non-empty email in OAuth results and fail the login if missing in `src/cli/cmd/auth.ts` and `src/plugin/codex.ts`. Also guard `Auth.setCodexAccount` to reject empty emails and avoid overwriting accounts with `unknown` values.

---

## Handle limits

Persist `rateLimit` metadata until `resetAt` passes, and only clear on expiry in `src/auth/index.ts`. Make `auth list` tolerant of missing `resetAt` when rendering status in `src/cli/cmd/auth.ts`.

---

## Add round robin

Extend `Auth.getNextAvailableCodexAccount` with a mode argument and store the next index after selection. Use config in `src/plugin/codex.ts` to choose `first` or `round-robin` when retrying after a 429.

---

## Verify

Manually login two accounts and confirm both emails render in `auth list`. Trigger a 429 and confirm automatic switch plus correct strategy by toggling config.
13 changes: 7 additions & 6 deletions packages/opencode/bin/opencode
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#!/usr/bin/env node

const childProcess = require("child_process")
const fs = require("fs")
const path = require("path")
const os = require("os")
import { spawnSync } from "node:child_process"
import fs from "node:fs"
import os from "node:os"
import path from "node:path"
import { fileURLToPath } from "node:url"

function run(target) {
const result = childProcess.spawnSync(target, process.argv.slice(2), {
const result = spawnSync(target, process.argv.slice(2), {
stdio: "inherit",
})
if (result.error) {
Expand All @@ -22,7 +23,7 @@ if (envPath) {
run(envPath)
}

const scriptPath = fs.realpathSync(__filename)
const scriptPath = fs.realpathSync(fileURLToPath(import.meta.url))
const scriptDir = path.dirname(scriptPath)

const platformMap = {
Expand Down
Loading