Carina is a local-first runtime layer for AI coding agents. It is not an editor, a chat app, or a hosted sandbox. It sits between an agent and the machine, so file reads, edits, commands, network access, plugins, and secrets go through explicit policy before they happen.
The current repository is useful for source builds, local experimentation, and teams designing their own agent execution substrate. It is still alpha. Public macOS packages are available through the Nebutra Homebrew tap. Apple signing and notarization automation is implemented but awaits release credentials. Linux archives/packages, npm trusted publishing, Windows worker, containers, and packaged VS Code/Web Operator clients are implemented in the release pipeline but still need their external registries, publishers, or credentials activated.
Use Carina when the hard part is not asking a model for code, but controlling what happens after the model decides to act.
Carina gives you:
- Per-action permission decisions for files, commands, network, secrets, patch application, plugins, and remote work.
- Auditable execution through an append-only hash chain that records decisions and granted side effects.
- Transactional file changes that can be proposed, inspected, applied, and rolled back.
- Daemon-backed sessions that can survive CLI exit and support background or remote workers.
- BYOK model access with provider catalog discovery and Nebutra OAuth as a fallback path when configured.
- MCP, plugins, sub-agents, workflows, and egress controls behind the same capability boundary.
Carina is a good fit when you need to:
- run coding-agent tasks on local repositories without giving the agent raw machine access;
- keep a record of what the agent read, changed, ran, and why it was allowed;
- build an IDE extension, CI integration, internal agent platform, or workflow runner on top of a reusable runtime;
- let sub-agents, plugins, or remote workers operate with narrower permissions than the parent task;
- evaluate agent work in environments where rollback and audit matter.
Carina is not the right tool if you only need an editor assistant, a hosted managed agent service, or a stable packaged release today.
Implemented in this repository:
| Area | What exists today |
|---|---|
| Sessions and tasks | Daemon-backed sessions, background runs, event streams, attach/replay, task steering |
| Agent loop | ReAct-style loop, structured actions, dual-threshold/token-triggered prompt compaction with verbatim-user preservation, structured compaction summaries, canonical-signature loop detection, consecutive-failure circuit breaker, opt-in best-of-N patch generation, success checks, verifier, risk review |
| Memory | Local governed memory store with memory / Nebutra-scoped user targets, frozen per-run prompt snapshot, native memory tool, CLI/RPC inspection, and kernel-gated MemoryWrite audit |
| Permissions | Built-in profiles, approval modes, approval overlays with justifications, workspace trust, org-locked config keys, declarative sub-agent manifests with per-agent tool allow-lists and a kernel-gated spawn capability |
| Audit | Hash-chained event log, audit export, verification, normalized session.items stream, turn net diff |
| File changes | Transactional patch propose/apply/rollback and post-edit diagnostics |
| Commands | Risk classification, approval gates, command output events, optional OS sandbox backend |
| Network and secrets | Deny-by-default egress proxy, allowlists, daemon-side credential injection, explicit per-host HTTPS MITM opt-in |
| Models | BYOK auth chain, provider catalog, OpenAI/Anthropic/Gemini/OpenRouter-style runtime adapters, catalog-gated image input for vision-capable models (raw bytes stay in the artifact store, never in transcripts or audit) |
| Context engine | Native context-engine boundary with bundled/configured Headroom discovery, managed private MCP transport, and carina context diagnostics |
| Integration | MCP client/server with tool search (mcp_find), WASM plugin boundary with org/user/project tighten-only enable merge, workers, workflow DAGs (batch and streaming — conditional/dynamic graphs, live inter-step channels, remote worker-pool dispatch, run-wide budgets; see docs/workflows.md) |
| Nebutra boundary | Local runtime stays authoritative; identity and multi-endpoint sync are scoped to Nebutra Cloud (nebutra.com) |
External activation still required:
- the first credentialed Apple-accepted public release; fail-closed signing and notarization automation is ready, but the required Apple credentials have not been provisioned;
- public Linux/npm/container publication; build, package, SBOM, provenance, and conformance paths are implemented, while external publisher/registry setup is not;
- Marketplace/hosting activation for the packaged VS Code and Web Operator clients;
- Homebrew Core review for untapped
brew install carina; the maintained Nebutra tap is available now; - real-provider/CJK/terminal validation requiring external credentials and representative hardware;
- Nebutra Cloud API, tenant, identity, and retention contracts. Local sync remains deliberately off;
- Windows is supported for the remote worker package, not a desktop daemon/CLI.
Carina publishes checksummed macOS packages for Apple Silicon and Intel through the official Nebutra tap:
brew install Nebutra/tap/carinaThe fully qualified command taps and trusts the Carina formula. After that,
brew install carina resolves the same formula.
Upgrade Carina with Homebrew's standard update flow:
brew update
brew upgrade carinabrew update carina is not a valid Homebrew command; brew update refreshes
package metadata and brew upgrade carina upgrades the installed formula.
Carina does not auto-start the daemon after installation.
Check or install the newest public release from any installation:
carina update --check
carina updateHomebrew installations delegate to brew; npm/pnpm installations delegate to
their owning package manager. Standalone and source-tree bin/carina
installations download the complete platform bundle, verify the published
SHA256 plus the archive manifest and internal checksums, reject unsafe archive
entries, and replace sibling runtime binaries as one rollback-capable
transaction. Use --version x.y.z for an exact standalone release and
--force only for an intentional reinstall or downgrade. A running daemon is
never killed automatically; restart it after active tasks finish.
Run bare carina in an interactive terminal (optional flags:
-session, -workspace, -locale, -socket, -no-alt-screen). The
composer keeps control keys responsive while a task submission is waiting for
its daemon acknowledgement. Ordinary typing or paste during that interval
starts an independent next draft; it cannot mutate the frozen, journaled
submission being reconciled.
The default interaction loop is:
Entersubmits while idle and steers the active task;Tabqueues a later turn andAlt+Uprecalls the newest queued turn for editing.Shift+Enter,Alt+Enter, orCtrl+Jinserts a newline.Ctrl+Rsearches prompt history scoped to the current workspace, so another repository's prompts do not appear in normal TUI recall.Escinterrupts an active task. With an idle, empty composer, pressEsctwice to open the checkpoint picker. Restore always requires a rollback preview, thenyandEnterconfirmation.Alt+Ropens the plain-text transcript,F1opens context-aware help, and the mouse wheel scrolls the currently focused transcript, approval, question, help, keymap, or checkpoint surface.!on an empty composer enters sticky shell mode (prompt becomes!; Enter runs a governedcommand.exec).Escon an empty shell draft returns to chat. One-shot!cmdin normal mode still works./settings(orCtrl+,) opens the control shell./planscaffolds a plan file under.carina/plans/;/approve-planexits plan mode.- Product HITL modes (footer; daemon config
approval_mode/CARINA_APPROVAL_MODE/-approval-mode//approval-mode):ask— pause onrequires_approvalfor operator once/session/projectalways-approve— auto-allowrequires_approvalwith an on-screen warning (/always-approve); deny rules, plan mode, and OS sandbox still applydont-ask— denyrequires_approvalunless a matching session/project grant already exists (exact resource, or a safeFileRead/FileWritedirectory prefix; no prompt; CI-friendly). Also/dont-askaccept-edits— auto-allowFileWrite/PatchApplyrequires_approval; shell/network/secrets still prompt (/accept-edits)- Orgs can lock out YOLO with
"disable_always_approve": true(manage-lock in/etc/carina/managed.json) - Not the same axis as session/kernel approval: session create still takes
untrusted|on_request|never(how the kernel escalates or auto-allows). Product mode is what the daemon does when the kernel still returnsrequires_approval. Do not set productapproval_modetonever— that token is rejected so it cannot be confused with sessionnever.
/planscaffolds.carina/plans/;/view-planopens a plan review overlay (aapprove,srequest changes,qquit plan,escclose)./approve-planstill works from the command line / settings./btw <q>is answer-only on the current session;/btw --fork//sideforks a session and switches to it (no dual-pane).- Context pressure notices appear around 80%/90%; auto-compact runs only when
a paused checkpoint makes
session.checkpoint.compactavailable. - Agent
ask_user: structured (2–6 options) or free-text (omitoptions); free-text answers use the TUI free-text field. - Autonomous risk review (always-approve / accept-edits edit path) is projected into the transcript with outcome / risk / rationale.
The TUI normally uses the alternate screen. To keep the rendered session in
the terminal's normal buffer, use carina --no-alt-screen, or set
"tui_alternate_screen": "never".
The accepted values are auto, always, and never.
The TUI ships authored copy for English, Simplified Chinese
(zh-CN/zh-Hans, runtime key zh), Traditional Chinese (zh-Hant /
zh-TW / zh-HK / zh-MO, runtime key zh-Hant), Japanese, Korean,
Spanish, and French. Traditional catalogs are derived from Simplified with
OpenCC-compatible conversion (regenerate via scripts/gen_zh_hant.py); the
Simplified zh strings remain the source of truth. Select locale with
carina --locale, CARINA_LOCALE, tui_locale in the normal config
cascade, or CARINA_TUI_LOCALE; the precedence is flag, CARINA_LOCALE,
config, then LC_ALL/LC_MESSAGES/LANG. System detection for an
unsupported locale quietly falls back to English, while an unsupported
explicit flag, environment value, or config value fails fast instead of
silently choosing a different language.
The interactive TUI reads key overrides from the normal global and project
configuration cascade (~/.carina/config.json and .carina/config.json).
Bindings are keyed by semantic action names shown in the F1 help overlay and
the /keymap picker:
{
"tui_keybindings": {
"global.help": ["f2"],
"chat.interrupt": ["esc"],
"composer.submit": ["ctrl+enter"],
"composer.external-editor": ["ctrl+g"],
"editor.move-word-left": ["alt+left", "alt+b"]
}
}Unknown actions, duplicate JSON keys, conflicting keys in the same context, and
unbound critical approval/search escape actions fail with an actionable error.
Cross-context bindings are checked against the contexts that can actually be
active together, including suggestions, normal transcript controls, and legacy
terminal-equivalent keys such as Ctrl+[ and Esc. Printable pager bindings
remain overlay-only, so they cannot steal composer text. Modifier aliases such
as control, option/opt, cmd/command, and win normalize to the runtime
ctrl, alt, and super vocabulary.
Multi-key chords use a space-separated value such as "ctrl+x ctrl+r".
Chord prefixes must start with a reliable modifier key; pending chords are
visible in the status line, time out after 1.2 seconds, and Esc cancels them.
Ambiguous single-key/chord prefixes are rejected instead of delaying or losing
ordinary input.
/keymap can replace a binding, add an alternate, or restore the inherited
value. During capture, Ctrl+V quotes the next key: for example, Ctrl+V Esc
records Escape, while Ctrl+X Ctrl+V Enter records a chord ending in Enter.
Bare Escape still cancels and bare Enter still saves, so capture always has a
reachable exit. The picker writes project .carina/config.json atomically and
applies the validated keymap immediately. External edits to managed, global, or
project config are hot-reloaded; invalid edits leave the last-good keymap
active.
Task submissions are journaled under the configured state directory before
dispatch. If an acknowledgement is lost or the TUI restarts, Carina reconciles
the same idempotency key instead of silently creating a duplicate task. Use the
composer.submit-new binding (default Alt+S) only when a distinct submission
is intentional.
Requirements:
- Go 1.25 or newer
- Rust 1.85 or newer
- Zig 0.15.x
- macOS or Linux
Build and install:
git clone https://github.com/Nebutra/carina
cd carina
make installmake install builds everything and installs the carina* binaries into
~/.local/bin (override with PREFIX=/usr/local); make sure that directory
is on PATH. To build without installing, run make all and use
./bin/carina directly. Homebrew installs already put carina on PATH.
Start the daemon:
carina-daemon &Provide a model credential to the daemon process. BYOK API keys have priority; Nebutra OAuth fallback is supported when configured.
export ANTHROPIC_API_KEY=sk-...
# or
export OPENAI_API_KEY=sk-...Run a task in the current repository:
carina run "fix the failing tests and show the patch"The CLI prints a continuation hint after submission:
To continue this session, run:
carina resume <session_id>Inspect what happened:
carina sessions
carina resume <session_id> "follow up on the previous task"
carina items <session_id>
carina audit verify <session_id>
carina patch list <session_id>
carina patch show <session_id> <patch_id>Roll back an applied patch:
carina patch rollback <session_id> <patch_id>Use the default safe-edit session for normal development. The agent can read
the workspace, propose patches, and run allowlisted build/test commands. Risky
commands, network access, secrets, and plugins stay denied or approval-gated by
the active profile.
Use carina items <session_id> for a normalized thread/turn/item view, including
turn-level patch summaries. Use carina audit <session_id> or
carina audit verify <session_id> when you need the raw event chain and
tamper-evidence.
Carina keeps local long-term memory under the daemon state directory. The
runtime separates agent/project notes (target=memory) from user profile facts
(target=user). User memory scope follows Nebutra canonical identity when
CARINA_NEBUTRA_IDENTITY_JSON is present, then Nebutra OIDC/JWT claims from
CARINA_NEBUTRA_TOKEN, then a local fallback. These claims are scope metadata,
not local authorization grants. Memory enters an agent run as a frozen prompt
snapshot, so writes during that run are durable but do not rewrite the run's
stable prompt prefix. Use carina memory ..., the local memory.* RPC methods,
or the agent's native memory tool to add, replace, remove, or batch memory
entries. Writes go through the default approval-gated MemoryWrite capability,
are bounded and content-scanned, and are audited by target/scope/action/content
hash rather than by raw memory text.
carina memory status <session_id> reports local storage paths, identity
scope, cached external-provider health, HMS projection state, and Nebutra Cloud
sync status. HMS recall and governed projection are explicit, restart-only
opt-ins. Projection uses a durable desired-state outbox and requires
NetworkAccess plus MemoryExternalize independently of MemoryWrite;
Nebutra Cloud memory sync remains off.
Release packages include a pinned Headroom executable as bin/headroom.
context_engine=auto enables Headroom only when it is bundled with Carina or
explicitly configured through CARINA_HEADROOM_BIN, headroom_bin, or
--headroom-bin. A global headroom found on PATH is reported but not used
as the built-in engine.
Inspect the integration:
carina context status
carina context doctor
carina context statsThe managed Headroom MCP server is private to Carina's context adapter. It does not appear in the agent's public MCP tool list.
Store local credentials and inspect the provider catalog:
carina auth login anthropic - < ~/.secrets/anthropic-key
carina auth login openai - < ~/.secrets/openai-key
carina auth list
carina providers list --refreshPick a runtime model explicitly when needed:
CARINA_REASONER_MODEL=openai/gpt-5 carina-daemon &
carina run --model openrouter/anthropic/claude-sonnet-4-5 "inspect this migration"The default backend is provider-first model-router; merely having claude
on PATH does not select Claude CLI. A provider is auto-selected only when it
is enabled and has a credential or an explicitly configured keyless local
endpoint; setting a model name alone does not make an unavailable provider
runnable. OpenAI-compatible
gateways can override the catalog endpoint without changing the provider
contract:
OPENAI_BASE_URL=https://gateway.example.com/v1 \
OPENAI_API_KEY="$GATEWAY_TOKEN" \
CARINA_REASONER_MODEL=openai/gpt-5 carina-daemon &Carina prefers the OpenAI Responses API for the openai provider. If a
compatible gateway explicitly reports that /responses is unsupported (a
route/endpoint 404, 405, or 501), the adapter retries the request through
/chat/completions. Model-not-found 404 responses do not switch protocols.
Disable providers persistently when inherited environment variables should not register them. The same list applies to completion, embeddings, rerank, and automatic reasoner selection; changes take effect after restarting the daemon:
{"disabled_providers":["openai"]}The environment-layer equivalent is
CARINA_DISABLED_PROVIDERS=openai,anthropic.
External CLI reasoners remain explicit compatibility adapters and are never selected by binary presence:
CARINA_REASONER_BACKEND=claude-cli carina-daemon &
# or
CARINA_REASONER_BACKEND=codex-cli carina-daemon &Claude's non-interactive form is claude -p; Codex uses codex exec, where
-p means --profile. The Codex adapter runs ephemerally from an empty working
directory, ignores Codex config, AGENTS.md instructions, and exec-policy
rules, disables supported tool entry points, and rejects tool events. Its
read-only sandbox is not a hard no-read/no-execution boundary, so use
codex-cli only when explicitly desired. Carina's file, command, patch, MCP,
and web actions continue to run through its own capability-governed runtime.
Discover reusable agents and commands at runtime:
carina agents list
carina commands list
carina run --agent plan "inspect the release risk"
carina run "/review main"Built-ins include build, plan, general, and explore. User and project
overrides live under ~/.carina/agents, <repo>/.carina/agents,
~/.carina/commands, and <repo>/.carina/commands.
Prompt skills use progressive disclosure. Put a skill in
~/.carina/skills/<name>/SKILL.md or
<repo>/.carina/skills/<name>/SKILL.md, then invoke it explicitly as $name
inside a task or as /name when no existing slash command has that name.
Existing commands always win collisions. Example:
---
name: security-review
description: Review a change for concrete security risks.
when-to-use: Authentication, authorization, secrets, or untrusted input.
user-invocable: true
implicit-invocation: true
triggers: [security audit, threat model]
allowed-tools: [read, search]
---
Inspect the requested change. Trace each finding from source to sink and cite
the affected files.Only bounded metadata is always present in the model prompt; the full body is
loaded for an explicit mention. Implicit matching is off by default and uses
only exact declared triggers when enabled with
CARINA_IMPLICIT_SKILL_PROMPTS=true. Disable skills fail-closed with
CARINA_DISABLED_SKILLS=name-a,name-b. allowed-tools is non-granting
guidance: the selected agent profile and capability kernel remain authoritative.
Use JSON-RPC, SDKs, or MCP server mode when Carina should sit behind another UI: an IDE extension, web console, CI workflow, or internal agent platform.
This is a positioning map, not a winner/loser checklist. These projects optimize for different jobs, and their capabilities change quickly. Use each project's official docs as the source of truth.
| If you primarily need... | Common choices | Where Carina fits |
|---|---|---|
| In-editor coding assistance | Cursor, Windsurf, Cline, IDE extensions | Carina can back an editor, but it is not an editor product. |
| Terminal-first pair programming | Claude Code, Codex CLI, Aider, OpenCode | Carina focuses less on chat UX and more on runtime boundaries, audit, rollback, workers, and embeddability. |
| Cloud-hosted agent tasks | OpenAI Codex cloud tasks and managed agent services | Carina is local-first. Cloud identity and multi-endpoint sync live behind Nebutra Cloud boundaries, not inside the local runtime. |
| Disposable cloud sandboxes | E2B and other sandbox runtimes | Carina can use sandboxing, but its core unit is policy-gated action on a repository, not a hosted VM product. |
| Internal agent infrastructure | Custom stacks, CI systems, internal platforms | Carina is meant to be used as a control-plane/runtime component. |
Carina is split by responsibility:
| Layer | Responsibility |
|---|---|
| Agent surface | Agent loop, transcripts, approvals, sub-agents, workflows |
| Control plane | Sessions, scheduling, JSON-RPC, workers, event streaming, egress |
| Capability kernel | Permission decisions, policies, transactional patches, audit chain, plugins |
| Native toolchain | Repository scan, grep, diff, patch, process execution, pty |
| Client surfaces | CLI, TUI, SDKs, MCP client/server |
The important boundary is not the language split. The important boundary is that the agent requests actions, while the runtime decides whether they can happen and records the result.
Default posture:
- Least privilege by default.
- No access outside the workspace unless explicitly granted.
- Secrets are unreadable by default.
- Network access is restricted by default.
- Destructive commands are denied by default.
- File changes go through patch transactions.
- Plugins start with no implicit permissions.
- Persistent memory writes are capability-gated, scoped, bounded, and audited.
Alpha limitations:
- Carina is not a VM or complete container isolation system by itself.
- OS sandbox backends exist, but production profiles need deployment review.
- Policy correctness depends on routing commands through the Carina daemon and toolchain.
- Tag-release automation fails closed on Developer ID signing and Apple notarization. A release is only considered notarized when its release page contains Apple-accepted notary JSON and the generated signing report.
See SECURITY.md and docs/security-model.md.
Build and test:
make all
go test ./go/... ./apps/...
cargo test
go test -race ./go/daemon ./go/config ./apps/carina-daemonRun the local release gate:
make release-checkBuild a local release candidate archive:
make release-packageMore documentation:
- Product positioning
- Brand and design system
- Nebutra Cloud boundary
- Roadmap
- Release process
- Architecture
- RPC API
- Plugin model
- Research status
MIT License. See LICENSE.
