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
106 changes: 106 additions & 0 deletions docs/harnesses/codelayer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
title: "CodeLayer"
---

# CodeLayer

Open Harness supports a **bounded, optional local coding-harness integration** for exactly `@humanlayer/codelayer@0.0.61`. It is off by default. This does not install or support `@humanlayer/cli`, a remote daemon, login automation, launch tokens, browser control, or a HumanLayer control plane.

The implementation and evidence are tracked in [core PR #636](https://github.com/mifunedev/openharness/pull/636).

## Enable and rebuild

Edit `harness.yaml`, uncomment the key, and rebuild:

```yaml
install:
codelayer: true
```

```bash
make destroy
make sandbox
make shell
```

Legacy `.devcontainer/.env` configuration can set `INSTALL_CODELAYER=true`; an explicit `harness.yaml` value wins. The image banner says **installed** only after `codelayer --help` succeeds locally. Installation does not prove provider authentication or authenticated usability.

## Why Open Harness supplies a wrapper

The pinned package declares `dist/cli.js` as its executable but omits that file while publishing `src/cli.ts` and JavaScript bundles ([pinned `package.json`](https://unpkg.com/@humanlayer/codelayer@0.0.61/package.json), [pinned `src/cli.ts`](https://unpkg.com/@humanlayer/codelayer@0.0.61/src/cli.ts)). The image therefore unconditionally replaces `/usr/local/bin/codelayer` with a root-owned regular executable:

```sh
#!/bin/sh
exec /usr/local/bin/bun /usr/local/lib/node_modules/@humanlayer/codelayer/src/cli.ts "$@"
```

The build fails if Bun or that exact published source path is missing. Open Harness does not copy or vendor CodeLayer source.

## Verify installation

Inside a rebuilt sandbox:

```bash
codelayer --help
stat -c '%F %U:%G %a' /usr/local/bin/codelayer
readlink /usr/local/bin/codelayer || true
```

Expected wrapper state is `regular file root:root 755`; `readlink` prints nothing. Help is a credential-free local parser check. It is not authentication evidence.

## Direct use and operator-owned authentication

The pinned CLI exposes `--prompt`, `--provider`, and `--model`; its listed provider values and defaults are package behavior ([`src/command.ts`](https://unpkg.com/@humanlayer/codelayer@0.0.61/src/command.ts), [`src/providers.ts`](https://unpkg.com/@humanlayer/codelayer@0.0.61/src/providers.ts)). Provider selection, model selection, and credentials are operator configuration. Open Harness does not authenticate CodeLayer and has not run a credentialed end-to-end test.

```bash
codelayer --provider openai --model <operator-selected-model> --prompt 'Inspect this repository'
```

Pinned source and its published README document `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, and `FIREWORKS_API_KEY` as provider credentials; `EXA_API_KEY` enables research-subagent web search. Anthropic and Fireworks can also fall back to AgentLayer's file auth store. That store documents only the path overrides `AGENTLAYER_AUTH_PATH`, `AGENT_SDK_AUTH_PATH`, and `OPENCODE_AUTH_PATH` ([CodeLayer README](https://unpkg.com/@humanlayer/codelayer@0.0.61/README.md), [`src/providers.ts`](https://unpkg.com/@humanlayer/codelayer@0.0.61/src/providers.ts), [AgentLayer auth README](https://unpkg.com/@humanlayer/agentlayer-provider-auth@0.0.61/README.md)). Installed never means authenticated.

## Ralph adapter

CodeLayer is explicit-only and is never in Ralph's fallback order. Export the selected provider's key in the shell that launches Ralph so an already-running tmux server cannot hide a newly supplied credential:

```bash
export OPENAI_API_KEY='<operator-supplied-key>'
RALPH_CODELAYER_PROVIDER=openai \
RALPH_CODELAYER_FLAGS='--model gpt-4.1 --verbose' \
bash .oh/scripts/ralph.sh --harness=codelayer <task-slug>
```

`--harness codelayer` and `RALPH_HARNESS=codelayer` are also accepted. Ralph owns long `--prompt` and emits `--provider "$RALPH_CODELAYER_PROVIDER"` only when non-empty.

`RALPH_CODELAYER_FLAGS` is intentionally not shell syntax. Empty or whitespace-only means no extra flags; otherwise use simple whitespace-delimited tokens only. Quotes, backslashes, embedded spaces represented by quotes, shell metacharacters, and glob characters are rejected. So are every `--prompt*`, `--provider*`, `-p`, and attached `-pVALUE` form. Ralph parses a Bash array without `eval` and with pathname expansion disabled.

For CodeLayer launches, Ralph keeps `tmux new-session -E` and uses tmux 3.3a per-session `-e NAME=value` arguments for only the two `RALPH_CODELAYER_*` controls and the seven pinned-source/documented auth variables above. Values stay out of the pane command and Ralph log; spaces and explicit empty values are preserved, and absent allowlisted names are unset in the pane. Other variables already present in an old tmux server follow normal tmux/Ralph inheritance and are outside this adapter contract.

CodeLayer's final-message wrapper is diagnostic only. Ralph completes only when `progress.txt` contains a whole line exactly `STATUS: COMPLETE`.

## Tested boundary

The enabled/default image smoke builds through build-only Compose in isolated Docker-in-Docker and runs uniquely named containers on an internal no-egress network. It proves:

- the enabled wrapper is a root-owned executable regular file, not a symlink;
- the exact published source exists and `codelayer --help` succeeds;
- exact adapter-shaped `--model gpt-4.1 --verbose --provider openai --prompt ...` parsing reaches pinned source's expected missing-`OPENAI_API_KEY` boundary; and
- the default image has no command, package, wrapper, or CodeLayer source.

This proves local executable and adapter compatibility only—not provider authentication, model availability, remote execution, or authenticated end-to-end behavior.

## Rollback

Set `install.codelayer: false` (or remove the key and retain `INSTALL_CODELAYER=false`), then rebuild. Verify absence:

```bash
! command -v codelayer
! test -e /usr/local/bin/codelayer
! test -e /usr/local/lib/node_modules/@humanlayer/codelayer
! test -e /usr/local/lib/node_modules/@humanlayer/codelayer/src/cli.ts
```

If the source-wrapper help or adapter parsing evidence regresses, disable the integration and downgrade support wording to Draft.

## Explicitly unsupported remote control plane

The separate `@humanlayer/cli` package and all remote-daemon behavior remain **Draft, deferred, and unsupported**. Open Harness does not install or manage a HumanLayer daemon, automate login, mint or consume launch tokens, drive browser control, expose daemon ports, manage a remote workspace, store daemon credentials, or claim support for a HumanLayer control plane. The accepted boundary is only the local `@humanlayer/codelayer@0.0.61` coding harness described above.
5 changes: 4 additions & 1 deletion docs/harnesses/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ title: "Harnesses Overview"

# Harnesses Overview

Open Harness ships with three agent CLIs in the default sandbox image: **Claude Code** (default), **Codex**, and **Pi**. **OpenCode**, **DeepAgents**, **Hermes**, and **Grok Build** are optional image-level installs controlled by `harness.yaml` `install:` keys (or `.devcontainer/.env` build flags). **T3 Code** runs on demand via the `/t3` skill (or directly with `npx t3`) as a browser UI on port 3773. Inside the sandbox, launch whichever you prefer — switch between them at any time, or keep long-running sessions in tmux.
Open Harness ships with three agent CLIs in the default sandbox image: **Claude Code** (default), **Codex**, and **Pi**. **OpenCode**, **DeepAgents**, **Hermes**, **Grok Build**, and the bounded local **CodeLayer** coding harness are optional image-level installs controlled by `harness.yaml` `install:` keys (or `.devcontainer/.env` build flags). **T3 Code** runs on demand via the `/t3` skill (or directly with `npx t3`) as a browser UI on port 3773. Inside the sandbox, launch whichever you prefer — switch between them at any time, or keep long-running sessions in tmux.

Open Harness is the harness; the **agent** is your call. To go beyond the preinstalled options, install via `npm` / `pip` / `cargo` inside the sandbox or edit the Dockerfile. For Pi+Slack specifically, the recommended path is the `pi-messenger-bridge` npm package (pinned in `.pi/settings.json`; see [Slack integration](../integrations/slack.md)). The product surface is one developer, one project, one agent — not racing or stacking multiple CLIs against each other.

Expand All @@ -22,6 +22,7 @@ For help matching a model to the work, see [Choosing a Model](../model-selection
| [DeepAgents](./deepagents.md) | LangChain's multi-provider terminal agent | `deepagents` | optional: `install.deepagents: true` in `harness.yaml` |
| [Hermes](./hermes.md) | Nous Research's self-improving terminal agent | `hermes` | optional: `install.hermes: true` in `harness.yaml` |
| [Grok Build](./grok-build.md) | xAI's proprietary Grok Build terminal agent | `grok` | optional: `install.grok_build: true` in `harness.yaml` |
| [CodeLayer](./codelayer.md) | Bounded local `@humanlayer/codelayer@0.0.61` coding harness; installed is not authenticated | `codelayer` | optional: `install.codelayer: true`; no daemon support |
| [T3 Code](./t3code.md) | Browser UI over Claude/Codex/OpenCode (port 3773) | `/t3` or `npx t3` | on-demand |

## Verifying installation
Expand All @@ -36,6 +37,7 @@ opencode --version # install.opencode: true
deepagents -v # install.deepagents: true
hermes --version # install.hermes: true
grok --version # install.grok_build: true
codelayer --help # install.codelayer: true; local parser check only

npx t3 --version # T3 Code (not preinstalled — fetched on demand)
```
Expand All @@ -51,6 +53,7 @@ Open Harness ships Claude Code, Codex, and Pi in the default image. Authenticate
- **DeepAgents**: write provider keys to `~/.deepagents/.env` (see [DeepAgents](./deepagents.md)).
- **Hermes**: run `hermes setup` (see [Hermes](./hermes.md)).
- **Grok Build**: run `grok login --device-auth` for headless/remote auth, `grok login` for interactive OAuth, or set `XAI_API_KEY` as a fallback (see [Grok Build](./grok-build.md)). Cached `~/.grok/auth.json` takes precedence over `XAI_API_KEY`.
- **CodeLayer**: configure the operator-selected provider according to the [pinned-source guidance](./codelayer.md#direct-use-and-operator-owned-authentication); image installation does not verify authentication and does not enable a remote daemon.
- **T3 Code**: authenticate one of Claude / Codex / OpenCode first, then run `/t3` (or `npx t3`) and open the printed pairing URL (see [T3 Code](./t3code.md)).

## Default surfaces
Expand Down
1 change: 1 addition & 0 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ Default CLIs are always present. Optional CLIs are excluded from the default ima
| DeepAgents | `deepagents` | LangChain's multi-provider terminal agent (`deepagents-cli` via `uv tool install`) | optional: set `install.deepagents: true` in `harness.yaml` (or `INSTALL_DEEPAGENTS=true` in `.devcontainer/.env`) |
| Hermes | `hermes` | Nous Research's self-improving agent CLI | optional: set `install.hermes: true` in `harness.yaml` (or `INSTALL_HERMES=true` in `.devcontainer/.env`) |
| Grok Build | `grok` | xAI's proprietary Grok Build CLI (`@xai-official/grok@0.2.39`, Node >=20) | optional: set `install.grok_build: true` in `harness.yaml` (or `INSTALL_GROK_BUILD=true` in `.devcontainer/.env`) |
| CodeLayer | `codelayer` | Exact `@humanlayer/codelayer@0.0.61` bounded local coding harness via tested Bun source wrapper; installed is not authenticated | optional: set `install.codelayer: true` (or `INSTALL_CODELAYER=true`), rebuild, and follow [CodeLayer](harnesses/codelayer.md); `@humanlayer/cli` remote-daemon support is deferred and unsupported |
| agent-browser | `agent-browser` | Headless Chromium for web-capable agents | optional: set `install.agent_browser: true` in `harness.yaml` (or `INSTALL_AGENT_BROWSER=true` in `.devcontainer/.env`) |

### Runtimes & package managers
Expand Down
5 changes: 4 additions & 1 deletion docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ directory: `/home/sandbox/harness`.
## Pick your harness

The default sandbox ships with Claude Code, Codex, and Pi. OpenCode,
DeepAgents, Hermes, and Grok Build are optional image-level installs; T3 Code runs on
DeepAgents, Hermes, Grok Build, and bounded local CodeLayer are optional image-level installs; T3 Code runs on
demand via the `/t3` skill or direct `npx`. Authenticate at least one harness before use.

> **Simplest cross-provider login — device mode via `/login`.** The most straightforward path
Expand All @@ -100,6 +100,7 @@ demand via the `/t3` skill or direct `npx`. Authenticate at least one harness be
- **[DeepAgents](./harnesses/deepagents.md)**: set `install.deepagents: true` in `harness.yaml` (or `INSTALL_DEEPAGENTS=true` in `.devcontainer/.env`), rebuild, then write provider keys to `~/.deepagents/.env`
- **[Hermes](./harnesses/hermes.md)**: set `install.hermes: true` in `harness.yaml` (or `INSTALL_HERMES=true` in `.devcontainer/.env`), rebuild, then run `hermes setup`
- **[Grok Build](./harnesses/grok-build.md)**: set `install.grok_build: true` in `harness.yaml` (or `INSTALL_GROK_BUILD=true` in `.devcontainer/.env`), rebuild, verify `grok --version`, then run `grok login --device-auth` (headless/remote) or `grok login`
- **[CodeLayer](./harnesses/codelayer.md)**: set `install.codelayer: true`, rebuild, then verify `codelayer --help`; this proves installation only, not provider authentication, and does not install or enable `@humanlayer/cli` or a remote daemon
- **[T3 Code](./harnesses/t3code.md)**: authenticate one of Claude / Codex / OpenCode, then `/t3` or `npx t3` (browser UI on port 3773)

Claude Code remains the documented default. See
Expand Down Expand Up @@ -133,6 +134,7 @@ install:
deepagents: false
hermes: false
grok_build: false
codelayer: false
agent_browser: false
```

Expand All @@ -159,6 +161,7 @@ The file also has `crons:`, `autopilot:`, `slack:`, and `compose:` sections (all
| `install.deepagents` | Set `true` to include DeepAgents in the sandbox image |
| `install.hermes` | Set `true` to include Hermes in the sandbox image; state defaults to `~/harness/.hermes`, auth lives in `~/.hermes` |
| `install.grok_build` | Set `true` to include Grok Build in the sandbox image; all Grok user state lives in the persisted `~/.grok` volume |
| `install.codelayer` | Set `true` for exact `@humanlayer/codelayer@0.0.61` bounded local coding-harness support; configure provider credentials and model separately; no remote-daemon support |

Apply changes with `make destroy && make sandbox`.

Expand Down
24 changes: 20 additions & 4 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ curl -fsSL https://oh.mifune.dev/install.sh | bash
cd ~/.openharness && make shell # terminal fallback

# 3 · run your agent inside the sandbox
claude # or codex · pi · hermes · openclaw (coming soon) · opencode
claude # or codex · pi · opencode · optional codelayer

# 4 · optional — Hermes + Slack messaging (in order)
hermes setup # 1. model/provider auth
Expand Down Expand Up @@ -81,6 +81,12 @@ const AGENTS: Array<{
href: "/docs/harnesses/grok-build",
icon: <img src="https://x.ai/favicon.ico" alt="" width={28} height={28} />,
},
{
name: "CodeLayer",
description: "Optional local multi-provider coding harness.",
href: "/docs/harnesses/codelayer",
icon: <CodeLayerIcon />,
},
{
name: "T3 Code",
description: "Browser UI over Claude/Codex/OpenCode (port 3773).",
Expand Down Expand Up @@ -122,7 +128,7 @@ export default function Home(): React.ReactElement {
const starLabel = formatStars(stars);

return (
<Layout description="Open Harness is a portable harness — one repo per sandbox — that wraps your project in an isolated Docker container and versions its state. Run coding agents like Claude Code, Codex, OpenCode, or Pi inside, never straight on your machine.">
<Layout description="Open Harness is a portable harness — one repo per sandbox — that wraps your project in an isolated Docker container and versions its state. Run coding agents like Claude Code, Codex, OpenCode, Pi, or optional CodeLayer inside, never straight on your machine.">
<main>
<section className={styles.hero}>
<div className={styles.heroBg} aria-hidden="true" />
Expand All @@ -136,7 +142,7 @@ export default function Home(): React.ReactElement {
Run coding agents in a sandbox, not on your machine.
</h1>
<p className={styles.heroSubtitle}>
Open Harness is a portable harness: one repo per sandbox that wraps your project in an isolated Docker container and versions its state. Bring your agent — Claude Code, Codex, OpenCode, Pi — and let it work while you sleep.
Open Harness is a portable harness: one repo per sandbox that wraps your project in an isolated Docker container and versions its state. Bring your agent — Claude Code, Codex, OpenCode, Pi, or optional CodeLayer — and let it work while you sleep.
</p>
<div className={styles.heroButtons}>
<Link
Expand Down Expand Up @@ -214,7 +220,7 @@ export default function Home(): React.ReactElement {
<div className={styles.container}>
<h2 className={styles.sectionTitle}>Pick your agent.</h2>
<p className={styles.sectionLede}>
Claude Code, Codex, and Pi ship preinstalled. OpenCode, DeepAgents, Hermes, and Grok Build are opt-in image installs. Switch between them inside the sandbox — or add your own by editing the Dockerfile.
Claude Code, Codex, and Pi ship preinstalled. OpenCode, DeepAgents, Hermes, Grok Build, and bounded local CodeLayer are opt-in image installs. CodeLayer is installed-only until you configure provider credentials; its remote daemon is unsupported. Switch between agents inside the sandbox — or add your own by editing the Dockerfile.
</p>
<div className={styles.agentGrid}>
{AGENTS.map((agent) => {
Expand Down Expand Up @@ -388,6 +394,16 @@ function OpenCodeIcon(): React.ReactElement {
);
}

function CodeLayerIcon(): React.ReactElement {
return (
<svg viewBox="0 0 28 28" width="28" height="28" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<rect x="4" y="5" width="20" height="5" rx="2" fill="currentColor" opacity="0.35" />
<rect x="4" y="12" width="20" height="5" rx="2" fill="currentColor" opacity="0.65" />
<rect x="4" y="19" width="20" height="5" rx="2" fill="currentColor" />
</svg>
);
}

function OpenClawIcon(): React.ReactElement {
return (
<svg viewBox="0 0 28 28" width="28" height="28" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
Expand Down