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:
ryaneggzandClaude Opus 4.7 committed 2026-05-14 02:36:15 +00:00
1 parent c6a30a8f96
commit d14bc330eb
17 files changed
+94 -165

No files matched your search

+1 -1
View File
@@ -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
+5 -5
View File
@@ -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
+1 -3
View File
@@ -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
+1 -1
View File
@@ -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
+49
View File
@@ -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:
+4 -5
View File
@@ -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`.
+1
View File
@@ -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`.
+8 -15
View File
@@ -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)
+2 -2
View File
@@ -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>
+3 -3
View File
@@ -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>
-7
View File
@@ -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)
+2 -12
View File
@@ -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
-4
View File
@@ -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
View File
@@ -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`.
-72
View File
@@ -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.
+1 -21
View File
@@ -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
View File
@@ -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