The codex backend spawns a long-running app-server process that doesn't exit after completing a turn. The lifecycle goroutine was waiting on <-readerDone which blocks on scanner.Scan() until stdout closes — but stdout never closes because the process stays alive. This caused the entire poll loop to freeze, preventing any further task processing. Fix: explicitly close stdin and cancel the context after the turn completes, which terminates the codex process and unblocks the reader. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .github/workflows | ||
| apps/web | ||
| e2e | ||
| packages | ||
| scripts | ||
| server | ||
| .env.example | ||
| .gitignore | ||
| .npmrc | ||
| CLAUDE.md | ||
| docker-compose.yml | ||
| Makefile | ||
| package.json | ||
| playwright.config.ts | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| tsconfig.base.json | ||
| turbo.json | ||
Multica
AI-native task management platform — like Linear, but with AI agents as first-class citizens.
Prerequisites
Quick Start
# 1. Install dependencies
pnpm install
# 2. Copy environment variables for the shared main environment
cp .env.example .env
# 3. One-time setup: start DB and run migrations
make setup
# 4. Optional: load example data
make seed
# 5. Start backend + frontend
make start
Open your configured FRONTEND_ORIGIN in the browser. By default that is http://localhost:3000.
Default behavior now prefers the shared main environment in .env. If you want an isolated environment for a Git worktree, generate .env.worktree and use the explicit worktree targets:
make worktree-env
make setup-worktree
make start-worktree
This lets you keep .env connected to your main database while using .env.worktree only for isolated feature testing.
Project Structure
├── server/ # Go backend (Chi + sqlc + gorilla/websocket)
│ ├── cmd/ # server, daemon, migrate, seed
│ ├── internal/ # Core business logic
│ ├── migrations/ # SQL migrations
│ └── sqlc.yaml # sqlc config
├── apps/
│ └── web/ # Next.js 16 frontend
├── packages/ # Shared TypeScript packages
│ ├── ui/ # Component library (shadcn/ui + Radix)
│ ├── types/ # Shared type definitions
│ ├── sdk/ # API client SDK
│ ├── store/ # State management
│ ├── hooks/ # Shared React hooks
│ └── utils/ # Utility functions
├── Makefile # Backend commands
├── docker-compose.yml # PostgreSQL + pgvector
└── .env.example # Environment variable template
Commands
Frontend
| Command | Description |
|---|---|
pnpm dev:web |
Start Next.js dev server (uses FRONTEND_PORT, default 3000) |
pnpm build |
Build all TypeScript packages |
pnpm typecheck |
Run TypeScript type checking |
pnpm test |
Run TypeScript tests |
Backend
| Command | Description |
|---|---|
make dev |
Run Go server (uses PORT, default 8080) |
make daemon |
Run local agent daemon |
make test |
Run Go tests |
make build |
Build server & daemon binaries |
make sqlc |
Regenerate sqlc code from SQL |
Database
| Command | Description |
|---|---|
docker compose up -d |
Start PostgreSQL |
docker compose down |
Stop PostgreSQL |
make migrate-up |
Run database migrations |
make migrate-down |
Rollback database migrations |
make seed |
Seed example data |
make worktree-env |
Generate an isolated .env.worktree for the current worktree |
make setup-main / make start-main |
Force use of the shared main .env |
make setup-worktree / make start-worktree |
Force use of isolated .env.worktree |
Environment Variables
See .env.example for all available variables:
DATABASE_URL— PostgreSQL connection stringCOMPOSE_PROJECT_NAME— Docker Compose project namePOSTGRES_DB/POSTGRES_PORT— Per-worktree PostgreSQL database and host portPORT— Backend server port (default: 8080)FRONTEND_PORT/FRONTEND_ORIGIN— Frontend port and browser originJWT_SECRET— JWT signing secretMULTICA_APP_URL— Browser origin used when generating local runtime pairing linksMULTICA_DAEMON_CONFIG— Optional path for the daemon's persisted local configMULTICA_WORKSPACE_ID— Optional dev override for the workspace id; normal usage should rely on browser pairing insteadMULTICA_DAEMON_ID/MULTICA_DAEMON_DEVICE_NAME— Stable daemon identity for local runtime registrationMULTICA_CODEX_PATH/MULTICA_CODEX_MODEL— Codex executable and optional model override for local task executionMULTICA_CODEX_WORKDIR— Default working directory used by the local Codex runtimeGOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET— Google OAuth (optional)NEXT_PUBLIC_API_URL— Frontend → backend API URLNEXT_PUBLIC_WS_URL— Frontend → backend WebSocket URL
Local Codex Daemon
The local daemon currently supports one local runtime type: codex.
- Start the daemon with
make daemon. - If the daemon does not already know its workspace, it prints a pairing link in the terminal.
- Open that link in the browser, sign in, and choose the workspace that should own the local Codex runtime.
- The daemon stores the approved workspace locally in
MULTICA_DAEMON_CONFIGor~/.multica/daemon.json. - The daemon registers the local Codex runtime via
/api/daemon/register. - Create an agent in Multica and bind it to that runtime.
- Assign an issue to the agent and move the issue to
todo. - The daemon claims the task, runs
codex exec, and reports the final comment back to the issue.
For local development you can still set MULTICA_WORKSPACE_ID directly to skip pairing, but that should be treated as a debug shortcut rather than the normal flow.