# Changelog All notable changes to this project are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions use CalVer (`YYYY.M.D` with `-N` suffix for same-day releases) and match git tags. Update policy and release automation live in [`.claude/rules/git.md`](.claude/rules/git.md) § Changelog. ## [Unreleased] ### Added ### Changed ### Fixed ### Removed ### Deprecated ### Security ## [2026.5.24] - 2026-05-24 ### Added - `wiki/` directory + `context/rules/wiki.md` schema for Karpathy LLM Wiki pattern ([#351](https://github.com/ryaneggz/open-harness/pull/351)). - `/wiki-ingest` skill (`.claude/skills/wiki-ingest/SKILL.md`) — captures `WebFetch` snapshots and authors/updates wiki entries; supports URL/path ingest + `--from-draft` promotion; orchestrator-only writes; body-merge per `context/rules/wiki.md` § 7 ([#351](https://github.com/ryaneggz/open-harness/pull/351)). - `/wiki-query` skill (`.claude/skills/wiki-query/SKILL.md`) — frontmatter-only grep against `wiki/*.md` (title, slug, tags) using the canonical extraction from `context/rules/wiki.md` § 6; multi-word OR semantics; sub-cap reads all when < 3, top 3 by `updated:` descending otherwise ([#351](https://github.com/ryaneggz/open-harness/pull/351)). - `/wiki-lint` skill (`.claude/skills/wiki-lint/SKILL.md`) — manual health check for the wiki corpus: five finding types (stale-90d, deprecated, orphan, broken outbound link, contradiction-stub-descoped); atomic `wiki/README.md` regeneration with tmp-then-rename + validation; `--dry-run` flag for read-only audits; reports `confidence: deprecated` entries but never autonomously sets the flag (per `context/rules/wiki.md` § 5 lifecycle) ([#351](https://github.com/ryaneggz/open-harness/pull/351)). - `/reflect` skill (`.claude/skills/reflect/SKILL.md`) — deliberate whole-session "Improve" pass that operationalizes the Memory Improvement Protocol (`context/rules/memory.md`): scans the current conversation for durable behavioral patterns, applies the qualify filter, classifies survivors by tier, and proposes `memory/MEMORY.md` / `context/IDENTITY.md` additions for explicit confirmation before writing (log-tier entry always appended). Manual-trigger, current-session scope, propose-then-confirm. Authored via the skill-builder agent for `github:mifunedev/skills` ([#337](https://github.com/ryaneggz/open-harness/issues/337)). - `/caveman` token-compression skill + subcommands (`.claude/skills/caveman{,-commit,-review,-compress,-stats}/`) — output-style mode that compresses agent prose ~65–75% via telegraphic phrasing while preserving code, API names, error strings, security warnings, and irreversible-action confirmations verbatim. Levels: `lite`/`full`/`ultra`/`wenyan`. Vendored adaptation of [JuliusBrussee/caveman](https://github.com/JuliusBrussee/caveman) (MIT, commit `655b7d9`) authored natively to harness skill conventions; upstream `curl | bash` installer intentionally not run. Pinned in `.mifune/skills.lock` as manual/vendored entries ([#335](https://github.com/ryaneggz/open-harness/issues/335)). - `/context-audit` skill (`.claude/skills/context-audit/`) — data-backed, repeatable eval for the default-loaded context budget. Tier-1 scores each file on 4 dimensions (footprint, load-bearing, integrity, redundancy) and emits KEEP/TRIM/DEMOTE/CUT verdicts. Tier-2 ablation harness (`runner.sh` + 7 probe files) removes a target file, runs a fixed task suite via `claude -p`, and measures behavior degradation — the only provably safe gate for cutting load-bearing content ([#333](https://github.com/ryaneggz/open-harness/issues/333)). - `/render-html` skill (`.claude/skills/render-html/SKILL.md`) — orchestrator skill for rendering an artifact as a bespoke, self-contained HTML file under `memory//.html` for one-shot human review (audit synthesis, council output, lint matrix, weekly digest). Output is gitignored via existing `memory/[0-9]*/` rule ([#314](https://github.com/ryaneggz/open-harness/issues/314)). - `/interview` skill (`.claude/skills/interview/SKILL.md`) — adaptive pre-work clarifier that batches 2–4 task-specific questions through `AskUserQuestion`, echoes a 2–3 sentence scope brief, and proceeds. Skips trivial tasks with an announcement. Serves as the in-tree reference pattern for `AskUserQuestion`-based elicitation in future skills ([#316](https://github.com/ryaneggz/open-harness/issues/316)). ### Changed - Register `/wiki-ingest`, `/wiki-query`, `/wiki-lint` in `AGENTS.md` skills table ([#351](https://github.com/ryaneggz/open-harness/pull/351)). - All 15 skills in `.claude/skills/` now sourced from and version-pinned to `github.com/mifunedev/skills` (commit `c559c100`) via `.mifune/skills.lock`; `interview` and `render-html` contributed upstream and added to the lock ([#327](https://github.com/ryaneggz/open-harness/issues/327)). - `README.md`, `docs/installation.md`, and `docs/quickstart.md` restructured to surface fork-and-clone and clone-and-own as first-class install paths alongside the upstream one-liner; `scripts/install.sh` local-run detection is now the documented bootstrap for self-hosters ([#331](https://github.com/ryaneggz/open-harness/issues/331)). - Skill `LICENSE` files updated to `Copyright (c) 2026 Mifune Dev (mifune.dev)` to match upstream correction. - Re-synced `context-audit` to the portable upstream form ([mifunedev/skills#6](https://github.com/mifunedev/skills/pull/6)): removed the top-level `argument-hint` frontmatter key, repinned `.mifune/skills.lock` (`commit` `f95011fe`, checksum `02dd6324`), and added the previously-missing `LICENSE` for folder parity ([#339](https://github.com/ryaneggz/open-harness/issues/339)). - Renamed the Slack-bridge tmux session from `agent-pi` to `client-slack` and introduced a `client-` prefix in `context/rules/sandbox-processes.md` for external-surface clients (Slack, Discord, web UIs) that bridge an in-sandbox agent. `.devcontainer/entrypoint.sh` now restores the `client-slack` session on container start whenever `SLACK_APP_TOKEN` and `SLACK_BOT_TOKEN` are present in `.devcontainer/.env` and `pi` is installed, so the Slack bridge survives `docker compose restart` without manual relaunch. Rename propagated through `apps/oh/src/config/slack.ts` (`oh config slack` wizard), `.pi/extensions/slack/README.md`, `docs/integrations/slack.md`, `docs/connecting.md`, `docs/intro.md`, and `docs/harnesses/overview.md` (the latter folding in the half-finished `harness-pi` rename from #302). ### Fixed - Sandbox image installs `pi-coding-agent` under the sandbox user's npm prefix (`/home/sandbox/.local`) and places that bin directory before `/usr/bin`, allowing `pi update` to self-update without sudo on fresh builds. ### Removed - `config.example.json` and its install-time seeding step (`scripts/install.sh`); the base ships zero compose overlays and all readers tolerate a missing `config.json`, so the example template was dead weight. Packs that need overlays create their own `config.json` ([#323](https://github.com/ryaneggz/open-harness/issues/323)). ### Deprecated ### Security ## [2026.5.18] - 2026-05-18 ### Added - `OH_GITHUB_REPO` and `OH_GITHUB_REF` env vars for fork-friendly installs ([#309](https://github.com/ryaneggz/open-harness/pull/309)). - `/worktrees` skill (`.claude/skills/worktrees/SKILL.md`) — orchestrator skill for managing `.worktrees/` lifecycle: create, list, remove, clean, stale audit, project clones. ### Changed - README and `docs/installation.md` add a "For forks / self-host" section; canonical upstream `oh.mifune.dev` URL unchanged ([#309](https://github.com/ryaneggz/open-harness/pull/309)). - `/release` skill now pushes the source branch back to origin immediately after the CHANGELOG promotion commit, before cutting the release branch. Without this, the promotion commit lived only on `release/*`, so the next round of work on `development` re-carried already-released `[Unreleased]` entries and the next `/release` would double-promote them ([#297](https://github.com/ryaneggz/open-harness/issues/297)). ### Fixed - Repaired `CHANGELOG.md` drift between `development` and `main`: prior to the `/release` fix above, three releases (`2026.5.14`, `2026.5.15`, `2026.5.16`) had promoted versioned sections on `main` but never landed those promotions back on `development`, leaving stale `[Unreleased]` entries that duplicated already-shipped content. This commit restores the versioned sections to `development` from `main` and trims `[Unreleased]` to the genuinely new (post-`2026.5.16`) entries ([#297](https://github.com/ryaneggz/open-harness/issues/297)). ### Removed ### Deprecated ### Security ## [2026.5.16] - 2026-05-16 ### Added - `docs/connecting.md` — new runbook documenting the VSCode Attach + port-forwarding workflow for remote dev servers. Covers the "machine unreachable" debugging pattern: VS Code Remote SSH's automatic port-forwarding, manual fallback for direct-terminal users, and the `localhost:` prefix convention for accessing services on the Docker host. Referenced from `intro.md`, `quickstart.md`, `harnesses/overview.md`, `harnesses/t3code.md`, and `integrations/slack.md`. ([#300](https://github.com/ryaneggz/open-harness/issues/300)) - **Agents catalog**: new `docs/agents/` section (renamed from `docs/agents/` → `docs/harnesses/` after initial creation to match sidebar label). Includes `_category_.json` organizing the section, `overview.md` as the hub page, and five per-branch playbook pages (`portfolio-mgr.md`, `blog-writer.md`, `linkedin-ghostwriter.md`, `dc-designer.md`, `uat-tester.md`), each documenting use-case, harness selection, auth flow, and tmux launch pattern. ([#300](https://github.com/ryaneggz/open-harness/issues/300)) ### Changed - Renamed `docs/agents/` folder to `docs/harnesses/` so the folder name matches the sidebar label; added `@docusaurus/plugin-client-redirects` to `apps/docs/` with seven redirects from `/docs/agents/*` → `/docs/harnesses/*` preserving URLs from the initial agents-catalog PR. ([#300](https://github.com/ryaneggz/open-harness/issues/300)) - Cross-linked `docs/connecting.md` from `intro.md`, `quickstart.md`, `harnesses/overview.md`, `harnesses/t3code.md`, and `integrations/slack.md` so the VSCode attach pattern is discoverable from each major entry point. ([#300](https://github.com/ryaneggz/open-harness/issues/300)) - Fixed `apps/README.md` script-name drift: `pnpm --filter @openharness/docs dev` → `pnpm --filter @openharness/docs start` to match the actual `start` script in `apps/docs/package.json`. ([#300](https://github.com/ryaneggz/open-harness/issues/300)) - Docs frame the orchestrator-via-VS-Code-attach as the canonical workflow. `docs/quickstart.md` "Enter the sandbox" now leads with the VS Code Dev Containers attach flow (Command Palette → `Dev Containers: Attach to Running Container...` → `openharness`), since it works identically on localhost and over Remote-SSH; `make shell` is demoted to a terminal fallback. `docs/intro.md` "How it works" names the **orchestrator** (the agent session attached at the project root that owns git, lifecycle, and edits, drives other containers over the Docker socket, and only needs host-shell intervention for things the running container can't do for itself — typically a new bind-mounted volume), frames a second sandbox as opt-in for isolation only, and closes with a Mermaid architecture diagram (orchestrator at the center of the sandbox subgraph, tmux session row, `docker.sock` → optional second sandbox, external GitHub / LLM-provider edges, host bind-mount). `docs/harnesses/overview.md` replaces the redundant "Running an agent in tmux" section with "Default surfaces" (Pi+Slack, T3 Code, docs app on `:3000`), each as a named tmux session, with explicit guidance to open the two browser surfaces in VS Code's Simple Browser (`Ctrl+Shift+P` → `Simple Browser: Show`; `Cmd+Shift+P` on macOS) so the live UI sits next to the code being edited. Documented tmux sessions renamed `agent-pi` → `harness-pi` and `agent-t3code` → `harness-t3code` in `docs/harnesses/overview.md` only — the `oh config slack` wizard at `apps/oh/src/config/slack.ts` still creates `agent-pi`, and `context/rules/sandbox-processes.md` still defines the `agent-` prefix; full rename across wizard code, rule, and sibling docs (`docs/intro.md`, `docs/integrations/slack.md`, `docs/harnesses/t3code.md`, `.pi/extensions/slack/README.md`) will follow. ([#302](https://github.com/ryaneggz/open-harness/issues/302)) - `.worktrees/README.md` now reserves `.worktrees/project///` for durable standalone repo clones and narrows `.worktrees/agent/` to harness agent branches / legacy agent-owned clones, using generic examples so the layout applies cleanly to new users. ([#295](https://github.com/ryaneggz/open-harness/issues/295), [#298](https://github.com/ryaneggz/open-harness/issues/298)) ### Fixed - Dark-mode inline `code` pills in the docs site were nearly invisible against pure-black surfaces. `apps/docs/src/css/custom.css` background bumped from `rgba(255, 255, 255, 0.06)` → `0.12`, border `0.1` → `0.22`, and text raised to pure white. Light mode untouched. ([#302](https://github.com/ryaneggz/open-harness/issues/302)) ### Removed ### Deprecated ### Security ## [2026.5.15] - 2026-05-15 ### Added ### Changed - `oh config slack` wizard UX overhaul. Token prompts now echo `●` per keystroke (was: silent — looked frozen) via a TTY-aware raw-mode `askSecret` that handles backspace, Ctrl-U, and Ctrl-C; piped/non-TTY stdin still uses the legacy readline fallback as `askSecretPiped` so `echo "" | oh config slack` keeps working. Flow is reframed into four numbered steps `[1/4] … [4/4]` with inline "Where:" hints and clickable URLs (OSC 8 hyperlinks; fall back to `label (url)` on legacy terminals). Each input shows `✓ valid prefix` / `✓ N user(s) accepted` after validation. A final summary screen lists the keys (tokens redacted, IDs visible) and gates the env-file write behind a `Proceed? [Y/n]` confirmation. New helpers exported from `apps/oh/src/lib/prompt.ts`: `step()`, `link()`, `bold()`. Zero new runtime dependencies. ([#290](https://github.com/ryaneggz/open-harness/issues/290)) ### Fixed ### Removed ### Deprecated ### Security ## [2026.5.14] - 2026-05-14 ### Added - `.devcontainer/docker-compose.yml` publishes container port 1455 to the host loopback (`127.0.0.1:1455:1455`) for the **Pi harness** login flow, whose OAuth callback binds `http://localhost:1455`. With the port on the host loopback, VS Code Remote SSH's automatic port-forwarding carries the redirect back to the laptop and Pi login completes out of the box; direct-terminal (plain `ssh`) users still need to forward the port manually with `ssh -L 1455:localhost:1455 user@host`. The Codex CLI is unaffected — it has its own headless path via `codex login --device-auth`. ([#287](https://github.com/ryaneggz/open-harness/issues/287)) ### 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`. ### Changed - Migrate `.pi/extensions/slack/{index,tools}.ts` from the deprecated `@mariozechner/pi-coding-agent` (and `@mariozechner/pi-agent-core`) to the upstream-recommended successors `@earendil-works/pi-coding-agent` (and `@earendil-works/pi-agent-core`). Per `npm view @mariozechner/pi-coding-agent`'s deprecation notice, the old package is no longer maintained. The other two in-tree extensions (`path-guard.ts`, `plan-mode/index.ts`) had already migrated; slack was the laggard. `.devcontainer/Dockerfile`'s `[pi-coding-agent]` mapping in the `PKG` array, `docs/agents/pi.md`'s upstream link, `docs/installation.md`'s Pi row, and `.pi/UPSTREAM.md`'s lineage label all updated to match. ([#281](https://github.com/ryaneggz/open-harness/issues/281)) - `docs/integrations/slack.md` § 5 leads with the new `oh config slack` wizard; the manual `set -a; source ...; tmux new-session` ritual is demoted to a `
` "Manual fallback" collapsible. Sections renumbered (8→7, 9→8). The wizard explicitly **starts the Slack bridge for you** at the end — kills any existing `agent-pi` tmux session, launches a fresh one running `pi` with the new env sourced, and polls `tmux capture-pane` for the `connected and listening` log line. ([#281](https://github.com/ryaneggz/open-harness/issues/281)) - Sidebar label `Agents` → `Harnesses` in `docs/agents/_category_.json` (and corresponding `Harnesses Overview` H1 in `docs/agents/overview.md`). The "Pick your harness" section in `docs/quickstart.md` now links each harness to its per-harness page and adopts the t3code "authenticate at least one provider before use" framing across Codex (`codex login`), OpenCode (`opencode auth login`), Claude (OAuth on first launch), Pi (env vars), DeepAgents (`~/.deepagents/.env`), and the new T3 Code (`npx t3` + pairing URL). Per-harness pages updated with matching Authentication sections. ([#281](https://github.com/ryaneggz/open-harness/issues/281)) - Docusaurus theme: prose links inside `.markdown` content now render in terminal green (`#15803d` light / `#4ade80` dark) with a 1px underline (2px on hover). Sidebar / navbar / TOC / footer links unchanged — their position already signals affordance. Closes the "links blend with body text" UX issue. ([#281](https://github.com/ryaneggz/open-harness/issues/281)) - `Makefile` `help` target now prints a "Configuration wizards" section after the auto-generated target list, surfacing `oh config slack` and `oh --help` with a note that they run inside the sandbox after `make shell`. Existing Make targets remain pure compose wrappers (verb-only naming preserved); wizards are listed separately as a different category. Decision rationale: 3-agent council (PM/Implementer/Critic) reviewed Makefile-target vs CLI vs hybrid shapes — picked CLI with help-text discoverability over `docker exec -it` indirection (which has HIGH-severity TTY fragility through CI/non-interactive contexts). ([#281](https://github.com/ryaneggz/open-harness/issues/281)) - Slack setup docs (`docs/integrations/slack.md`, `.pi/extensions/slack/README.md`, `.devcontainer/.example.env`) now spell out the actual working flow: add `SLACK_APP_TOKEN` / `SLACK_BOT_TOKEN` / `SLACK_ALLOW_USERS` (or `SLACK_ALLOW_CHANNELS`) to `.devcontainer/.env` in Compose `KEY=value` format, then inside the sandbox run `set -a; source /home/sandbox/harness/.devcontainer/.env; set +a` before launching `pi` so the child process inherits exported vars. `pi` itself goes in a named tmux session (`tmux new-session -d -s agent-pi 'pi 2>&1 | tee /tmp/agent-pi.log'`) per `context/rules/sandbox-processes.md`. The `set -a` requirement is documented as a temporary band-aid — `.devcontainer/.env` is dual-purpose (Compose substitution + shell source), and a future change should remove the manual `set -a` step. - Full rewrite of `docs/integrations/slack.md` to document ID allowlist semantics, Socket Mode smoke test, the token-freshness pattern, and migration from the legacy `@ryaneggz/mifune` pack; `docs/quickstart.md` adds a "Next steps" section pointing to integration pages. References to the stale `@ryaneggz/mifune` Slack context pack removed from `README.md`, `docs/installation.md`, `docs/agents/pi.md`, and `docs/agents/overview.md`. ([#279](https://github.com/ryaneggz/open-harness/issues/279)) ### Fixed - Docusaurus marketing landing page hero quickstart still showed `cd ~/openharness && make shell`, leaving new users at "no such directory" after the curl-pipe install. Updated `apps/docs/src/pages/index.tsx` to `cd ~/.openharness && make shell` to match the installer rename in [#200](https://github.com/ryaneggz/open-harness/issues/200) / [#210](https://github.com/ryaneggz/open-harness/issues/210). The same rename had already landed in `README.md`, `docs/quickstart.md`, and `docs/installation.md`; the JSX template literal in the home page was the last copy still pointing at the old path. - `pi` failing on a fresh sandbox with `Failed to load extension "/home/sandbox/harness/.pi/extensions/slack/index.ts": Cannot find module '@slack/socket-mode'`. The in-tree Slack Pi extension imports `@slack/socket-mode`, `@slack/web-api`, and `chalk`, all declared in the root `package.json` but never installed automatically — the harness is bind-mounted, so a Dockerfile-time install would be shadowed at runtime. `.devcontainer/entrypoint.sh` now runs `pnpm install --prefer-offline` at the harness root on first boot when `node_modules/` is missing, before the cron runtime starts (which itself imports `croner` from the same `package.json`). Set `SKIP_PNPM_INSTALL=1` to opt out. - Docs landing page supported-agent copy and agent grid now include DeepAgents with a matching icon tile. - `opencode --version` (and any `opencode` invocation) failing with `EACCES: permission denied, mkdir '/home/sandbox/.config/opencode'` on a fresh sandbox. Docker auto-creates `~/.config` as root to satisfy the `gh-config:/home/sandbox/.config/gh` named-volume mount, which then blocks the sandbox user from creating siblings like `~/.config/opencode`. The entrypoint's non-recursive parent-chown loop now also covers `~/.config` alongside the existing `~/.local` / `~/.local/share` parents, while leaving the bind-mounted `~/.config/gh` contents untouched. ([#247](https://github.com/ryaneggz/open-harness/issues/247)) - `opencode` and `opencode /connect` failing with `EACCES: permission denied, mkdir '/home/sandbox/.local/state'` on a fresh sandbox. Docker auto-creates `~/.local` and `~/.local/share` as root to satisfy the `opencode-host` bind-mount path; the entrypoint now non-recursively chowns those parent dirs to `sandbox:sandbox` so the user can create siblings like `.local/state`. The bind-mounted `~/.local/share/opencode` itself stays untouched. Re-applies a fix that was lost when [#241](https://github.com/ryaneggz/open-harness/pull/241) merged a conflicting `entrypoint.sh`. ([#245](https://github.com/ryaneggz/open-harness/issues/245)) ### Added - `oh config slack` — in-sandbox CLI wizard that sets up the Slack integration end-to-end. Lives at `apps/oh/` (Node TypeScript, esbuild-bundled to ~13 kb, no runtime deps); installed via `.devcontainer/Dockerfile` to `/usr/local/bin/oh` (built from `/opt/oh/`, outside the bind-mount so the binary survives the runtime overlay). Walks the user through token entry (`xapp-`/`xoxb-` prefix validation), allowlist-mode prompt (users / channels / both with `U…`/`C…` ID validation and trim), atomic `.devcontainer/.env` merge (per-key, comments preserved, `.tmp.` + `renameSync` for crash safety), and `agent-pi` tmux session restart with `connected and listening` poll (15s). Pluggable via `oh config ` namespace — future `oh config github`/`postgres`/`cloudflare` are one-file additions under `apps/oh/src/config/`. Replaces the orphaned `.pi/onboard-steps/slack.ts` with bugs fixed (correct tmux session name, real `pi` launch path, prefix validation, redaction). ([#281](https://github.com/ryaneggz/open-harness/issues/281)) - `docs/agents/t3code.md` — new harness page documenting T3 Code (Theo Browne / ping.gg), the browser-based coding agent that wraps Claude/Codex/OpenCode as backends and listens on port 3773. Page includes pairing-URL auth model, `npx t3` invocation pattern, and tmux launch convention. Added to the harnesses overview, supported-agents table, authentication bullets, and the home-page agent grid in `apps/docs/src/pages/index.tsx`. ([#281](https://github.com/ryaneggz/open-harness/issues/281)) - `build-essential` (gcc, g++, make, libc6-dev, dpkg-dev) in the default sandbox image (`.devcontainer/Dockerfile`) so native-deps install hooks succeed out of the box — e.g. `node-pty` falling through to `node-gyp rebuild` when no Linux prebuild is shipped, which was the root cause of the `npx t3` silent-failure investigated upstream at [pingdotgg/t3code#2621](https://github.com/pingdotgg/t3code/issues/2621). Adds ~250MB to the image; intentional trade-off — the harness optimizes for "things work out of the box" over "smallest possible image". Supersedes the 707-LOC documentation-only PR #264, which was closed without merge. ([#263](https://github.com/ryaneggz/open-harness/issues/263), [#271](https://github.com/ryaneggz/open-harness/issues/271)) - `context/rules/recursive-delegation.md`: project rule encoding the inference-time *structural* patterns from *Recursive Agent Optimization* (arXiv 2605.06639, Gandhi et al., May 2026) — bounding compute (`Max depth` / `Max children per level` / `Step budget` fields in briefings), `Context` block for context-as-parameter, structured-return schemas in `Acceptance criteria`, multi-level delegation protocol, and the orchestrator-vs-sandbox recursion boundary. The rule explicitly disclaims RAO's *training-result* benefits (depth-12 generalization, 2.5× wall-clock) — those require an RL-trained policy this harness does not have — and notes the harness `Agent` tool is stateless/synchronous, unlike the paper's `async launch_subagent` REPL primitive. `context/rules/advisor-model.md` gains a `Multi-level (recursive)` row in its Pipeline Variants table cross-linking the new rule; `.claude/skills/delegate/SKILL.md` gains a distinct-scope decomposition rule and a recursion-authorization gate (Step 5 a.1) that confirms `Max depth` / `Max children per level` / `Step budget` are all present before allowing a worker to spawn grandchildren; `.claude/protected-paths.txt` registers the new rule as load-bearing. Already-covered principles (fresh context per child, parallel-when-independent, quality-over-quantity, don't-delegate-trivial) intentionally not duplicated. ([#269](https://github.com/ryaneggz/open-harness/issues/269), [#270](https://github.com/ryaneggz/open-harness/pull/270)) - Slack integration as a Pi extension at `.pi/extensions/slack/` ([#261](https://github.com/ryaneggz/open-harness/issues/261)). - Project-local Pi single-line footer extension showing cwd/branch, context usage, model/thinking state, extension statuses, token usage, and session name with width-aware truncation. Header copy now uses a plain `MIFUNE` wordmark with an `agent harness` subtitle. - Project-local Pi config under `.pi/` standing the agent up at the harness root: OpenAI-default `settings.json` (`gpt-4o`, model-cycling list scoped to GPT/o-series), `mifune-banner.ts` extension replacing pi's startup header with a flush-left `MIFUNE` wordmark + `pi harness · github.com/ryaneggz/mifune` subtitle, `path-guard.ts` extension intercepting `tool_call` events to confirm before write/edit on sensitive paths (`.env*`, `secrets/`, `credentials.{json,yaml}`, `*.pem`, `*.key`, ssh keys) and risky bash (`rm -rf`, `sudo`, `git push --force`, `git reset --hard`, bare `> /dev/sd*|nvme*|hd*|disk*`) with case-insensitive matching and `ctx.hasUI` guards for headless/RPC mode, generic consumer-agnostic `APPEND_SYSTEM.md`, `prompts/review.md` template invokable as `/review`, and `skills` + `rules` directory symlinks to `../.claude/skills` / `../.claude/rules` matching the single-source-of-truth pattern already in `.codex/`. New canonical `.claude/skills/harness-context/SKILL.md` reachable from pi via the symlink. Test suite at `.pi/extensions/__tests__/{path-guard,mifune-banner}.test.ts` (32 + 7 cases, hand-rolled mock `ExtensionAPI`, no pi devDep); pi source verified via `gh api` for tool-name casing (lowercase) and write/edit canonical input key (`path`). `vitest.config.ts` `include` extended to `.pi/**/__tests__/**/*.test.ts`; `.github/workflows/ci-harness.yml` `paths:` filter extended (`.pi/**`, `scripts/**`, `vitest.config.ts`) and a new "Root tests" step runs `pnpm test:scripts`, also bringing the previously-orphaned `scripts/__tests__/cron-runtime.test.ts` into CI. Project Pi settings pin `npm:@tintinweb/pi-subagents@0.7.1` so PR #256 starts with Claude Code-style sub-agents available in pi. ([#255](https://github.com/ryaneggz/open-harness/issues/255)) - Project-local Pi plan-mode extension under `.pi/extensions/plan-mode/`, with `/plan`, `/plan approve`, `--plan`, read-only tool/bash gating, plan approval prompts, and `[DONE:n]` progress tracking. - Directory README pattern: tracked `README.md` in `apps/`, `crons/`, `scripts/`, `tasks/`, and `.worktrees/` documenting each directory's intent, subfolder conventions, and lifecycle. New rule `.claude/rules/directory-readme.md` codifies the pattern; `.gitignore` exempts only `.worktrees/README.md` (replacing the unused `.gitkeep` exemption); `.claude/rules/git.md` § Worktrees points to the new README and documents the `.worktrees/project///` slot for independent project clones; `docs/architecture/container-runtime.md` moves `.worktrees/` into the canonical tree (README tracked, contents ignored). Three session lessons appended to `context/IDENTITY.md` covering README-over-`.gitkeep`, "treat X same as Y" interpretation discipline, and semantic-subfolder enumeration. - OpenCode as a core sandbox agent: install `opencode-ai` in the base image, persist `~/.local/share/opencode`, add the `opencode-host` overlay, support `scripts/ralph.sh --harness=opencode`, and document OpenAI OAuth as the default OpenCode provider path. - DeepAgents CLI support as a first-class supported sandbox runtime alongside Claude Code, Codex, OpenCode, and Pi. `.devcontainer/Dockerfile` installs `deepagents-cli` via `uv tool install` into `/usr/local/bin`; `.devcontainer/docker-compose.yml` adds a `deepagents-auth` named volume at `/home/sandbox/.deepagents` so provider keys, memory, skills, and sessions persist across rebuilds; `.devcontainer/docker-compose.deepagents-host.yml` is an opt-in host-state overlay (off by default — DeepAgents stores raw provider API keys with no scope/expiry, so the blast radius is wider than the Claude/Codex host overlays); `.devcontainer/entrypoint.sh` extends its chown loop to include `.deepagents` and skips it when `DEEPAGENTS_HOST_BIND_MOUNT=1`. `scripts/ralph.sh` accepts `--harness=deepagents` (or `RALPH_HARNESS=deepagents`) and dispatches to a constrained default invocation `deepagents -y --shell-allow-list recommended -q --no-stream --max-turns "$RALPH_DEEPAGENTS_MAX_TURNS" -n "$task"` (default 25 turns); `RALPH_DEEPAGENTS_FLAGS` overrides the safety/output flag string, and `--max-turns` is always appended after so the per-iteration cap cannot be silently dropped. `--shell-allow-list all` combined with the sandbox's mounted Docker socket can affect sibling containers or host Docker — only enable for trusted tasks via the env-var override. `install/banner.sh` reports DeepAgents `[installed]` from `command -v deepagents` and `[configured]` only when `~/.deepagents/.env` or `~/.deepagents/config.toml` is non-empty (an empty mounted directory is no longer treated as authenticated). New agent doc at `docs/agents/deepagents.md`; `docs/agents/overview.md`, `README.md`, `docs/quickstart.md`, `docs/onboarding.md`, `docs/installation.md`, `docs/operations/{provision,destroy,repair}.md`, `docs/guide/{overlays,permissions,configuration}.md`, and `docs/architecture/{container-runtime,overview}.md` enumerate the new agent, volume, overlay, and Ralph harness option. Repo-local `.deepagents/` is project data and follows normal git review/ignore rules; secrets and provider keys belong only in `~/.deepagents` or ignored local files. Claude remains the default Ralph harness; existing Claude/Pi/Codex execution and fallback behavior are unchanged. ([#237](https://github.com/ryaneggz/open-harness/issues/237)) - `docs/agents/pi.md` stub (linking upstream to `badlogic/pi-mono`) and a Pi entry in the home-page agent grid at `apps/docs/src/pages/index.tsx`, matching Pi's restoration as a default-installed CLI. ([#233](https://github.com/ryaneggz/open-harness/pull/233)) - Top-level `Makefile` wrapping `docker compose -f .devcontainer/docker-compose.yml` so users type `make sandbox` / `make shell` / `make destroy` instead of the 50-character compose lines. Targets: `sandbox`, `shell`, `destroy`, `stop`, `logs`, `ps`, `restart`, `help` (default, self-documenting via awk). Uses `-include .devcontainer/.env` so `SANDBOX_NAME` flows through. No agent-CLI targets — the harness's value is sandbox isolation, agent choice (`claude` / `codex` / `pi`) happens inside `make shell`. ### Changed - Sandbox image-name convention flipped from `-sandbox` (Compose's default `-` tag) to `sandbox-` so all harness images sort/group together in `docker images` and `docker ps`. `.devcontainer/docker-compose.yml` now sets an explicit `image: sandbox-${SANDBOX_NAME:-openharness}` on the sandbox service; container name (`${SANDBOX_NAME}`) and the postgres/devnet sibling-service names (`-postgres`, `-devnet`) are unchanged. Existing built images on each host are left in place — the new tag takes effect on the next `make sandbox` rebuild and old `*-sandbox` images can be `docker rmi`'d at leisure. `docs/operations/destroy.md` updated to match. ([#265](https://github.com/ryaneggz/open-harness/issues/265)) - Move project rules from `.claude/rules/` to `context/rules/` as the canonical, tool-agnostic location, alongside the existing `SOUL.md`, `IDENTITY.md`, `TOOLS.md`, `USER.md`. `.claude/rules` is retained as a directory symlink to `../context/rules` so Claude Code's auto-loader keeps working unchanged. The previously inert `.codex/rules` and `.pi/rules` symlinks are removed — neither CLI has a rules-loading feature. New `context/README.md` and `context/rules/README.md` per `directory-readme.md`. Canonical layout tree at `docs/architecture/container-runtime.md` and high-visibility teaching references (`AGENTS.md`, `CLAUDE.md`, `.claude/agents/rule-builder.md`) updated; ~50 scattered references in skills/agents/crons/archived PRDs left as-is — the `.claude/rules` symlink resolves them. ([#257](https://github.com/ryaneggz/open-harness/issues/257)) - **BREAKING**: Installer now clones to `~/.openharness/` (was `~/openharness/`); `scripts/install.sh` auto-migrates existing `~/openharness/` checkouts in place. - **BREAKING**: In-repo `.openharness/` subdirectory removed entirely. - **BREAKING**: `composeOverrides[]` config moved from `.openharness/config.json` to repo-root `config.json` (gitignored, seeded from tracked `config.example.json`). - **BREAKING**: `pi-host.yml` dropped from default `composeOverrides` — Pi users add it back manually in `config.json`. - `/cloudflared-tunnel` skill reconstructs a missing `.json` from `cloudflared tunnel token` instead of failing — fixes the case where a tunnel exists in the Cloudflare account (e.g. created on another host) but only `cert.pem` is on the running machine. Documents that token-mode runs (`--token `) silently drop the local `--url` flag, leaving Cloudflare to return 530s while connections register. ([#249](https://github.com/ryaneggz/open-harness/issues/249)) - Quickstart collapsed from two parallel paths (installer + manual) to a single linear flow in `README.md` and `docs/quickstart.md`. Manual setup demoted to a `
` block. New "Configuration" section in both docs surfaces `.devcontainer/.env` as the customization surface (`make destroy && make sandbox` to re-apply). - `install.sh` moved to `scripts/install.sh` to colocate with `cron-runtime.ts` and `ralph.sh` per the orchestrator-scripts convention. Repo-detection logic and help-text self-references updated for the new path. **Action required for the curl-pipe URL**: update the `https://oh.mifune.dev/install.sh` redirect to `https://raw.githubusercontent.com/ryaneggz/open-harness/refs/heads/main/scripts/install.sh`. - `scripts/install.sh` smarter: auto-detects host `gh auth token` and prompts to share it with the sandbox (skips in-sandbox `gh auth login` when accepted); auto-populates `.devcontainer/.env` with host timezone and git identity; new `prompt_yn` helper for interactive Y/n prompts; idempotency guard preserves existing `.devcontainer/.env` on re-runs. Dropped the unconditional `SANDBOX_PASSWORD` prompt (only honored by the opt-in sshd overlay; defaults silently to `changeme`). Build-time message added before the cold-cache build to set ~10-min expectations. "Next steps" output restructured to lead with the `.devcontainer/.env` path so the customization surface is discoverable. - `CLAUDE.md` Lifecycle section uses the new `make` targets (`make sandbox`, `make shell`, `make ps`, `make destroy`); deeper inspection commands (`docker exec ... tmux ls`) keep their docker-native form. - `.devcontainer/.example.env`: top header rewritten to document the file as the single customization surface; `INSTALL_AGENT_BROWSER` default flipped from `true` to `false` (~1 GB / +3 min on first build, opt-in only when needed); `SANDBOX_PASSWORD` comment clarified to note it's only honored with the sshd overlay. - Consolidate repository layout documentation into `docs/architecture/container-runtime.md#repo-layout`; reduce duplicate tree blocks in `AGENTS.md` and `README.md` to one-line pointers; add `.claude/rules/repo-layout-source.md` to prevent the next drift round. Remove phantom heartbeat env vars (`HEARTBEAT_ACTIVE_START`, `HEARTBEAT_ACTIVE_END`, `HEARTBEAT_AGENT`, `HEARTBEAT_INTERVAL`) from `docs/architecture/container-runtime.md` and `.devcontainer/.example.env`. Fix broken `README.md` croner link (was `.claude/specs/structure-spec-v0.7.md`, now `docs/architecture/crons-and-heartbeats.md`). ### Added - Restore `@mariozechner/pi-coding-agent` as a default-installed CLI alongside Claude Code and Codex. `Dockerfile` `AGENTS` default goes back to `claude-code,codex,pi-coding-agent`; `.devcontainer/docker-compose.pi-host.yml` overlay restored and listed in `.openharness/config.json` `composeOverrides`; `.devcontainer/entrypoint.sh` extends its host-bind skip-chown loop with `.pi`/`PI_HOST_BIND_MOUNT`. Pi auth shares the same trust tradeoffs as the claude/codex host overlays (host UID = 1000 + pre-existing `~/.pi`). The Mom Slack bot stays out of base — install [`@ryaneggz/mifune`](https://github.com/ryaneggz/mifune) for that. `docs/installation.md`, `docs/onboarding.md`, `docs/operations/{provision,repair}.md` updated; stale `mom` shell alias dropped from `install/.zshrc` (leftover from #209). - `"type": "module"` in root `package.json` to silence the Node `MODULE_TYPELESS_PACKAGE_JSON` warning emitted on every `cron-runtime.ts` invocation. The script already uses ESM `import` syntax; no CommonJS in `scripts/` to break. - `## Active items` watchlist inside `crons/heartbeat.md` — session-curated section the hourly heartbeat reads each pulse to validate deferred follow-ups across session boundaries via an enumerated permitted-checks list (`gh pr view`, `gh issue view`, `gh run list`, `gh release list`, date-based reminders). Cron is read-only on the section; sessions add and remove lines. New `crons/.cron.log` (gitignored under `crons/*.log`) appended each pulse as a one-line ISO-8601 liveness signal — additive to the existing `memory//log.md` writes. `context/USER.md` gains a 3-sentence "Tracking deferred follow-ups" pointer at the `Authorization patterns` boundary. Plan at `.claude/plans/polished-spinning-dijkstra.md` survived 3 critic rounds (round 1 rejected a separate `memory/HEARTBEAT.md`, round 2 rejected `AGENTS.md` documentation, round 3 converged on the v5 shape). ([#224](https://github.com/ryaneggz/open-harness/issues/224)) - Memory concept: long-term `memory/MEMORY.md`, daily logs at `memory/YYYY-MM-DD/log.md`, and canonical write-side protocol in `context/rules/memory.md`; auto-loaded via CLAUDE.md session-start list. ### Removed - `oh` CLI references and the multi-agent / N-worktree / heartbeat-daemon copy from the marketing landing page at `apps/docs/src/pages/index.tsx`; quickstart code block now uses `make shell`, hero + architecture + WHY sections rewritten to "we provide the sandbox, you choose the harness". `docs/agents/overview.md` similarly drops the "Why run multiple agents" framing and the deleted `oh harness add` invocation. ([#233](https://github.com/ryaneggz/open-harness/pull/233)) - Gemini hidden from the docs sidebar and sitemap via `unlisted: true` in `docs/agents/gemini.md` (Docusaurus 3); page stays reachable by direct URL for old links. The home-page agent grid swaps the Gemini tile for Pi. ([#233](https://github.com/ryaneggz/open-harness/pull/233)) - Stale files missed in #223: `.devcontainer/tests/cli-binaries.sh`, `.devcontainer/init-env.sh` (orphan helper — `install.sh` writes `.devcontainer/.env` directly and docker compose loads it from that folder by default), `.claude/posts/{linkedin,x}.md`, `tsconfig.base.json`, `.claude/plans/crispy-beaming-torvalds.md`. Doc tree comments in `docs/architecture/container-runtime.md` and `.openharness/README.md` updated to drop the `init-env.sh` references. ([#228](https://github.com/ryaneggz/open-harness/issues/228)) - Pruned four orphaned files in `.openharness/` left over from the v0.7 convergence: `agents` (broken symlink to deleted `workspace/.claude/agents/`), `agent/settings.json` (referenced non-existent `gpt-5.4` model and `lastChangelogVersion: 0.66.1`; no loader on `main`), `banner.json` (custom-banner skill deleted in `fb71365`), and `settings.json` (pointed at non-existent `./.claude/skills/`). Refreshed `.openharness/.gitignore` header and added `.openharness/README.md` documenting the remaining live file (`config.json`) and the dormant status of `Caddyfile` / `exposures.json`. The directory's load-bearing role — `composeOverrides` consumed by `install.sh` and the container build — is unchanged. ([#222](https://github.com/ryaneggz/open-harness/issues/222)) - Remove 0 eligible stale remote branches after critic-gated review; preserve all live remote branches because none met the >60-day deletion gate, and the backup branch still contains unique commits. ([#213](https://github.com/ryaneggz/open-harness/issues/213)) - Remove five stale or corrupted `.worktrees/` agent directories and stale worktree registrations, reducing the ignored worktree footprint below 100 MB. ([#213](https://github.com/ryaneggz/open-harness/issues/213)) - Remove the dead legacy install-side setup, entrypoint, and tmux wrapper scripts now that the Dockerfile wires `.devcontainer/entrypoint.sh` directly. ([#213](https://github.com/ryaneggz/open-harness/issues/213)) - Remove the empty untracked `packages/web-ui/` and `packages/slack/` husks, plus the stale Slack workspace and entrypoint references. ([#213](https://github.com/ryaneggz/open-harness/issues/213)) - Remove the obsolete on-disk SPEC v0.6 artifact so `.claude/specs/` only exposes canonical tracked specs. ([#213](https://github.com/ryaneggz/open-harness/issues/213)) - **BREAKING**: `oh harness add` deprecated; `mifune` (and any other harness pack) installs via `git clone` + manual `cp` per the pack's README for v1. The CLI-driven pack installer was deleted along with `packages/sandbox/` in US-006; its `fetchGitPack` (command-injection-prone) and `registerComposeOverlays` (path-traversal-prone) plumbing is gone with it. A redesigned, security-first standalone installer (~50 LOC) tracked for v0.8 in [#211](https://github.com/ryaneggz/open-harness/issues/211): URL allowlisting, signature/SHA verification, sandboxed install, command-injection-safe `spawnSync`, path-traversal-safe overlay resolution, atomic registry write. Per SPEC v0.7 §"Pack mechanism status in v0.7". ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - **BREAKING**: workspace template emptied of pi-coupled scaffolding. Deleted `workspace/HEARTBEAT.md`, `workspace/IDENTITY.md`, `workspace/MEMORY.md`, `workspace/SOUL.md`, `workspace/TOOLS.md`, `workspace/USER.md` (six identity files belonging to the v0 multi-agent persona); `workspace/heartbeats/` (replaced by root `crons/` per US-002), `workspace/.ralph/`, `workspace/.codex` symlink, `workspace/.openharness` symlink, and `workspace/memory/` (instance state in template); `workspace/.claude/skills/{compress,content-gate,eval-conciseness,quality-gate,wiki-ingest,wiki-lint,wiki-query,ralph,prd,ci-status}/` (ten workspace skills); `workspace/.claude/agents/{council,critic,implementer,pm,agent-builder,command-builder,rule-builder,skill-builder}.md` (eight sub-agents); and `workspace/.claude/hooks/notify_slack.sh` (Slack hook + its references in `workspace/.claude/settings.local.json`). Rewrote `workspace/AGENTS.md` (and the `CLAUDE.md` symlink) as a generic ~22-line agent-runtime stub. Kept: `workspace/AGENTS.md`, `workspace/startup.sh`, `workspace/.claude/.example.env.claude`, `workspace/.claude/rules/{code-quality,git,token-conservation}.md`, `workspace/.claude/settings.local.json`, `workspace/.claude/screenshots/.gitkeep`. The workspace template is now agent-runtime-agnostic; identity, skills, sub-agents, and routines come from a harness pack (e.g. `@ryaneggz/mifune`), not from this directory. Per SPEC v0.7 §"Harness Packs". ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - **BREAKING**: orchestrator skill set triaged to a defensible 4-skill core. Deleted `.claude/skills/{delegate,harness-audit,strategic-proposal,skill-lint,prd,ralph}/` (six skill directories that mapped to v0 multi-agent / autonomous-agent flows). Converted `.claude/skills/{provision,destroy,repair}/` to plain Markdown documentation at `docs/operations/{provision,destroy,repair}.md` (the operations are now `docker compose` invocations, not skills). Surviving orchestrator skills: `/release`, `/ci-status`, `/cloudflared-tunnel`, `/agent-browser`. Stale heartbeat/daemon/worktree-discovery docs (`docs/heartbeats/`, `docs/architecture/daemon.md`, `docs/architecture/worktrees.md`) deleted alongside; incidental `workspace/heartbeats/` references in `docs/guide/{configuration,workspace}.md` and `docs/agents/{overview,claude-code}.md` rewritten to point at the croner runtime + `crons/`. Pack-side counterparts for `cloudflared-tunnel` and `agent-browser` tracked in `ryaneggz/mifune#1` and `#2`. Per SPEC v0.7 §"Orchestrator vs workspace agent skills". ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - **BREAKING**: multi-agent comparison narrative archived. Deleted the still-draft `blog/2026-04-29-worktree-per-agent.md`; moved `blog/2026-04-28-byoh.md` to `blog/archive/2026-04-28-byoh.md` with `archived: true` frontmatter and a top-of-post note that v1 framing differs. Stripped the residual "side-by-side" wording from `docs/agents/overview.md`. Per SPEC v0.7 §"oh CLI" + §"Documentation source"; the v1 ICP statement at `.claude/ICP.md` now explicitly rejects multi-agent comparison-shopping framing as out-of-scope. ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - **BREAKING**: `@openharness/sandbox` CLI removed; `docker compose` is the canonical substrate. Deleted the `packages/sandbox/` workspace package (CLI binary + harness/onboard/lib/tools source + tests), the entry from `pnpm-workspace.yaml`, the `link:cli` script from root `package.json`, the now-stale `.github/workflows/ci.yml` (sandbox-only CI), and the duplicate `.github/workflows/build.yml` (which had been pushing a drifted `ghcr.io/ryaneggz/open-harness` image alongside the canonical `ghcr.io/ryaneggz/openharness` produced by `release.yml`). The CLI build/symlink block in `.devcontainer/entrypoint.sh` that wired `/usr/local/bin/openharness` and `/usr/local/bin/oh` is gone. `release.yml` is now the sole image producer. Per SPEC v0.7 §"oh CLI". ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - **BREAKING**: heartbeat daemon removed. Deleted `packages/sandbox/src/lib/heartbeat/` (~1,752 LOC), `packages/sandbox/src/cli/heartbeat-daemon.ts`, `packages/sandbox/src/cli/actions/heartbeat.ts`, `packages/sandbox/src/tools/heartbeat.ts`, the `oh heartbeat {start,stop,status}` command group, the `heartbeat-daemon` package bin, the seven `heartbeat-*.test.ts` suites, and `.claude/skills/heartbeat/`. Heartbeat env vars (`HEARTBEAT_ACTIVE_START`/`_END`/`_AGENT`) stripped from `.devcontainer/docker-compose.yml`; the legacy install-side daemon-startup blocks and the `/usr/local/bin/heartbeat-daemon` symlink in `.devcontainer/entrypoint.sh` are gone; `install/banner.sh` no longer advertises `heartbeat-daemon status`. The croner runtime (`scripts/cron-runtime.ts`, US-002/US-003/US-004) is the canonical replacement per SPEC v0.7 §"Croner runtime". ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - **BREAKING**: `@mariozechner/pi-coding-agent` is no longer a dependency. The pi agent CLI and Mom Slack bot have been extracted to a separate harness pack at [`ryaneggz/mifune`](https://github.com/ryaneggz/mifune) (npm: `@ryaneggz/mifune`). Install with `oh harness add @ryaneggz/mifune`. ([#208](https://github.com/ryaneggz/open-harness/pull/208)) ### Added - `context/` folder at repo root — orchestrator identity layer per the gist v0.6 spec §"context/" (https://gist.github.com/ryaneggz/8f6811efa144ac94d3cdc383846134d8), adapted for single-user harness scope. Four files: `SOUL.md` (voice and disposition, ~30 lines), `IDENTITY.md` (operating principles + append-only lessons learned, ~80 lines), `TOOLS.md` (environment inventory, ~40 lines), `USER.md` (working-relationship patterns, living document, ~45 lines). `AGENTS.md` bootloader updated with a session-start read instruction; `.claude/protected-paths.txt` extended with the four new entries so future cleanup passes do not delete them. Implements the session-loaded identity layer the v0.7 convergence (PR #212, US-013) correctly removed from `workspace/` (pack territory) but never created at the orchestrator level. The `IDENTITY.md` lessons-learned section captures the meta-principles surfaced this session (revealed > stated preference, critic-gate before destructive actions, short feedback loops over speculative infrastructure). ([#220](https://github.com/ryaneggz/open-harness/issues/220)) - `.claude/protected-paths.txt` — list of load-bearing skills, scripts, and config paths that critics must NOT propose deleting without an explicit override note in the finding's RECOMMENDATION column. Wired into `.claude/agents/critic.md` (general adversarial review) and `.claude/skills/ship-spec/SKILL.md` stage 3 (PRD critic gate). Replaces the per-invocation usage-logging proposal (closed as #217) after Critic B's proportionality argument: zero runtime overhead, works on day 1, ~20 LOC vs. an 8-story PRD with hooks. The v0.7 convergence (PR #212, US-012) deleted six load-bearing skills under "defensible 5-skill set" rationale; this list is the gate that would have caught it. ([#218](https://github.com/ryaneggz/open-harness/issues/218)) - **`/ship-spec` v1.1**: stages 3 and 5 reordered — critics run BEFORE the GH issue is opened (was: issue first, then critics). Earlier ordering created dangling issues when critics halted; now no GitHub-side state changes until the spec passes the critic gate. Surfaced during the dogfood run on issue #217. ([#218](https://github.com/ryaneggz/open-harness/issues/218)) - `/ship-spec` orchestrator skill at `.claude/skills/ship-spec/SKILL.md`. Composes `/prd` → 2 critics (parallel, asymmetric: implementer + user lens) → critique gate → `/ralph` → `gh issue` → branch + push → `gh pr create --draft` into one durable invocation. Critics write to `tasks//critique.md`; pipeline HALTs on any high-severity finding without mitigation. v1 stops at draft PR; loop launch + CI verification stay manual until the critic phase has been proven valuable across 2-3 real runs. Idempotent at every stage. ([#215](https://github.com/ryaneggz/open-harness/issues/215)) - v1 Ideal Customer Profile statement at `.claude/ICP.md`: primary persona (single working developer, one project, agent-tended), top three jobs-to-be-done, top three needs, and explicit anti-ICP (not multi-tenant SaaS, not non-developers, not production agent operators, not comparison-shopping tinkerers). ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - Seeded the two SPEC-reserved crons: `crons/heartbeat.md` (hourly pulse, `0 * * * *`) and `crons/cleanup-tasks.md` (Sunday 23:00, `0 23 * * 0`). Bodies follow SPEC v0.7 §"Croner runtime" + §"Weekly cleanup cron"; substrate stays empty otherwise so users add their own. ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - `.devcontainer/entrypoint.sh` now starts `scripts/cron-runtime.ts` in a `system-cron` tmux session on container boot, replacing the legacy `heartbeat-daemon` watchdog block. Idempotent (`tmux has-session` guard); restart policy is per-container-start per SPEC v0.7 §"Croner runtime". ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - `scripts/cron-runtime.ts` — minimal croner-backed runtime (≤120 LOC) that reads `crons/*.md` frontmatter, schedules per-cron tasks, runs the body as a prompt to `claude -p` (or `$CRON_AGENT_BIN`), logs to `crons/.cron.log`, and uses a PID-lock at `crons/.pid` to prevent double-firing. Replaces the 1,900-LOC heartbeat daemon per SPEC v0.7. ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - SPEC v0.7 amendments at `.claude/specs/structure-spec-v0.7.md` — additive-only revision resolving seven v0.6 conflicts (canonical image name, docs path, `oh` CLI deprecation, croner runtime contract, hook execution mechanism, memory directory format, tasks vs `.ralph` paths) and adding sections for harness packs, orchestrator-vs-workspace skill scope, and shrunk prose on Docusaurus config / eval flakiness / wiki-sync rubric / blog authorship / weekly cleanup. ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - README "Docker only (no installer)" section — concise compose-based deploy path for hosts that have only Docker + git. - Per-page OpenGraph + canonical link tags via theme.config.tsx head function ([#140](https://github.com/ryaneggz/open-harness/issues/140)). - Blog post draft: Worktree-per-agent — stages for Wed publish ([#145](https://github.com/ryaneggz/open-harness/pull/145)). - Blog section at /blog and About page nav entry (#143). - Blog post: BYOH — stop installing agent CLIs on your laptop (#144). - Root `CHANGELOG.md` and Keep-a-Changelog workflow documented in `.claude/rules/git.md`; `/release` now promotes `[Unreleased]` to the new version section at tag time. - Generate `sitemap.xml` and `robots.txt` during docs build via `next-sitemap` ([#141](https://github.com/ryaneggz/open-harness/issues/141)). - Launch runbook consolidating manual cutover steps (DNS, GH settings, OG validation, GSC, promotion). - Docusaurus v3 docs site at `apps/docs` deployed to oh.mifune.dev ([#164](https://github.com/ryaneggz/open-harness/issues/164)). ### Changed - Consolidated cron runtime log onto `crons/.cron.log`; the daemon no longer writes `crons/cron-runtime.log`. Both files were already gitignored under `crons/*.log`. ([#228](https://github.com/ryaneggz/open-harness/issues/228)) - Aligned the remaining flat-format memory references in tracked docs to the directory-per-day form per SPEC v0.7 §"Memory structure". Updated `docs/guide/workspace.md` (tree comment + daily-logs paragraph), `docs/guide/identity.md` (file table + memory protocol step + how-it-works paragraph), and `docs/architecture/container-runtime.md` (workspace tree comment) to use `memory/YYYY-MM-DD/log.md`. Flat `memory/.md` files are deprecated. ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - **BREAKING**: `CLAUDE.md` rewritten for `docker compose`-only orchestrator instructions. The Lifecycle (Setup/Validate/Teardown), Permissions, "What You Do", "Exposing apps", and Project Structure sections no longer reference `openharness sandbox/list/shell/clean/heartbeat` or `oh expose`/`oh harness add`; commands now use `docker compose -f .devcontainer/docker-compose.yml up -d --build`, `docker compose ps`, `docker exec -it -u sandbox openharness zsh`, and `docker compose ... down -v`. Skills table trimmed to the 4-skill triaged set (`/release`, `/ci-status`, `/cloudflared-tunnel`, `/agent-browser`); provision/destroy/repair are documented in `docs/operations/`. The orphaned `packages/sandbox/` entry in the project-structure block is removed and `scripts/` + `crons/` are added. `.claude/skills/cloudflared-tunnel/SKILL.md` no longer references `oh expose` (the gateway relationship is now described via `.claude/rules/gateway-routing.md`); `.claude/skills/ci-status/SKILL.md` updated to the actual workflow name `CI: Harness`. Per SPEC v0.7 §"oh CLI" + §"Orchestrator vs workspace agent skills". ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - **BREAKING**: `docs/installation.md`, `docs/onboarding.md`, `docs/sandbox-lifecycle.md`, and `docs/connecting.md` rewritten to remove `oh` CLI references. Installation is now `docker compose -f .devcontainer/docker-compose.yml up -d --build`; sandbox lifecycle uses `docker compose up/stop/down -v`; connecting uses `docker exec -it -u sandbox zsh`. Onboarding is now a manual checklist run inside the sandbox (gh auth, claude, optional ssh / cloudflared / pack-supplied Slack). Deleted the entire `docs/cli/` reference tree (overview, oh-sandbox, oh-shell, oh-clean, oh-onboard) and aligned stray `oh expose` / `oh clean` mentions in `docs/integrations/{cloudflare,github,postgres}.md`, `docs/architecture/{overview,container-runtime}.md`, and `docs/guide/overlays.md`. Per SPEC v0.7 §"oh CLI". ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - **BREAKING**: `README.md`, `docs/intro.md`, and `docs/quickstart.md` rewritten for single-project framing. The "run Claude, Codex, Gemini, and Pi side-by-side" tagline is gone; the harness is now framed as a Docker-based agent harness for **one project**, agent-tended over time. Quickstart leads with `docker compose -f .devcontainer/docker-compose.yml up -d --build`; all `oh` CLI references in these three files are gone (multi-agent setups now point at the [`@ryaneggz/mifune`](https://github.com/ryaneggz/mifune) harness pack). Per SPEC v0.7 §"oh CLI". ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - **BREAKING**: `install.sh` rewritten as a docker-compose-only installer. Removed `--cli`, `--with-cli`, `--install-node` flags and the auto-detect / 3-way `choose_path` prompt; removed `detect_node`, `install_nvm`, the nvm SHA-256 pin, the `pnpm setup` + `pnpm link --global ./packages/sandbox` block, and the local-repo `packages/sandbox/package.json` detection at the repo-resolution step. The script now only checks Docker + git, clones / pulls into `~/openharness`, prepares host auth dirs (`~/.claude`, `~/.codex`, `~/.claude.json`), writes `.devcontainer/.env`, runs `docker compose -f .devcontainer/docker-compose.yml up -d --build`, and prints next-steps using `docker exec -it -u sandbox zsh` and `docker compose ... down -v`. Per SPEC v0.7 §"oh CLI". ([#210](https://github.com/ryaneggz/open-harness/issues/210)) - `install.sh` curl-pipe target renamed `~/.openharness` → `~/openharness` so the cloned project no longer collides with the in-repo `.openharness/` config dir (`~/.openharness/.openharness/` was visually and semantically confusing). One-time migration: existing `~/.openharness` clones are `mv`'d to `~/openharness` automatically when the new path is absent. In-container paths (`/home/sandbox/.openharness`) are unchanged. ([#200](https://github.com/ryaneggz/open-harness/issues/200)) - Reverted the sandbox/orchestrator vocabulary realignment ([#170](https://github.com/ryaneggz/open-harness/issues/170), [#172](https://github.com/ryaneggz/open-harness/issues/172)). The in-container Linux user is `sandbox` again (UID/GID 1000 preserved); the `ORCHESTRATOR_USER`/`ORCHESTRATOR_HOME` constants are removed. The package name `@openharness/sandbox`, compose service, container default, `SANDBOX_NAME` env var, `POSTGRES_USER`, and `sandbox_*` Pi tool prefix were never changed. `install/banner.sh` carries an inverted migration guard for users coming back from a renamed image. ([#198](https://github.com/ryaneggz/open-harness/issues/198)) - Consolidate documentation: `/docs/` is now the single source of truth, served by Docusaurus from `apps/docs/` via `path: '../../docs'`. Enabled blog at `/blog/`. Removed the duplicate `apps/docs/docs/` tree. ([#178](https://github.com/ryaneggz/open-harness/pull/178)) - Installer auto-detects Node 20+; new `--cli` / `--docker-only` / `--install-node` flags; `--with-cli` deprecated. ([#176](https://github.com/ryaneggz/open-harness/pull/176)). - README and installation docs now use the short `https://oh.mifune.dev/install.sh` URL (302 redirect to the raw GitHub install script on `main`) instead of the long `raw.githubusercontent.com` URL. - `/release` now executes the `[Unreleased]` → `[$VERSION]` promotion (was prose-only) and `release.yml` sources the GitHub Release body from the promoted CHANGELOG section via `body_path` instead of `generate_release_notes`, so the GitHub Release notes match the changelog byte-for-byte. - Revert prior secondary product name; "Open Harness" is the sole brand across README, docs, and onboarding ([#157](https://github.com/ryaneggz/open-harness/issues/157)). - Cloudflare onboarding step now requires an explicit public hostname (no default domain) ([#157](https://github.com/ryaneggz/open-harness/issues/157)). - Slim README to ~110 lines, lead with oh CLI flow (#139). - Wiki promoted from `workspace/wiki/` to `docs/wiki/` — same structure (`pages/`, `sources/`, `index.md`, `log.md`), now top-level alongside human-curated docs. - 26 docs pages converted from Nextra MDX to plain markdown rendered by GitHub. ### Fixed - `make sandbox` and `scripts/install.sh` now expand `.openharness/config.json` `composeOverrides` into `-f` flags so the default claude/codex/pi host-auth bind-mounts actually apply on a fresh install. Previously both paths ran the base compose file only, silently falling through to named-volume auth despite the documented intent. Also pre-creates `~/.pi` alongside `~/.claude` and `~/.codex` in the install-time host-auth-dir loop, and removes residual references to the deleted `/provision` skill across docs and agent files. - Pi icon on the home-page agent grid no longer renders dim. Restored the inline `PiIcon` React component pattern from #168 (commit `fbda6a5`) so `currentColor` inverts cleanly between eggshell light and pure-black dark themes — the previous `` wiring sandboxed the SVG document and lost the `currentColor` inheritance. `apps/docs/static/img/agents/pi.svg` reverted to `fill="currentColor"` so the file stays theme-adaptive if loaded directly elsewhere. ([#233](https://github.com/ryaneggz/open-harness/pull/233)) - `.claude/hooks/deny-env-dump.sh` no longer false-denies on `gh ... --body "$(cat <<'EOF' ... EOF)"` invocations whose prose contains words like `history` or phrases like `cat .env`. Heredoc bodies are now stripped via `perl -0777` before pattern matching (handles `<