Experimental. Built on OpenShell, which is itself alpha software. Expect breaking changes in both.
Declarative workflow layer for OpenShell AI agent sandboxes.
harness init # generate a config
harness doctor # check your environment
harness apply -f harness.yaml # launch a sandboxLaunch an interactive coding session with Claude Code or OpenCode.
harness apply --attach # built-in default agent
harness apply -f harness.yaml --attach # agent config in harness.yaml
harness apply -f harness.yaml --attach --entrypoint opencode # OpenCodeharness apply runs against whichever gateway OpenShell has provisioned and you
have selected (openshell gateway select) — local or cluster, the harness YAML
is identical. Provisioning the gateway is OpenShell's job, not the harness's (see
Install).
Run a task headlessly -- the agent executes in a sandbox and outputs results.
harness apply -f harness.yaml --task "review this codebase for security issues"
harness apply -f harness.yaml --task @skills/cpp-pro/SKILL.mdUse base_agent to inherit providers and inference routing from an existing config. The repo field clones the repository outside the sandbox and uploads it -- OpenShell sandboxes have no host mounts by design.
name: reviewer
base_agent: default
repo: https://github.com/stackrox/collector
task: "identify the highest-priority C++ remediation"harness apply -f reviewer.yamlTo get results out: --task mode outputs to stdout, openshell sandbox exec pulls files, or attach a github provider so the agent can push directly via the scoped proxy token.
OpenShell provides a strict, secure sandbox runtime — deny-by-default L7 network policy, credential proxying, Landlock filesystem isolation, and inference routing. It also provisions the gateway itself (the local installer, or helm install openshell on a cluster). What it doesn't provide is the developer workflow layer on top: the config that wires up providers, the declarative reconciliation that makes a gateway match your intent, or the CI harness that catches breakage before developers hit it.
Without a shared harness layer, every team building on OpenShell independently solves the same problems — writing shell scripts to register providers, hand-rolling container images, re-deriving inference routing. The configs diverge, the security posture varies, and nobody catches regressions until something breaks in production.
The design boundary: managing a gateway is OpenShell's problem; the harness is a declarative setup/run layer with zero compute-backend opinion. It never provisions or tears down a gateway — it declares providers, inference, and policy against one OpenShell already stood up, and runs agents in it. That keeps the harness YAML portable: the same file targets a local gateway or a cluster gateway with no target field to change.
The core design constraint: if the developer harness isn't running and live-tested in CI, the developer experience can't be maintained. OpenShell, agent CLIs, and provider APIs all change frequently — often multiple times per week. A harness that works today and isn't continuously validated will silently break. harness-openshell runs the workflow (register providers → reconcile inference → create sandbox → run task) in CI on every change, against gateways provisioned three ways: local Podman, Kind, and OpenShift.
The path from local to automated: a developer runs harness apply --attach for interactive work. When the workflow is ready for CI, they change --attach to --task @skill.md and select a cluster gateway instead of the local one. The harness YAML stays the same. No rewriting. The harness YAML is the artifact — sharable, versionable, forkable.
OpenShell's upstream direction is toward a Kubernetes Operator where providers and sandboxes become CRDs and the gateway narrows to data-plane only. The harness explores what the workflow layer looks like above that with a developer mindset from local machine to cluster.
A single file defines the entrypoint, credential providers, inference routing, environment, and files uploaded to the sandbox. This is the default config (profiles/agent-default.yaml):
name: agent
entrypoint: claude
tty: true
providers:
- profile: github # scoped GITHUB_TOKEN via proxy
- profile: google-vertex-ai # inference routing through gateway
- profile: atlassian # Jira/Confluence via mcp-atlassian
env:
JIRA_URL: # empty = read from host env
JIRA_USERNAME:
- profile: google-workspace # Gmail, Calendar, Drive via gws CLI
env:
ANTHROPIC_BASE_URL: https://inference.local # route inference through gateway proxy
ANTHROPIC_API_KEY: sk-ant-openshell-proxy-managed
CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: "1"
payloads:
- sandbox_path: /sandbox/.claude/CLAUDE.md # agent instructions
local_path: profiles/images/sandbox-default/CLAUDE.md
- sandbox_path: /sandbox/.claude.json # claude code settings
local_path: profiles/images/sandbox-default/claude.json
- sandbox_path: /sandbox/.claude/settings.json # permissions and defaults
local_path: profiles/images/sandbox-default/settings.json
- sandbox_path: /sandbox/.mcp.json # MCP server config (jira, confluence)
local_path: profiles/images/sandbox-default/mcp.jsonCredentials never enter the sandbox -- the gateway proxy resolves placeholder tokens at the network boundary. Each provider also contributes its own L7 network policy endpoints and binary allowlists.
Use harness apply -o yaml to see the fully resolved config -- providers expand to show credential definitions, endpoint policies, scopes, and refresh strategies.
Bundle agent, providers, payloads, and policy in one self-contained file. Use base_agent to inherit from an existing config:
---
kind: agent
name: security-reviewer
base_agent: default # inherits providers, env, payloads
repo: https://github.com/stackrox/collector
task: "review for memory safety issues"
---
kind: payload
sandbox_path: /sandbox/.claude/CLAUDE.md
content: |
You are a C++ security review agent specializing in RAII,
move semantics, and concurrency safety. Focus on the
highest-priority remediation and explain the fix.
---
kind: policy
network_policies:
github_git:
endpoints:
- host: github.com
port: 443
rules:
- allow: { method: GET, path: "/**/info/refs*" }
- allow: { method: POST, path: "/**/git-upload-pack" }
binaries:
- { path: /usr/bin/git }This inherits all four providers and inference routing from agent-default.yaml, adds a custom CLAUDE.md as the agent's instructions, and defines an L7 policy that allows git clone but blocks git push at the HTTP method level.
(OpenShell has already provisioned the gateway; you selected it)
harness apply -f config.yaml
|
+-> Register providers (credentials from host env)
+-> Reconcile inference routing to match the config
+-> Upload payloads (CLAUDE.md, MCP config, skills)
+-> Create sandbox (isolated container, deny-by-default network)
+-> Run task (agent executes, outputs results)
OpenShell provisions the gateway and provides the runtime isolation. The harness provides the workflow.
For runtime operations and policy management, use openshell directly:
openshell sandbox connect <name> # interactive shell
openshell sandbox exec <name> -- ... # run commands
openshell sandbox logs <name> # view logs
openshell policy get <name> # inspect active policy
openshell term # interactive policy terminalopenshell term provides a live view of policy decisions -- which requests are allowed, denied, or pending review. This is how you audit and tune the deny-by-default L7 network policy while an agent is running.
# OpenShell CLI + local gateway, pinned to the version this repo targets
# (.openshell-version). Installs the exact release CI uses and starts the
# managed gateway service (Homebrew/launchd on macOS, systemd on Linux).
make openshell
# Download the harness binary
curl -L https://github.com/stackrox/harness-openshell/releases/latest/download/harness_darwin_arm64 -o harness
chmod +x harnessInstall a bare brew install openshell off the tap and you get whatever version
the formula defaults to — usually behind. make openshell runs the upstream
install.sh at the pinned version instead, so local matches CI exactly.
The installer starts the gateway service; register and select it once:
openshell gateway add https://127.0.0.1:17670 --local --name openshell
openshell gateway select openshellIf you need to restart the service later: brew services restart openshell
(macOS) or systemctl --user restart openshell-gateway (Linux).
Or build the harness from source: make cli
Provisioning a cluster gateway is OpenShell's job too — the harness has no
deploy command. Install the chart, then register and select the gateway:
helm install openshell oci://ghcr.io/nvidia/openshell/helm-chart
openshell gateway add https://<gateway-endpoint> --name my-cluster
openshell gateway select my-cluster
harness apply -f harness.yaml # same YAML, cluster gatewayTear the gateway down with helm uninstall openshell and
openshell gateway remove my-cluster. The harness delete command removes
sandboxes; add --providers (or --all) to remove providers too. It never
removes the gateway.
Migration:
harness deploy,harness teardown,harness status, anddelete --k8sare removed. Provision the gateway with OpenShell (theopenshellinstaller orhelm install openshell); the harness declares providers/inference/policy and runs agents against it.
| Command | What it does |
|---|---|
harness init |
Generate a harness.yaml (interactive or --non-interactive) |
harness doctor |
Validate environment (offline + online checks) |
harness apply -f FILE |
Deploy a sandbox from config |
harness apply --task TEXT |
One-shot headless run |
harness apply --task @FILE |
One-shot from a skill/playbook file |
harness apply --attach |
Interactive TTY mode |
harness apply --dry-run |
Validate without deploying |
harness apply -o yaml |
Output resolved config |
harness get agents|providers|gateways |
List resources |
harness describe <name> |
Sandbox details |
harness delete <name> [--all] |
Tear down |
harness plan -f FILE |
Read-only reconciliation plan (mutates nothing) |
harness migrate -f FILE |
Convert a legacy v1 config to v1alpha1 |
Each provider discovers credentials from the host. Missing providers are skipped.
| Provider | Required |
|---|---|
github |
GITHUB_TOKEN env var |
google-vertex-ai |
gcloud auth application-default login + ANTHROPIC_VERTEX_PROJECT_ID |
atlassian |
JIRA_API_TOKEN + JIRA_URL + JIRA_USERNAME |
google-workspace |
gws auth login (gws CLI) |
| File | Purpose |
|---|---|
profiles/agent-*.yaml |
Agent configs |
profiles/providers/ |
Provider profiles (imported to gateway) |
profiles/images/sandbox-default/ |
Sandbox image defaults (overridable via payloads) |
Tested on macOS (arm64) with Podman. Linux support is expected but not yet validated.
make test # vet + unit tests (16 packages)
make lint # golangci-lint
make test-suite # config parsing (32 tests, no gateway needed)
make test-local # full e2e on local Podman (22 tests)
make test-kind # self-contained kind cluster lifecycle
make test-remote # full e2e on OCP (needs KUBECONFIG)test-local is the primary validation target. It provisions a gateway via the OpenShell installer, registers all 4 providers, creates sandboxes, verifies exec/env/GWS token resolution/MCP config/Claude inference, tests missing-provider recovery, and tears down the sandboxes and providers it created (the gateway is OpenShell's to remove).
test-kind creates its own kind cluster, helm installs OpenShell, builds and loads the sandbox image, runs the full flow, and deletes the cluster on exit. Use KEEP=1 to keep the cluster for debugging.
test-remote requires KUBECONFIG pointing at an OCP cluster and pushes the image automatically. Use --reuse-gateway to skip gateway provisioning/teardown when iterating.
Each integration target builds (and pushes, for remote) the sandbox image automatically.
- GitHub Action -- run harness tasks in CI (review PRs, enforce standards, generate reports)
- Observability -- structured telemetry export (Langfuse, MLflow, OpenTelemetry) for agent tool calls, token usage, and policy decisions
- Skills integration -- first-class support for community skill packs (e.g., awesome-omni-skills) as task inputs
- OpenShell plugin -- register the harness as an
openshellCLI plugin soopenshell harness applyworks natively alongside other openshell commands - Linux validation -- CI and local testing on Linux (currently macOS-only)
| Document | What it is |
|---|---|
| SPEC.md | Behavior spec for the CLI |
| AGENTS.md | Contributor guide |
| TODO.md | Roadmap and upstream tracking |