Esta página está em português. A versão em inglês é a referência principal quando houver divergência.
CLI Runtime Architecture
The CLI (packages/opencode/) is CFactory's local agent engine. It owns agent execution, tools, sessions, provider integration, configuration, local persistence, directory routing, and HTTP surfaces used by editor clients and CFactory Console.
This page describes repository-defined local runtime behavior. It is not an endpoint catalog or a statement about cloud deployment configuration.
Concepts
These terms describe local execution. They are separate from hosted Cloud Agent sessions described in Cloud Platform.
| Term | Meaning |
|---|---|
| CFactory CLI runtime | Local agent engine in packages/opencode/ |
cfactory serve server | Local HTTP and SSE process used by editor clients and CFactory Console; selected browser-oriented paths also use WebSocket |
| Local daemon | Detached reusable cfactory serve server managed by cfactory daemon commands |
| Directory context | Normalized local filesystem directory used to select local runtime state |
| Local runtime instance | Directory-keyed runtime context inside one CFactory CLI process |
| Local routing workspace | Optional routing context that can resolve to a local directory or remote target |
| Worktree directory | Alternate git worktree path used as directory context for isolated concurrent work |
| Process-shared state | Runtime service state shared by every directory context in one CFactory CLI process |
| Modes | Configurable agent presets for tools, prompts, restrictions, and behavior |
| MCP | Protocol for extending agent tools |
One cfactory serve process can host several local runtime instances. Directory-keyed state stays isolated. Process-shared service state does not.
Command entry points
| Entry point | Command or caller | Runtime model |
|---|---|---|
| Interactive TUI | cfactory | Attaches to local daemon when available; otherwise starts Bun worker and sends SDK-shaped requests over RPC |
| Headless run | cfactory run | Uses daemon attach when available, then embedded server fetch fallback |
| Attached run | cfactory run --attach <url> | Targets explicit running cfactory serve server |
| Explicit API server | cfactory serve | Starts HTTP + SSE server for external local clients |
| Local daemon | cfactory daemon start | Starts detached cfactory serve child for reuse |
| Browser console | cfactory console | Starts or reuses local daemon and opens daemon-served /console UI |
TUI fallback is not direct call from UI thread to embedded fetch. UI thread starts worker.ts; worker RPC method constructs request, calls Server.Default().app.fetch(), and forwards global events back to UI thread.
One server with multiple directory contexts
Each running editor host starts one editor-owned cfactory serve server. That server can handle coding sessions for workspace root and additional worktree directories at same time. It does not start separate server process for each directory.
| Step | What happens | Why it matters |
|---|---|---|
| Send request | Editor client includes directory with local API request | CLI can distinguish workspace root from worktree directory |
| Select state | InstanceStore normalizes directory and selects directory-keyed local runtime instance | Sessions for alternate directories keep isolated runtime state |
| Return events | Server publishes event with directory metadata through shared /global/event SSE stream | Editor client routes event to matching directory and session view |
Authentication boundaries
Three credential boundaries coexist. Keep them separate when tracing request path or changing authentication code.
| Boundary | Protects | Owner |
|---|---|---|
Local cfactory serve access | HTTP, SSE, and selected WebSocket access to local server | CFactory CLI server and spawning local client |
| Outbound provider authentication | Model provider, CFactory Gateway, catalog, and indexing access | CFactory CLI provider router and auth stores |
| Remote MCP OAuth | Browser authorization and credentials for remote MCP server | CFactory CLI MCP runtime |
Local cfactory serve access
Server Basic Auth is optional. It becomes required when CFACTORY_SERVER_PASSWORD is non-empty. Default username is cfactory; CFACTORY_SERVER_USERNAME can override it.
| Path or mode | Authentication behavior |
|---|---|
| Normal HTTP and SSE | Basic Authorization header when server password is configured |
| Browser WebSocket | auth_token query parameter accepts base64 username:password because browser WebSocket constructors cannot set arbitrary headers |
| Public UI assets | Selected manifest and icon GET paths bypass Basic Auth so browser metadata can load |
| PTY ticket issue | Authenticated POST /pty/{ptyID}/connect-token requires expected ticket header and allowed origin |
| PTY ticket connect | GET /pty/{ptyID}/connect?ticket=... bypasses Basic middleware, then consumes single-use, scope-bound ticket in PTY handler |
| PTY shell child | Removes CFACTORY_SERVER_PASSWORD and CFACTORY_SERVER_USERNAME from spawned user-shell environment |
PTY connect supports two browser-oriented modes: loopback query credential mode (auth_token) used by current Console and VS Code Agent Manager paths, and short-lived ticket mode exposed by server API.
Outbound provider authentication
Provider auth records use api, oauth, or wellknown variants in ${Global.Path.data}/auth.json, written with mode 0600. CFACTORY_AUTH_CONTENT can supply process-local auth JSON. Separate v2 multi-account auth store also exists for account-oriented flows.
| Path | Behavior |
|---|---|
| Direct providers | Use provider-specific keys, OAuth records, environment values, and configured endpoints |
| CFactory Gateway | Resolves CFactory model access and model catalog through gateway client |
| Anonymous CFactory | If no CFactory key exists, provider loader sets API key value anonymous; gateway model catalog can fall back to public unauthenticated endpoint |
| Organization catalog | CFactory model fetch includes organization ID when resolved from config, auth, or environment |
| Model cache | Caches provider model results for five minutes; failed loads invalidate cache for retry |
| Custom endpoints | Provider config can override endpoint and credential options |
| Indexing auth | Resolves indexing-specific CFactory config first, then provider config, auth record, provider options, and CFACTORY_API_KEY / CFACTORY_ORG_ID environment values |
Remote MCP OAuth
Remote MCP OAuth belongs to CLI runtime. Static headers remain supported. For OAuth servers, CLI handles browser authorization and stores credentials in protected local state; editor clients invoke CLI-owned flow instead of storing MCP credentials themselves.
Directory routing and local runtime instances
Instance routes select directory context in this order:
directoryquery parameter.x-cfactory-directoryrequest header.- Server process cwd.
Local routing workspace selection is separate. Session workspace, workspace query parameter, and CFACTORY_WORKSPACE_ID can select workspace context. Configured CFACTORY_WORKSPACE_ID keeps requests local to current workspace runtime. Other selected workspaces resolve through workspace-routing adapter to local directory or remote target.
| Request plan | Behavior |
|---|---|
| Local | Provides resolved directory and optional workspace ID to request handlers |
| Remote | Proxies HTTP or WebSocket request to adapter target |
| Missing workspace | Returns workspace-not-found response |
| Workspace-routing local | Keeps selected local routes and /console on local server instead of proxying |
Remote HTTP proxy responses can include sync fence metadata. Router waits for matching sync progress before returning. InstanceStore normalizes directory keys, deduplicates concurrent boots with deferred entry, and disposes directory state through registered cleanup hooks.
Core subsystems
| Subsystem | Purpose |
|---|---|
| Agent runtime | Orchestrates messages, model calls, permissions, questions, and multi-step execution |
| Tool registry | Loads built-in, CFactory-specific, MCP, and readiness-gated semantic search tools |
| LSP client | Provides diagnostics and language intelligence |
| Config service | Merges global, project, organization, managed, and runtime inputs |
| Instance store | Caches normalized directory-scoped runtime contexts |
| SQLite and storage services | Persist structured records and remaining JSON-owned data |
| Snapshot service | Tracks git-backed file baselines for diffs and revert flows |
| Provider router | Resolves direct providers, CFactory Gateway, custom endpoints, and credentials |
| HTTP server | Publishes REST, WebSocket, and SSE surfaces |
Daemon lifecycle
cfactory daemon start|status|stop|restart manage detached local cfactory serve child. cfactory console calls same start path, so it reuses healthy daemon instead of spawning second process.
| Area | Behavior |
|---|---|
| State file | ${Global.Path.state}/daemon.json, written with mode 0600 |
| Log file | ${Global.Path.log}/daemon.log, created with mode 0600 |
| Port allocation | For --port 0, scans 4097..4116 and chooses available port |
| Child process | Detached cfactory serve --hostname <host> --port <port> process |
| Health | Probes authenticated /global/health with 2 second timeout |
| Reuse | Reuses daemon only when process is alive, health succeeds, and installed version matches |
| Cleanup | Terminates stale process when present, clears stale state, then starts replacement |
| Opt-out | CFACTORY_NO_DAEMON disables automatic attach by clients; explicit daemon commands still manage daemon |
Daemon credentials differ from editor-spawned server credentials. Current daemon source stores username cfactory, password cfactory, and base64 Basic token in daemon.json. File permissions protect this local credential record. Editor clients generate random passwords per spawned server.
Persistence
SQLite is default structured store.
| Area | Behavior |
|---|---|
| Default database | ${Global.Path.data}/cfactory.db |
| Override | CFACTORY_DB; relative paths resolve under data directory; :memory: is accepted |
| Runtime pragmas | WAL journal, normal sync, 5 second busy timeout, foreign keys, passive checkpoint, bounded cache |
| Schema changes | Drizzle migrations load from bundled journal in compiled binary or migration directories in development |
| Main tables | Projects, sessions, messages, parts, todos, permissions, session messages, workspaces, sync events, accounts, and account state |
| Legacy migration | On first database creation, CLI runs one-time JSON-to-SQLite migration for projects, sessions, messages, parts, todos, permissions, and shares |
Some JSON-backed storage remains. Session diffs still use storage path session_diff, and configuration, auth, and selected local state files retain their own owners. Snapshot storage is separate from SQLite and JSON storage.
Snapshot state boundary
Snapshot baselines use separate git directory per project worktree:
${Global.Path.data}/snapshot/<project-id>/<worktree-hash>
Snapshot implementation state is directory-keyed through InstanceState. One Snapshot.Service also owns process-shared slow-snapshot guard state outside directory cache. This distinction matters when multiple Agent Manager worktrees use same cfactory serve process.
Slow initial tracking has guarded behavior:
| Condition | Behavior |
|---|---|
| Fast track | Returns snapshot hash normally |
| Slow interactive track | After default 10 seconds, can prompt to keep waiting or disable snapshots for project |
| Managed Agent Manager turn | Sends snapshotInitialization: "wait"; waits without inline question so concurrent started sessions retain baselines |
| Visible long track | Adds temporary progress part after short delay, updates spinner, and removes part when done |
| Disable choice | Writes "snapshot": false to project config without disposing active turn |
| Dismissed or untargeted timeout | Interrupts or skips track and suppresses repeat prompt for active service scope |
SDK contract
CLI server contract flows through generated and handwritten layers:
- Effect
HttpApigroups underpackages/opencode/src/server/routes/instance/httpapi/define routes. packages/opencode/src/server/routes/instance/httpapi/public.tsnormalizes public OpenAPI to legacy-compatible request and response shapes.- CFactory-specific API groups and handlers live under
packages/opencode/src/cfactory/server/httpapi/and enter shared API through narrow injection seams. packages/sdk/js/script/build.tsgenerates TypeScript v2 client from CLI OpenAPI.packages/sdk/js/src/v2/client.tsaddscreateCFactoryClient()wrapper for directory and workspace routing, Electron and Node fetch compatibility, and clearer empty-response errors.- Root
./script/generate.tsruns SDK generation, emits tracked OpenAPI artifact, updates CLI docs, and formats outputs.
Regenerate checked-in JavaScript SDK output after server endpoint changes. Do not hand-edit generated client files.
Config precedence
Later sources override earlier values during instance config load:
| Order | Source |
|---|---|
| 1 | Legacy CFactory migrations |
| 2 | Organization modes |
| 3 | Auth-record .well-known/opencode remote config |
| 4 | Global config files |
| 5 | Explicit CFACTORY_CONFIG file |
| 6 | Project cfactory.json[c] and cfactory.json[c] files plus discovered config directories |
| 7 | CFACTORY_CONFIG_DIR directory |
| 8 | CFACTORY_CONFIG_CONTENT |
| 9 | Active CFactory Cloud organization config |
| 10 | Managed config directory |
| 11 | macOS managed preferences |
| 12 | Runtime flag-derived permission, tool, compaction, and plugin behavior |
Global config files load from ${Global.Path.config}. Project updates prefer existing config files found in ancestor .cfactory, .cfactory, or .opencode directories, then existing project root config files, then create .cfactory/cfactory.json. Global indexing settings can carry provider and storage defaults, but global indexing.enabled is stripped so project enablement remains local in effective instance config.
Signed-in organization modes become normal agent configuration during load. They override migrated legacy modes and remain overridable by later config sources in table.
Runtime config loading is separate from editor-facing JSON Schema publication. Cloud-served schema improves validation and completion for cfactory.json and cfactory.jsonc; it does not load, apply, or override effective runtime config. When adding or changing config key, follow CLI Config Schema so CLI source and cloud overlay stay aligned.
Global and instance SSE
| Stream | Scope | Payload |
|---|---|---|
/event | One local runtime instance bus | Direct event payloads until instance disposal |
/global/event | Process-wide multiplexed bus | Wrapper with payload and available directory, project, and workspace metadata |
CFactory Console
cfactory console starts or reuses daemon, opens /console, and prints Console launch URL. Browser launch URL embeds daemon Basic credentials so initial request authenticates.
| Area | Behavior |
|---|---|
| Frontend | Solid/Vite app in packages/cfactory-console/ |
| Server route | /console assets resolved by CLI UI handler |
| Release build | CLI executable build copies Console assets beside binary under bin/console |
| SDK | Console calls generated JavaScript SDK through createCFactoryClient() |
| Discovery | Console scans 4097..4116 loopback daemon URLs, ranks healthy hits, then tries cached URL fallback |
Source development can serve built Console assets from package output or build them on demand. This is development behavior, not production deployment claim.
Codebase indexing
packages/cfactory-indexing/ owns indexing engine. CLI bridge injects indexing plugin by default unless default plugins are disabled, then starts indexing asynchronously per normalized directory during instance bootstrap.
| Area | Behavior |
|---|---|
| Bootstrap | CFactoryBootstrap forks indexing initialization so instance startup is not blocked |
| Worker | Dedicated indexing worker owns CodeIndexManager and search calls |
| Cache | CLI bridge caches worker entry by directory and disposes it with instance |
| Status | GET /indexing/status and indexing.status bus event expose progress |
| Tool | semantic_search is registered only after indexing reports readiness |
| Worktrees | Agent Manager .cfactory/worktrees/ and legacy .cfactory/worktrees/ paths return disabled status |
| Empty VS Code window | Extension sets CFACTORY_DISABLE_CODEBASE_INDEXING=vscode-no-workspace; bridge reports disabled status |
| Embeddings | Supports CFactory, OpenAI, Ollama, OpenAI-compatible, Gemini, Mistral, Vercel AI Gateway, Bedrock, OpenRouter, and Voyage configuration |
| Vector stores | Supports Qdrant and LanceDB |
Source map
Paths below are relative to AP-DIGITAL-SERVICES/cfly-factory.
| Concern | Source paths |
|---|---|
| CLI entry points | packages/opencode/src/cli/cmd/ |
| Daemon | packages/opencode/src/cfactory/daemon/ |
| HTTP server | packages/opencode/src/server/ |
| Directory and workspace routing | packages/opencode/src/server/routes/instance/httpapi/middleware/workspace-routing.ts |
| SQLite | packages/opencode/src/storage/db.ts |
| Snapshots | packages/opencode/src/snapshot/index.tspackages/opencode/src/cfactory/snapshot/track.ts |
| SDK | packages/sdk/js/script/generate.ts |
| Console | packages/cfactory-console/packages/opencode/src/cfactory/console/ |
| Indexing | packages/cfactory-indexing/packages/opencode/src/cfactory/indexing.ts |
Related pages
- Architecture Overview - local and hosted execution map
- VS Code Extension - extension-host ownership, Agent Manager, and webview bridge
- Development Patterns - API generation, code-ownership seams, and fork-maintenance rules
- CLI Config Schema - editor validation contract for CLI config keys