Changelog
latest
-
Banner mount lines abbreviate the invoking user’s home directory to
~and print a mount whose host and container paths are identical once, followed by(mirror). -
The startup banner lists the mounted paths, one
host -> containerline each, with shadow mounts marked(read-only). Suppressed by--verbose, like the rest of the banner. -
The codex harness is now routed through the credential proxy by a merged, read-only
config.tomlmounted over~/.codex/config.tomlinside the container. Codex reads noOPENAI_BASE_URL: the built-inopenaiprovider takes its endpoint from theopenai_base_urlconfig key, and custommodel_providersentries cannot override built-in provider ids, so previous proxied runs sent the per-run token toapi.openai.com, which rejected it. The host file is untouched, and its comments and formatting are preserved in the merged copy. orka warns and forwards keys directly when the user’sconfig.tomlalready setsopenai_base_urlor selects amodel_providerother thanopenai. Claude needs no overlay; it honorsANTHROPIC_BASE_URL. -
The
models.jsonmount destination is created host-side as an empty file before the container starts, so the OCI runtime no longer creates it as root inside the user namespace and writes a subuid-owned 0700 file back into the bind-mounted state directory. -
An empty
models.jsonis treated as an absent one, including when orka cannot read it. The OCI runtime creates a missing bind-mount destination as root inside the user namespace, so the first proxied run leaves a zero-byte file owned by a subuid at<state-dir>/agent/models.json; under--harness-configthat made every later run fail to read it.staton the stub still succeeds because the parent directory belongs to the invoking user, so a real file whose contents are withheld still aborts the run. -
The environment context snippet is now prepended to the task prompt rather than to the first argument after
--.orka -- -p "task"produced a single argument"<snippet>\n\n-p"followed by the prompt, which the harness parsed as an unknown option. The snippet attaches to the last argument when that argument is not itself an option; a--list made only of options is left untouched. -
A pi state directory that orka cannot read or write now aborts the run instead of falling back to direct key forwarding. Building the
models.jsonoverlay failed for reasons unrelated to the user’s configuration — a root- or subuid-owned~/.pi, or a path that is not a directory — and the fallback handed the realANTHROPIC_API_KEYandOPENAI_API_KEYto the agent with only a warning. The fallback still applies when the user’s ownmodels.jsonblocks proxy routing, which is a configuration choice;--no-proxyremains the way to ask for direct forwarding. -
--harness-config <DIR>usesDIRon the host for the harness’s persistent state in place of~/.pi,~/.claude, or~/.codex. The directory is created if absent and is mounted at the harness’s default path inside the sandbox, so the harness needs no reconfiguration. For claude,claude.jsonis read from and written toDIR/claude.json. Applies to every backend, including bubblewrap.config.yamlaccepts a matchingharness-configkey, applied to whichever harness runs. -
A failed image build under
--engine containernow prints a note about recreating the builder (container builder delete --force && container builder start). Apple’s builder image lives in the same store as user images, socontainer image prunecan remove it, after which builds fail with an unexplainedinput/output erroron a/tmppath. -
Provider API keys are now concealed from the agent by default. A per-run reverse proxy on the host holds the real
ANTHROPIC_API_KEYandOPENAI_API_KEY; the container gets a random per-run token and base-URL overrides instead, and the proxy injects the real key only for requests carrying the token.OPEN_ROUTER_KEYhas no base-URL override and is withheld while the proxy is active.--no-proxy(orno-proxy: trueinconfig.yaml) restores direct forwarding of all three keys. The proxy is skipped automatically when neither key is set or under--engine container. Pi ignores the base-URL env vars, so the pi harness is routed through the proxy by a merged, read-onlymodels.jsonmounted over~/.pi/agent/models.jsoninside the container; the host file is untouched, and orka warns and forwards keys directly when the user’smodels.jsonalready routes a proxied provider elsewhere or cannot be parsed. The container startup banner reports each key asproxied,set, orunset—set(a raw credential readable by the agent) in yellow — based on the injectedORKA_PROXYlist of proxied key names. Seedocs/credential-proxy.md. -
The bubblewrap sandbox no longer bind-mounts
/opt, which exposed every third-party install tree on the host read-only. An agent installed under/optstill runs: its launcher directory and package tree are mounted individually, as they already were for installs outside the system directories. -
Base image ships bun 1.4.0 instead of 1.3.14. 1.3.14 does not export
markAsUncloneablefromnode:worker_threads, which undici 8.0.3+ requires, so recent pi releases crashed at startup withwebidl.util.markAsUncloneable is not a function. Rebuild the base image (--no-cache, or deleteorka-base:latest) to pick it up. -
Every file named
.orkashadowat any depth in a mounted directory is now always shadowed, not just the root one. Each is replaced with the read-only empty stub, so the agent cannot read which paths are hidden and cannot edit a shadow file to weaken its own coverage on a later run. A nested.orkashadowis hidden even when it is the only shadow configuration present, which now means each mounted directory is scanned on every run regardless of whether a global or root-level shadow file exists. -
THIRD_PARTY_LICENSESregenerated. It was missingclap_complete,serde_ignored,itoa, andryu, all of which are linked into the released binaries. The license texts printed by--print-licenseare no longer HTML-escaped, and the summary at the top lists each license with the number of crates using it instead of an empty line per license. -
orka scratchis an alias fororka scratchpad. -
Top-level flags are now global and accepted in any position, before or after a subcommand.
orka scratchpad foo --preset gh --dry-runpreviously failed withunexpected argument '--preset' found; it now behaves the same asorka --preset gh --dry-run scratchpad foo.--preset listis likewise handled regardless of position. -
orka is now open source under the MIT license (
LICENSE), replacing the previous binary-only terms.orka --print-licenseprints the MIT text followed byTHIRD_PARTY_LICENSES. The full source, documentation, and config templates live in one repository; topic pages moved underdocs/. -
--volume <PATH>mounts an extra host path into the container, repeatable. A bare path is mounted at the same absolute path it has on the host;HOST:CONTAINERsets the destination explicitly. Paths already mounted (the working directory, or a preset volume) are skipped rather than mounted twice.config.yamlaccepts a matchingvolumelist applied to every run. -
config.yamlacceptsharness-args: extra arguments per harness (pi,claude,codex), forwarded to the agent. They are placed ahead of anything passed after--, so a trailing prompt stays last. Removes the need to type flags such as--dangerously-skip-permissionson every run. -
config.yamlacceptspresetandenvlists, applied to every run as if passed with--presetand--env. Command-line values are appended to the configured ones. Presets are deduplicated, so naming an always-on preset again on the command line no longer produces a duplicate mount, which the container engines reject. -
config.yamlacceptsno-cache,verbose,quiet, andpreserve-containerbooleans, each setting the corresponding flag on every run. They can only turn a flag on; the flags have no negated form. -
A preset named in
config.yamlbut missing fromenvironments.yamlnow reportsconfig.yamland the offending name, instead of an error that reads as a mistyped--presetflag. -
--tmpreplaced by theorka tmpsubcommand. Same behaviour: the workdir is a freshmktemp -ddirectory that persists after the container exits. -
--scratchpad <NAME>replaced by theorka scratchpad [NAME]subcommand. Without a name, existing scratchpads are shown in an interactive fuzzy selector (type to narrow, arrows or Ctrl-N/Ctrl-P to move, Enter to select, Esc to abort).orka scratchpad --listprints the names without starting a container.orka config pathnow also prints the scratchpad root. -
Podman backend:
--useris no longer passed. It was redundant with--userns=keep-id, and it made Podman reverse-resolve the numeric UID to a username, which fails for LDAP/sssd users who are absent from/etc/passwd. Those runs failed withunknown user error looking up userand exit status 125. -
Bubblewrap backend: the agent binary’s package tree is now bind-mounted, not just its
bindirectory. npm-style installs place a relative symlink inbinpointing intolib/node_modules/...; binding onlybinleft that symlink dangling and the sandbox failed withexecvp ...: No such file or directory. The interpreter named in a script’s shebang is now mounted too. -
harness-version,pi-path,claude-path, andcodex-pathinconfig.yamlare now honoured. They were read as snake_case while the documented and shipped format is kebab-case, so all four were silently ignored. -
agent-browser and Chromium are now bundled directly into the base image (
orka-base). The separateorka-browser-baseintermediate image is gone. The base builds once and is shared across harness rebuilds as before. -
Chrome is now reachable by the container’s runtime user.
agent-browser installran as root during the base build and left the download in/root/.agent-browser/browsers, so browser tool calls failed in the running container. The download is relocated to/opt/browser-cacheand exposed throughAGENT_BROWSER_EXECUTABLE_PATH. The unusedPLAYWRIGHT_BROWSERS_PATHvariable is gone; custom base images that set it should setAGENT_BROWSER_EXECUTABLE_PATHinstead. -
Documented that the Docker backend is not restricted to Linux. orka gates no backend by platform, so
--engine dockerworks whereverdockerresolves onPATH, Docker Desktop on macOS included. Untested, and noted as such. -
--cap-drop=ALLis now passed to Apple’scontaineronly when that binary accepts it. Capability flags were added incontainer0.12.0, and earlier versions reject unknown options outright, so every run failed withError: Unknown option '--cap-drop'and exit status 64. Docker and Podman are unaffected and are not probed. -
ARM64 base images now install the Chromium build published by Playwright instead of Chrome for Testing, which has no Linux ARM64 release. The base image build previously failed on Apple silicon at the
agent-browser installstep.AGENT_BROWSER_EXECUTABLE_PATHstill points at/opt/browser-cache/chromeon both architectures. The revision is pinned by thePLAYWRIGHT_CHROMIUM_REVISIONbuild argument. -
Architecture-dependent download steps in the bundled Dockerfiles now read BuildKit’s
TARGETARCHrather thanuname -m, falling back todpkg --print-architectureon the legacy builder. Cross-builds with--platformpreviously selected binaries for the builder’s architecture instead of the image’s. -
--initreplaced byorka config init. New sibling subcommands:orka config completions <SHELL>prints a shell completion script (bash, zsh, fish, elvish, powershell), andorka config pathprints the configuration paths orka reads. -
--no-browserremoved. To run without browser support, provide a custom~/.config/orka/Dockerfile.basethat omits agent-browser.
previous
--initto write the bundled config templates (config.yaml,environments.yaml,orkashadow) to~/.config/orka/. Files that already exist are skipped.--quietto suppress image build output (build output is now shown by default; use--quietto hide it).--verbosenow passesVERBOSE=1into the container environment instead of controlling build output visibility.- Podman backend:
--userns=keep-idis now passed automatically so container file ownership matches the host user. --engine bubblewrapto run the agent in a bubblewrap user-namespace sandbox instead of a container. No image is built; the agent binary must already be installed on the host. Bind-mounts system paths, agent config directories, and user-specified volumes into the namespace. Linux only.pi-path,claude-path,codex-pathin~/.config/orka/config.yamlto set explicit paths to agent binaries that are not on PATH. Used only by the bubblewrap backend.--engineto select the container engine:docker(default) orpodman. The engine binary is used for all build and run commands.~/.config/orka/config.yamlfor persistent user defaults. Supportsengineandharness. Command-line flags always win. Copy the bundledconfig/config.yamlto get started.orkashadowfiles to hide sensitive files from the agent. Files matching patterns in~/.config/orka/orkashadow(global) or.orkashadow(per-repo, placed at the root of any mounted directory) are replaced with empty read-only stubs inside the container. The agent can see the filename but cannot read or write the content. Uses.gitignoresyntax. Copy the bundledconfig/orkashadowfor annotated examples.--file/-fto mount specific files into the container rather than the entire working directory. Repeatable. Each file is mounted at its host path; the container workdir is set to the invoking directory.--tmpto create a temporary directory withmktemp -dand use it as the container workdir. The directory persists after the container exits.--scratchpad <NAME>to create or reuse~/.local/share/orka/scratch/<NAME>as the container workdir.- Support claude-code (
--harness claude) - Support Codex (
--harness codex) --presetto mount named volume and env var sets; presets can be stacked--harness-versionto pin the agent version installed in the image--preserve-containerto keep the container after it exits (containers are removed on exit by default)--dry-runto print commands without executing them