task: cloudflared/SSH/host-overlay doc cleanup (keep postgres)
Apply PR #284's doc updates selectively — cloudflared, SSH overlays, host-bind overlays, SANDBOX_PASSWORD, and openssh-server references removed everywhere. Postgres mentions preserved; postgres compose overlay restored. Doc edits: - AGENTS.md / CLAUDE.md (symlink): drop /cloudflared-tunnel skill row, rewrite "Exposing apps" to mention generic tunnels/proxies. - README.md, docs/installation.md: drop SANDBOX_PASSWORD, cloudflared, openssh-server, host-overlay references. - docs/quickstart.md: keep postgres link, drop cloudflare link, mention postgres overlay is opt-in. - docs/integrations/github.md: drop SSH-overlay section. - docs/integrations/cloudflare.md: deleted. - docs/agents/{deepagents,opencode}.md: drop host-overlay sections. - context/rules/git.md: drop "Advanced opt-ins" SSH section. - Makefile: drop _check-jq / _check-config gates; jq invocation is now defensive (only runs when jq + config.json both present). - apps/docs/src/pages/index.tsx: keep postgres in "composable substrate" copy, drop cloudflare tunnels / Caddy gateway mentions. - .claude/skills/{agent-browser,harness-audit,strategic-proposal}/SKILL.md and .claude/agents/command-builder.md: drop cloudflared references (strategic-proposal infra row keeps PostgreSQL 16). - CHANGELOG.md [Unreleased] § Removed: new entry for #283 listing the 10 deleted overlays + companion infrastructure; note postgres was kept. Infra: - Restored .devcontainer/docker-compose.postgres.yml. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
c6a30a8f96
commit
d14bc330eb
17 files changed
+94
-165
No files matched your search
@@ -117,7 +117,7 @@ Yes if it has side effects, is invoked deliberately by the user, and runs end-to
|
||||
ls .claude/skills/
|
||||
```
|
||||
|
||||
Pick 2-3 task-shaped exemplars (e.g., this project's `release`, `ci-status`, `cloudflared-tunnel`) and read their SKILL.md to match house style — section structure, command-quoting conventions, how reports are formatted.
|
||||
Pick 2-3 task-shaped exemplars (e.g., this project's `release`, `ci-status`, `agent-browser`) and read their SKILL.md to match house style — section structure, command-quoting conventions, how reports are formatted.
|
||||
|
||||
### Phase 3 — Author SKILL.md
|
||||
|
||||
|
||||
@@ -74,8 +74,8 @@ Rationale for the pins:
|
||||
- **0.8.5** — later majors have breaking CLI changes; the rest of this
|
||||
skill targets 0.8.5's flags.
|
||||
|
||||
Or rebuild the image with `INSTALL_BROWSER=true` in the compose overlay
|
||||
to bake this in.
|
||||
Or rebuild the image with `INSTALL_AGENT_BROWSER=true` in
|
||||
`.devcontainer/.env` to bake this in.
|
||||
|
||||
After installing, resume the health check from step 2b — **do not stop**.
|
||||
|
||||
@@ -123,7 +123,7 @@ agent-browser close
|
||||
|
||||
### Step 2d — DNS resolution check (tunnel hostnames)
|
||||
|
||||
If the URL contains a hostname that routes through a cloudflared tunnel (any `<name>.<your-domain>` served via cloudflared), the container's DNS may not resolve it. Check and fix:
|
||||
If the URL contains a hostname served by a tunnel or reverse proxy, the container's DNS may not resolve it yet. Check and fix:
|
||||
|
||||
```bash
|
||||
HOSTNAME=$(echo "$URL" | sed 's|https\?://||; s|/.*||; s|:.*||')
|
||||
@@ -135,7 +135,7 @@ if ! getent hosts "$HOSTNAME" &>/dev/null; then
|
||||
echo "$IP $HOSTNAME" | sudo tee -a /etc/hosts >/dev/null
|
||||
echo "Added $HOSTNAME -> $IP to /etc/hosts (container DNS didn't resolve it)"
|
||||
else
|
||||
echo "FAIL: $HOSTNAME does not resolve. Check cloudflared tunnel DNS routing."
|
||||
echo "FAIL: $HOSTNAME does not resolve. Check tunnel/DNS routing."
|
||||
# Stop here
|
||||
fi
|
||||
fi
|
||||
@@ -177,7 +177,7 @@ FILENAME=$(echo "$URL" | sed 's|https\?://||; s|/|--|g; s|--$||; s|[^a-zA-Z0-9._
|
||||
agent-browser screenshot ".claude/screenshots/${FILENAME}.png"
|
||||
```
|
||||
|
||||
Example: `https://my-app.oh-local.localhost:8443/guide/exposure/` → `.claude/screenshots/my-app.oh-local.localhost-8443--guide--exposure.png`
|
||||
Example: `https://my-app.oh-local.localhost:8443/guide/configuration/` → `.claude/screenshots/my-app.oh-local.localhost-8443--guide--configuration.png`
|
||||
|
||||
### Step 5 — Report
|
||||
|
||||
|
||||
@@ -176,8 +176,6 @@ Launch 4 Agent tool calls **in a single message**. Each receives the Context Sna
|
||||
>
|
||||
> 4. **State corruption risks** — Look for: shared files written by multiple agents concurrently (e.g., `MEMORY.md`), no file locking on append operations, mid-commit crash scenarios (partial writes to critical files), compose volumes that could diverge.
|
||||
>
|
||||
> 5. **Tunnel fragility** — Check `.claude/skills/cloudflared-tunnel/SKILL.md` and any compose services named `tunnel` or `cloudflared`. Is there auto-restart? Health monitoring? What happens if the tunnel drops silently?
|
||||
>
|
||||
> **Return format (Ultra compression):**
|
||||
> ```
|
||||
> CRITIC_FINDINGS
|
||||
@@ -282,7 +280,7 @@ See `context/rules/memory.md` for the canonical Memory Improvement Protocol.
|
||||
|---------|--------------|
|
||||
| PM | Onboarding, skill consistency, issue templates, wiki/memory utilization |
|
||||
| Implementer | Startup reliability, test coverage, CI/CD, package health, compose overlays |
|
||||
| Critic | Security, heartbeat reliability, worktree cleanup, state corruption, tunnel |
|
||||
| Critic | Security, heartbeat reliability, worktree cleanup, state corruption |
|
||||
| Explorer | Memory quality, wiki utilization, heartbeat health, worktree status, skill usage |
|
||||
|
||||
### Severity and effort definitions
|
||||
|
||||
@@ -82,7 +82,7 @@ Assemble a structured markdown briefing to pass to ALL 5 experts:
|
||||
- API routes: none
|
||||
|
||||
### Infrastructure
|
||||
- Docker Compose + PostgreSQL 16 + cloudflared tunnel
|
||||
- Docker Compose + opt-in PostgreSQL 16 overlay
|
||||
- CI/CD: GitHub Actions (lint, format, type-check, build, test, E2E)
|
||||
- Release: CalVer → GHCR Docker image
|
||||
- Agent: 8 skills, 7 sub-agents, 4 heartbeats, memory protocol
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# PostgreSQL Service Overlay
|
||||
# ===========================
|
||||
# Purpose: Run PostgreSQL 16 as a sibling service for sandbox database operations.
|
||||
# Default credentials: user=sandbox, password=sandbox, database=sandbox
|
||||
# Network: Sandbox and postgres share isolated network (devnet) for inter-service communication
|
||||
# Storage: pgdata volume persists database across container restarts
|
||||
# Health: Includes healthcheck; sandbox waits for postgres to be ready before starting
|
||||
# Environment vars injected into sandbox: DATABASE_URL, PGHOST, PGUSER, PGPASSWORD, PGDATABASE
|
||||
# Usage: docker compose -f docker-compose.yml -f docker-compose.postgres.yml up
|
||||
# Connection: psql postgresql://sandbox:sandbox@postgres:5432/sandbox (from inside sandbox)
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: ${SANDBOX_NAME:-openharness}-postgres
|
||||
environment:
|
||||
POSTGRES_USER: sandbox
|
||||
POSTGRES_PASSWORD: sandbox
|
||||
POSTGRES_DB: sandbox
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U sandbox"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- devnet
|
||||
|
||||
sandbox:
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://sandbox:sandbox@postgres:5432/sandbox
|
||||
- PGHOST=postgres
|
||||
- PGUSER=sandbox
|
||||
- PGPASSWORD=sandbox
|
||||
- PGDATABASE=sandbox
|
||||
networks:
|
||||
- devnet
|
||||
|
||||
networks:
|
||||
devnet:
|
||||
name: ${SANDBOX_NAME:-openharness}-devnet
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
@@ -107,7 +107,6 @@ Remove the sandbox.
|
||||
|-------|------|
|
||||
| `/release` | CalVer release — branch, tag, push, GHCR |
|
||||
| `/ci-status` | After `git push` — poll CI, report pass/fail |
|
||||
| `/cloudflared-tunnel` | One-time named tunnel setup (remote mode) |
|
||||
| `/agent-browser` | Open a URL headless for screenshots / preview checks |
|
||||
| `/prd` | Generate a new PRD from a feature description |
|
||||
| `/ralph` | Convert markdown PRD → `tasks/<name>/prd.json` for the Ralph runner |
|
||||
@@ -122,10 +121,10 @@ the `Lifecycle` section above. There is no dedicated skill.
|
||||
|
||||
## Exposing apps
|
||||
|
||||
There is no first-class exposure tool right now. For external access,
|
||||
either enable the `cloudflared` compose overlay (see
|
||||
`docs/integrations/cloudflare.md`) or stand up your own reverse proxy
|
||||
in front of the sandbox.
|
||||
There is no first-class exposure tool. For external access, stand up
|
||||
your own reverse proxy (nginx/Caddy/Traefik) or tunnel (cloudflared,
|
||||
ngrok, tailscale-funnel) in front of the sandbox — the base ships
|
||||
without any of these.
|
||||
|
||||
Long-running apps inside the sandbox go in named tmux sessions, related
|
||||
apps as stacked panes — see `context/rules/sandbox-processes.md`.
|
||||
|
||||
@@ -9,6 +9,7 @@ Update policy and release automation live in [`.claude/rules/git.md`](.claude/ru
|
||||
## [Unreleased]
|
||||
|
||||
### Removed
|
||||
- In-tree docker-compose overlays under `.devcontainer/` except `docker-compose.postgres.yml`: the five host-auth overlays (`claude-host.yml`, `codex-host.yml`, `opencode-host.yml`, `pi-host.yml`, `deepagents-host.yml`), the three SSH overlays (`ssh.yml`, `ssh-generate.yml`, `sshd.yml`), `git.yml`, and `cloudflared.yml`. The host-auth overlays existed to share host agent credentials when the host UID matched the sandbox's UID 1000; `.devcontainer/entrypoint.sh` now syncs the sandbox user's UID/GID to the bind-mounted repo's owner on boot (replacing the host-group-membership workaround), so files written in either direction stay readable without per-agent overlays. Agent auth still persists in named volumes (`claude-auth`, `codex-auth`, `pi-auth`, `opencode-auth`, `deepagents-auth`, `cloudflared-auth`, `gh-config`); `gh auth login` covers git over HTTPS without per-overlay setup. Postgres remains opt-in via `docker-compose.postgres.yml`. Removed companion infrastructure: `install/cloudflared-tunnel.sh`, the `/cloudflared-tunnel` skill, the `*_HOST_BIND_MOUNT` / `SANDBOX_PASSWORD` / `INSTALL_BROWSER` / `INSTALL_CLOUDFLARED` / `GIT_COMMON_DIR` / `HOST_SSH_DIR` / `HOST_*_DIR` env plumbing in `.devcontainer/entrypoint.sh`, and the host-UID overlay-stripping block in `scripts/install.sh`. Deleted doc: `docs/integrations/cloudflare.md`. The `composeOverrides[]` mechanism in `config.json` is retained so downstream packs (Pi extensions, BYO harness packs) can still register their own overlays. ([#283](https://github.com/ryaneggz/open-harness/issues/283))
|
||||
- Orphaned `.pi/onboard-steps/slack.ts` (and the empty `.pi/onboard-steps/` directory). The wizard logic lives in `apps/oh/src/config/slack.ts` now, with the bugs from the original mifune port fixed (correct tmux session name `agent-pi`, real `pi` launch path, token-prefix validation, allowlist-ID validation, atomic env-file merge). ([#281](https://github.com/ryaneggz/open-harness/issues/281))
|
||||
- Stale documentation pages: `docs/onboarding.md`, `docs/sandbox-lifecycle.md`, `docs/connecting.md`, `docs/operations/{provision,destroy,repair}.md`, and `docs/architecture/{overview,container-runtime,crons-and-heartbeats}.md`. These pages described flows and tooling that no longer match the harness; rather than rewrite them, the docs site is trimmed to `intro`, `quickstart`, `installation`, and the `guide` / `agents` / `integrations` sections as the smaller accurate foundation. `context/rules/repo-layout-source.md` is also removed — it pinned `docs/architecture/container-runtime.md#repo-layout` as the canonical repo-tree source; with that file gone, the rule has no anchor. Cross-references in `AGENTS.md` (which is `CLAUDE.md` via symlink), `README.md`, `docs/intro.md`, `tasks/README.md`, `apps/README.md`, `crons/README.md`, `.claude/skills/harness-context/SKILL.md`, `context/rules/directory-readme.md`, `context/rules/memory.md`, `context/README.md`, `context/rules/README.md`, `.devcontainer/.example.env`, and `apps/docs/src/pages/index.tsx` updated to point at surviving docs or removed where they no longer apply. The brief `## Project Structure` block in `AGENTS.md` plus per-directory `README.md` files now stand in for the deleted repo-layout tree. ([#279](https://github.com/ryaneggz/open-harness/issues/279))
|
||||
- `.pi/overlays/docker-compose.slack.yml` and all references to it. The in-tree Pi extension at `.pi/extensions/slack/` reads `SLACK_APP_TOKEN` / `SLACK_BOT_TOKEN` directly from `process.env` at `session_start`, so the compose-time wiring overlay is redundant. `docs/integrations/slack.md`, `README.md`, `docs/architecture/container-runtime.md`, `docs/guide/bring-your-own-harness.md`, `.devcontainer/docker-compose.yml`, and `.devcontainer/.example.env` no longer reference the overlay; `.pi/overlays/` directory removed. Source of truth for Slack env wiring is `.pi/extensions/slack/README.md`.
|
||||
|
||||
@@ -5,26 +5,19 @@
|
||||
|
||||
SANDBOX_NAME ?= openharness
|
||||
COMPOSE_BASE := -f .devcontainer/docker-compose.yml
|
||||
COMPOSE_OVERRIDES := $(shell jq -r '.composeOverrides[]?' \
|
||||
config.json 2>/dev/null | sed 's|^|-f |' | tr '\n' ' ')
|
||||
# Base ships with no required overlays. Downstream packs (Pi extensions,
|
||||
# BYO harness packs) register their own by appending paths to
|
||||
# composeOverrides[] in config.json; jq is only invoked when both jq and
|
||||
# config.json are present.
|
||||
COMPOSE_OVERRIDES := $(shell command -v jq >/dev/null 2>&1 && [ -f config.json ] && \
|
||||
jq -r '.composeOverrides[]?' config.json 2>/dev/null | sed 's|^|-f |' | tr '\n' ' ')
|
||||
COMPOSE := docker compose $(COMPOSE_BASE) $(COMPOSE_OVERRIDES)
|
||||
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
.PHONY: sandbox shell destroy stop logs ps restart help _check-jq _check-config
|
||||
.PHONY: sandbox shell destroy stop logs ps restart help
|
||||
|
||||
_check-jq:
|
||||
@command -v jq >/dev/null 2>&1 || { \
|
||||
echo "ERROR: jq is required to expand config.json composeOverrides."; \
|
||||
echo "Install jq (e.g. apt install jq, brew install jq) and re-run."; \
|
||||
exit 1; }
|
||||
|
||||
_check-config:
|
||||
@[ -f config.json ] || { \
|
||||
echo "ERROR: config.json missing. Run scripts/install.sh, OR: cp config.example.json config.json"; \
|
||||
exit 1; }
|
||||
|
||||
sandbox: _check-jq _check-config ## Provision and start the sandbox
|
||||
sandbox: ## Provision and start the sandbox
|
||||
$(COMPOSE) up -d --build
|
||||
|
||||
shell: ## Connect to the sandbox (agent choice happens inside)
|
||||
|
||||
@@ -42,8 +42,8 @@ Prefer VS Code or remote SSH? Use the Dev Containers extension's "Attach to Runn
|
||||
|
||||
`.devcontainer/.env` is generated with safe defaults during install. Open
|
||||
it any time to change `SANDBOX_NAME`, set a different `GH_TOKEN`, change
|
||||
`TZ`, set `SANDBOX_PASSWORD` (sshd overlay), or set `SLACK_*` tokens for
|
||||
the Pi Slack extension. Apply with `make destroy && make sandbox`.
|
||||
`TZ`, or set `SLACK_*` tokens for the Pi Slack extension. Apply with
|
||||
`make destroy && make sandbox`.
|
||||
|
||||
<details><summary>Manual setup (no installer)</summary>
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ const WHY: Array<{ title: string; body: string }> = [
|
||||
},
|
||||
{
|
||||
title: "Composable substrate",
|
||||
body: "Postgres, Cloudflare tunnels, SSH, the Caddy gateway — cherry-pick via Compose overlays. Multi-agent setups ship as separate harness packs.",
|
||||
body: "Postgres ships as an opt-in compose overlay; add tunnels, reverse proxies, or multi-agent setups as harness packs.",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -185,7 +185,7 @@ export default function Home(): React.ReactElement {
|
||||
Open Harness runs as a single long-lived Docker container dedicated to your project. The bind-mounted <code>workspace/</code> houses whatever your project needs — one repo, several, side-by-side branches, scratch dirs. The agent owns its workspace; your laptop stays clean.
|
||||
</p>
|
||||
<p>
|
||||
A markdown cron runtime reads <code>crons/*.md</code> and wakes the agent on a schedule — issue triage, PR review, background grooming, anything you want running while you sleep. Configure the sandbox via <code>.devcontainer/.env</code>; add infra (Postgres, Cloudflare tunnels, SSH, Caddy gateway) via Compose overlays.
|
||||
A markdown cron runtime reads <code>crons/*.md</code> and wakes the agent on a schedule — issue triage, PR review, background grooming, anything you want running while you sleep. Configure the sandbox via <code>.devcontainer/.env</code>; Postgres ships as an opt-in compose overlay, and additional infra (tunnels, reverse proxies) is registered via harness-pack overlays in <code>config.json</code>.
|
||||
</p>
|
||||
<p>
|
||||
Multi-agent setups — like a Pi+Mom Slack bot — ship as separate harness packs you <code>git clone</code> into the workspace.
|
||||
@@ -220,7 +220,7 @@ export default function Home(): React.ReactElement {
|
||||
<Link className={styles.linkCard} to="/docs">
|
||||
<span className={styles.linkCardLabel}>Documentation</span>
|
||||
<span className={styles.linkCardSub}>
|
||||
Quickstart, architecture, overlays
|
||||
Quickstart, architecture, agents
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -34,13 +34,6 @@ Detect via `git show-ref --verify --quiet refs/heads/<name>` (or remote `refs/re
|
||||
|
||||
Inside sandbox, run `gh auth login && gh auth setup-git` during onboarding. GitHub CLI installs credential helper — `git push` / `git fetch` use your GitHub token — no SSH keys required.
|
||||
|
||||
Advanced opt-ins (only when git-over-SSH explicitly needed):
|
||||
|
||||
- `docker-compose.ssh.yml` — mounts host `~/.ssh` read-only (reuses existing keys)
|
||||
- `docker-compose.ssh-generate.yml` — generates persistent ED25519 keypair in named volume (add to GitHub manually)
|
||||
|
||||
Mutually exclusive — pick at most one. Both off by default.
|
||||
|
||||
## PR Titles
|
||||
|
||||
Format: `FROM <source-branch> TO <target-branch>` (literal)
|
||||
|
||||
@@ -61,15 +61,6 @@ on PATH and **configured** only when `~/.deepagents/.env` or
|
||||
`~/.deepagents/config.toml` is non-empty — an empty mounted directory is
|
||||
not treated as authenticated.
|
||||
|
||||
### Reusing host DeepAgents state
|
||||
|
||||
If you already use DeepAgents on the host, opt in to the
|
||||
`deepagents-host` overlay to bind-mount your host `~/.deepagents` into the
|
||||
sandbox. The overlay requires host UID 1000 and a pre-existing host
|
||||
`~/.deepagents` directory; DeepAgents stores raw provider API keys with no
|
||||
scope or expiry, so enable it only when you've accepted that blast radius
|
||||
explicitly.
|
||||
|
||||
## State persistence and repo-local `.deepagents/`
|
||||
|
||||
Two separate directories carry DeepAgents state, with very different
|
||||
@@ -77,7 +68,7 @@ durability and review semantics:
|
||||
|
||||
| Path | Scope | Persistence | Notes |
|
||||
|---|---|---|---|
|
||||
| `~/.deepagents/` | Per-sandbox user state | Survives rebuilds via the `deepagents-auth` volume (or host bind-mount) | Provider keys, model defaults, memory, skills, sessions live here. **Only place secrets here.** |
|
||||
| `~/.deepagents/` | Per-sandbox user state | Survives rebuilds via the `deepagents-auth` volume | Provider keys, model defaults, memory, skills, sessions live here. **Only place secrets here.** |
|
||||
| `<repo>/.deepagents/` | Per-project | Whatever git decides | Project memory and skills the agent may load from the workspace root. **Treat as project data — follows normal `.gitignore` and code-review rules.** |
|
||||
|
||||
A repo-local `.deepagents/` directory may be read by the agent and may be
|
||||
@@ -156,8 +147,7 @@ Two environment overrides apply:
|
||||
> via `RALPH_DEEPAGENTS_FLAGS` grants unrestricted non-interactive shell
|
||||
> execution. Combined with the mounted Docker socket (enabled by default
|
||||
> in the base compose file), this can affect sibling containers or the
|
||||
> host Docker daemon, and combined with the `deepagents-host` overlay can
|
||||
> reach raw host provider keys. Only use `all` for trusted tasks where
|
||||
> host Docker daemon. Only use `all` for trusted tasks where
|
||||
> you have accepted that risk explicitly.
|
||||
|
||||
## Tips
|
||||
|
||||
@@ -50,10 +50,6 @@ tmux new-session -d -s agent-opencode 'opencode'
|
||||
tmux attach -t agent-opencode
|
||||
```
|
||||
|
||||
## Host auth overlay
|
||||
|
||||
The `opencode-host` overlay bind-mounts your host OpenCode state from `~/.local/share/opencode` into the sandbox. Enable it only for trusted workflows, because any code running in the sandbox can read those credentials.
|
||||
|
||||
## Upstream documentation
|
||||
|
||||
- [OpenCode CLI](https://opencode.ai/docs/cli/)
|
||||
|
||||
+12
-12
@@ -26,7 +26,7 @@ The installer:
|
||||
|
||||
1. Verifies Docker and git are present.
|
||||
2. Clones the repo into `~/.openharness` (or pulls latest if the directory already exists).
|
||||
3. Prompts for `SANDBOX_NAME` and `SANDBOX_PASSWORD`, then writes `.devcontainer/.env`.
|
||||
3. Prompts for `SANDBOX_NAME`, then writes `.devcontainer/.env`.
|
||||
4. Runs `docker compose -f .devcontainer/docker-compose.yml up -d --build`.
|
||||
5. Prints the next-step commands (open a shell, stop, tear down).
|
||||
|
||||
@@ -37,9 +37,8 @@ The installer:
|
||||
| `OH_INSTALL_REF=<git-ref>` | Pin the cloned repo to a specific tag or SHA instead of `main`. |
|
||||
| `OH_ASSUME_YES=1` | Accept defaults at every prompt. |
|
||||
| `SANDBOX_NAME=<name>` | Skip the "Container name" prompt. |
|
||||
| `SANDBOX_PASSWORD=<value>` | Skip the credential prompt (used by the optional `sshd` overlay). |
|
||||
|
||||
`SANDBOX_NAME` and `SANDBOX_PASSWORD` resolve independently — set one and the other still prompts. Both fall back to defaults (`openharness` and `changeme`) when no TTY is available.
|
||||
`SANDBOX_NAME` falls back to the default (`openharness`) when no TTY is available.
|
||||
|
||||
## Manual installation
|
||||
|
||||
@@ -112,9 +111,8 @@ Debian Bookworm (slim). The `sandbox` user has passwordless sudo.
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| Docker CLI + Compose | Container management from inside the sandbox (with docker overlay) |
|
||||
| Docker CLI + Compose | Container management from inside the sandbox (host docker socket bind-mounted by the base compose) |
|
||||
| GitHub CLI (`gh`) | PRs, issues, releases from the terminal |
|
||||
| cloudflared | Cloudflare Tunnel for public URLs to dev servers |
|
||||
| tmux | Detachable terminal sessions for long-running agents |
|
||||
| croner | Markdown-frontmatter cron scheduler for autonomous agent tasks |
|
||||
|
||||
@@ -127,7 +125,7 @@ Debian Bookworm (slim). The `sandbox` user has passwordless sudo.
|
||||
| ripgrep (`rg`) | Fast code search |
|
||||
| curl, wget | HTTP clients |
|
||||
| nano | Text editor |
|
||||
| openssh-server | SSH server (enabled via sshd overlay) |
|
||||
| openssh-client | `ssh-keygen` for GitHub auth flows |
|
||||
| bash-completion | Tab completion |
|
||||
|
||||
### Shell aliases
|
||||
@@ -143,10 +141,12 @@ codex → codex --dangerously-bypass-approvals-and-sandbox
|
||||
|
||||
Auth credentials survive container rebuilds via named Docker volumes:
|
||||
|
||||
- `claude-auth` → `~/.claude` (Claude Code OAuth) — or, with the `claude-host` overlay, a RW bind-mount of your host `~/.claude`.
|
||||
- `codex-auth` → `~/.codex` (Codex OAuth) — or, with the `codex-host` overlay, a RW bind-mount of your host `~/.codex`.
|
||||
- `opencode-auth` → `~/.local/share/opencode` (OpenCode OAuth; `auth.json`) — or, with the `opencode-host` overlay, a RW bind-mount of your host `~/.local/share/opencode`.
|
||||
- `pi-auth` → `~/.pi` (Pi Agent OAuth) — or, with the `pi-host` overlay, a RW bind-mount of your host `~/.pi`.
|
||||
- `deepagents-auth` → `~/.deepagents` (DeepAgents provider keys, memory, skills, sessions) — or, with the `deepagents-host` overlay, a RW bind-mount of your host `~/.deepagents`. Repo-local `.deepagents/` is **project data** and follows normal `.gitignore` and code-review rules — never put secrets there.
|
||||
- `cloudflared-auth` → `~/.cloudflared` (Cloudflare credentials)
|
||||
- `claude-auth` → `~/.claude` (Claude Code OAuth)
|
||||
- `codex-auth` → `~/.codex` (Codex OAuth)
|
||||
- `opencode-auth` → `~/.local/share/opencode` (OpenCode OAuth; `auth.json`)
|
||||
- `pi-auth` → `~/.pi` (Pi Agent OAuth)
|
||||
- `deepagents-auth` → `~/.deepagents` (DeepAgents provider keys, memory, skills, sessions). Repo-local `.deepagents/` is **project data** and follows normal `.gitignore` and code-review rules — never put secrets there.
|
||||
- `cloudflared-auth` → `~/.cloudflared` (Cloudflare tunnel credentials, when used)
|
||||
- `gh-config` → `~/.config/gh` (GitHub CLI tokens)
|
||||
|
||||
Downstream harness packs and Pi extensions can introduce additional volumes or bind-mount overlays by adding their own compose file to `composeOverrides[]` in `config.json`.
|
||||
@@ -1,72 +0,0 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
title: "Cloudflare"
|
||||
---
|
||||
|
||||
# Cloudflare
|
||||
|
||||
Open Harness exposes sandbox apps to the public internet via **Cloudflare named tunnels**. Use the `/cloudflared-tunnel` skill (or run `install/cloudflared-tunnel.sh` directly) to create a tunnel, write its ingress config, and route DNS — all in one idempotent step.
|
||||
|
||||
## Enabling the cloudflared overlay
|
||||
|
||||
To install `cloudflared` inside the sandbox, add the cloudflared overlay at startup:
|
||||
|
||||
```bash
|
||||
docker compose \
|
||||
-f .devcontainer/docker-compose.yml \
|
||||
-f .devcontainer/docker-compose.cloudflared.yml \
|
||||
up -d --build
|
||||
```
|
||||
|
||||
This sets `INSTALL_CLOUDFLARED=true` in the container environment. The entrypoint installs the `cloudflared` binary to `/usr/local/bin/cloudflared` during container startup.
|
||||
|
||||
## Named tunnels via cloudflared-tunnel.sh
|
||||
|
||||
For persistent public URLs tied to a Cloudflare-managed domain, use `install/cloudflared-tunnel.sh`. This script creates a named tunnel, writes the ingress config, and routes DNS — all idempotently. The `/cloudflared-tunnel` skill drives this same script with the canonical onboarding flow (prereq checks, multi-ingress YAML, DNS routing, optional `--run`, post-start verification).
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. `cloudflared` installed (provided by the cloudflared overlay above).
|
||||
2. Authenticated with Cloudflare: `cloudflared login` (opens browser, saves `~/.cloudflared/cert.pem`).
|
||||
3. A domain managed in your Cloudflare account.
|
||||
|
||||
### Usage
|
||||
|
||||
Single ingress:
|
||||
|
||||
```bash
|
||||
install/cloudflared-tunnel.sh <tunnel-name> <hostname> <local-port>
|
||||
```
|
||||
|
||||
Multiple ingress routes:
|
||||
|
||||
```bash
|
||||
install/cloudflared-tunnel.sh <tunnel-name> <hostname>:<port> [<hostname>:<port> ...]
|
||||
```
|
||||
|
||||
Start the tunnel immediately after configuration:
|
||||
|
||||
```bash
|
||||
install/cloudflared-tunnel.sh myproject app.example.com:3000 api.example.com:3001 --run
|
||||
```
|
||||
|
||||
Replace `example.com` with your own Cloudflare-managed domain.
|
||||
|
||||
### Running the tunnel in tmux
|
||||
|
||||
For a long-lived tunnel, run it in a named tmux session:
|
||||
|
||||
```bash
|
||||
tmux new-session -d -s expose-public-3000 \
|
||||
'cloudflared tunnel run myproject 2>&1 | tee /tmp/expose-public-3000.log'
|
||||
```
|
||||
|
||||
Attach to inspect logs:
|
||||
|
||||
```bash
|
||||
tmux attach -t expose-public-3000
|
||||
```
|
||||
|
||||
### Driving the flow with the skill
|
||||
|
||||
Prefer the `/cloudflared-tunnel` skill when working interactively — it parses arguments, checks prerequisites, creates or reuses the tunnel, writes `~/.cloudflared/config-<tunnel-name>.yml`, routes DNS for every hostname, and (with `--run`) starts the tunnel and verifies each hostname end-to-end. See `.claude/skills/cloudflared-tunnel/SKILL.md` for the canonical step-by-step.
|
||||
@@ -40,26 +40,6 @@ gh run list --branch feat/my-feature
|
||||
gh issue view 42
|
||||
```
|
||||
|
||||
## Optional SSH overlays
|
||||
|
||||
For cases where Git-over-SSH is required (custom Git servers, deploy keys, or workflows that do not support HTTPS), two compose overlays are available:
|
||||
|
||||
| Overlay | Behavior |
|
||||
|---|---|
|
||||
| `docker-compose.ssh.yml` | Mounts your host `~/.ssh` directory into the sandbox read-only. Uses your existing SSH keys without copying them. |
|
||||
| `docker-compose.ssh-generate.yml` | Generates a new persistent ED25519 keypair in a named Docker volume. The public key must be added to GitHub manually before use. |
|
||||
|
||||
These overlays are mutually exclusive — use at most one. Both are off by default. Add one when starting the sandbox:
|
||||
|
||||
```bash
|
||||
docker compose \
|
||||
-f .devcontainer/docker-compose.yml \
|
||||
-f .devcontainer/docker-compose.ssh.yml \
|
||||
up -d --build
|
||||
```
|
||||
|
||||
For most users, `gh auth login` and `gh auth setup-git` are sufficient and no SSH overlay is needed.
|
||||
|
||||
## Persisting credentials across restarts
|
||||
|
||||
The `gh` token is stored inside the container at `~/.config/gh/`. Because this path is inside the container, it is lost when the container is removed. To persist credentials across `docker compose down -v` cycles, either re-run `gh auth login` after each rebuild, or bind-mount a host directory to `~/.config/gh/` via a custom compose overlay.
|
||||
The `gh` token is stored inside the container at `~/.config/gh/`, backed by the named `gh-config` volume. The token survives `docker compose down` and `docker compose up` cycles. `docker compose down -v` removes the volume — re-run `gh auth login` after a `down -v`, or register your own compose overlay in `config.json` `composeOverrides[]` to bind-mount a host directory to `~/.config/gh/`.
|
||||
+4
-2
@@ -70,7 +70,10 @@ safe defaults during install. The most-edited values:
|
||||
|
||||
Apply changes with `make destroy && make sandbox`.
|
||||
|
||||
For Postgres, Cloudflare tunnels, SSH, etc., chain compose overlays from `.devcontainer/`.
|
||||
For additional services, the base ships with an opt-in Postgres overlay
|
||||
at `.devcontainer/docker-compose.postgres.yml`; for anything else
|
||||
(tunnels, reverse proxies), register your own compose overlay by
|
||||
appending it to `composeOverrides[]` in `config.json`.
|
||||
|
||||
## Next steps
|
||||
|
||||
@@ -79,7 +82,6 @@ With the sandbox running, here's what to wire up next:
|
||||
- Slack bridge for your sandbox agent → [integrations/slack.md](./integrations/slack.md)
|
||||
- GitHub auth (only if you skipped `GH_TOKEN` at install) → [integrations/github.md](./integrations/github.md)
|
||||
- Postgres via Compose overlay → [integrations/postgres.md](./integrations/postgres.md)
|
||||
- Cloudflare tunnels for external access → [integrations/cloudflare.md](./integrations/cloudflare.md)
|
||||
|
||||
## Tear down
|
||||
|
||||
|
||||
Reference in new issue
Block a user