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 # OpenCodeFor a v1alpha1 workflow, harness apply uses spec.target, --gateway and
--workspace (flag, environment, then config precedence). Legacy configs retain
the selected-gateway fallback. Provisioning the gateway is OpenShell's or
HyperShell'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. The workflow remains portable because its target can be overridden by standard gateway and workspace flags or environment variables.
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. CI exercises the workflow against local and Kind gateways on Linux. OpenShift remains a manually credentialed integration target.
The path from local to automated: a developer runs harness apply --attach
for interactive work, then checks agent arguments and payloads into the v1alpha1
workflow for headless CI. Legacy configs can continue to use --task @skill.md
during migration. The goal is for the same versioned workflow declaration to be
sharable, forkable, and executable in both environments.
Current schema transition: harness plan and harness apply now share strict
parsing, environment resolution, target resolution, and action decisions for
harness.openshell.dev/v1alpha1. Legacy agent files remain accepted by apply
through a compatibility path; use harness migrate to produce the canonical
format. New fields are added only to v1alpha1.
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.
The canonical workflow is accepted by both plan and apply:
apiVersion: harness.openshell.dev/v1alpha1
kind: Harness
metadata:
name: security-review
spec:
target:
gateway: acs
workspace: stackrox
providers:
- name: github-read
management: referenced
sandbox:
image: quay.io/example/security-reviewer:v1
providers: [github-read]
keep: false
tty: false
agent:
type: claude
args: [--print, "Review the repository for security defects"]
source:
repo: https://github.com/stackrox/stackrox
ref: main
destination: /sandbox/stackroxplan is read-only and may render desired state while the gateway is offline.
apply requires the effective gateway to be reachable, verifies referenced
providers before sandbox creation, and disables OpenShell provider auto-discovery.
Managed providers may be updated or explicitly adopted, but apply does not create
credentialed providers; platform bootstrap owns their creation. Relative payload
and policy paths resolve from the workflow file's directory.
Remote-image, non-interactive workflows use the OpenShell SDK for sandbox creation, readiness, execution, and cleanup. Source or payload uploads, local image builds, policy files, and interactive TTYs currently use the OpenShell CLI because those paths do not yet have complete SDK-native implementations.
The legacy Agent YAML remains available during migration. It does not use the canonical v1alpha1 execution path below.
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
|
+-> Verify/reconcile declared providers and inference
+-> 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 |
Render the v1alpha1 action plan without mutating |
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 |
The legacy compatibility path discovers provider credentials from the host and may skip missing providers. Canonical v1alpha1 apply is strict: referenced providers must already exist, and credentialed provider creation is a separate platform/bootstrap responsibility.
| 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) |
Developer testing primarily uses macOS (arm64) with Podman. GitHub Actions runs unit, local-gateway, and Kind integration coverage on Linux. OpenShift integration is available as a manually credentialed target.
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.
| Document | What it is |
|---|---|
| AGENTS.md | Contributor guide |
| docs/ci.md | HyperShell CI bootstrap and repository contract |
| docs/archive/ | Historical design context; not current behavior |