Files
open-harness/CHANGELOG.md
T
2026-05-22 06:31:53 +00:00

70 KiB
Raw Blame History

Changelog

All notable changes to this project are documented here.

Format follows Keep a Changelog; 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 § Changelog.

[Unreleased]

Added

  • /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).
  • /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 (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).
  • /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).
  • /render-html skill (.claude/skills/render-html/SKILL.md) — orchestrator skill for rendering an artifact as a bespoke, self-contained HTML file under memory/<UTC-date>/<slug>.html for one-shot human review (audit synthesis, council output, lint matrix, weekly digest). Output is gitignored via existing memory/[0-9]*/ rule (#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).

Changed

  • 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).
  • 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).
  • 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): 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).

Fixed

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).

Deprecated

Security

[2026.5.18] - 2026-05-18

Added

  • OH_GITHUB_REPO and OH_GITHUB_REF env vars for fork-friendly installs (#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).
  • /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).

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).

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)
  • 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)

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)
  • 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)
  • 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)
  • 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)
  • .worktrees/README.md now reserves .worktrees/project/<owner>/<repo>/ 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, #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)

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)

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)

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)
  • 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)
  • 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)
  • .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)
  • 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 <details> "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)
  • 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)
  • 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)
  • 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)
  • 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)

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 / #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)
  • 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 merged a conflicting entrypoint.sh. (#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, <path>.tmp.<pid> + renameSync for crash safety), and agent-pi tmux session restart with connected and listening poll (15s). Pluggable via oh config <integration> 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)
  • 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)
  • 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. 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, #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, #270)
  • Slack integration as a Pi extension at .pi/extensions/slack/ (#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)
  • 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/<project-name>/<repo>/ 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)
  • 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)
  • 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 <name>-sandbox (Compose's default <project>-<service> tag) to sandbox-<name> 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 (<name>-postgres, <name>-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)
  • 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)
  • 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 <tunnel-id>.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 <T>) silently drop the local --url flag, leaving Cloudflare to return 530s while connections register. (#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 <details> 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 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/<today>/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)
  • 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)
  • 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)
  • 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)
  • 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)
  • 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)
  • Remove five stale or corrupted .worktrees/ agent directories and stale worktree registrations, reducing the ignored worktree footprint below 100 MB. (#213)
  • Remove the dead legacy install-side setup, entrypoint, and tmux wrapper scripts now that the Dockerfile wires .devcontainer/entrypoint.sh directly. (#213)
  • Remove the empty untracked packages/web-ui/ and packages/slack/ husks, plus the stale Slack workspace and entrypoint references. (#213)
  • Remove the obsolete on-disk SPEC v0.6 artifact so .claude/specs/ only exposes canonical tracked specs. (#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: 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)
  • 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)
  • 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)
  • 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)
  • 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)
  • 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)
  • 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 (npm: @ryaneggz/mifune). Install with oh harness add @ryaneggz/mifune. (#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)
  • .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)
  • /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)
  • /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/<slug>/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)
  • 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)
  • 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)
  • .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)
  • 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)
  • 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)
  • 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).
  • Blog post draft: Worktree-per-agent — stages for Wed publish (#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).
  • 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).

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)
  • 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/<date>.md files are deprecated. (#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)
  • 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 <name> 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)
  • 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 harness pack). Per SPEC v0.7 §"oh CLI". (#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 <name> zsh and docker compose ... down -v. Per SPEC v0.7 §"oh CLI". (#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)
  • Reverted the sandbox/orchestrator vocabulary realignment (#170, #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)
  • 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)
  • Installer auto-detects Node 20+; new --cli / --docker-only / --install-node flags; --with-cli deprecated. (#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).
  • Cloudflare onboarding step now requires an explicit public hostname (no default domain) (#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 <img src="/img/agents/pi.svg"> 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)
  • .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 <<DELIM, <<'DELIM', <<"DELIM", <<-DELIM). The Tier-2 ASK rule for echo|printf of any uppercase $VAR was also removed — too broad on benign echo "Branch: $BRANCH" patterns; the deny tier above already catches secret-named variables (TOKEN, SECRET, AUTH, KEY, GH_TOKEN, AWS_*, …). .claude/skills/ship-spec/SKILL.md updated to note heredoc bodies are now safe (was: "prefer --body-file over heredoc"). (commit 3ec98fe)
  • Correct the container runtime documentation to show Dockerfile ENTRYPOINT ["entrypoint.sh"] invoking .devcontainer/entrypoint.sh directly, with install/banner.sh only sourced for interactive shell status. (#213)
  • Restored six orchestrator skills removed in error during the v0.7 convergence (US-012, commit fb71365): /ralph (PRD → prd.json converter), /prd (PRD generator), /harness-audit (parallel-sub-agent codebase audit), /skill-lint (skill staleness scorer), /delegate (parallel execution coordinator), and /strategic-proposal (council-based roadmap planning). The triage rationale ("workspace-agent skills, not orchestrator") was wrong: the orchestrator actively uses the prd.json schema for its own task management (e.g. tasks/openharness-v07-convergence/prd.json), so removing the tools that produce that schema was a regression. scripts/ralph.sh (the runner) was kept all along — only the wrapper skills were lost. Restored from fb71365^ unchanged; CLAUDE.md skills table updated.
  • install.sh now auto-disables the *-host.yml overlays in .openharness/config.json when host UID ≠ 1000 (was: a multi-line warning telling the user to do it by hand). Mode-0600 credential files in ~/.claude / ~/.codex / ~/.pi can't be read across UIDs, and mode-0700 dirs (e.g. ~/.pi/agent/sessions/) reject writes from non-owner UIDs — the sandbox user (UID 1000) would EACCES on oh / claude / codex / pi. The new logic uses jq to filter claude-host.yml, codex-host.yml, pi-host.yml out of composeOverrides so the base named volumes take over. The original warning is retained as a jq-missing fallback. (#202)
  • Host auth (~/.claude, ~/.codex, ~/.pi) is shared into the sandbox again. install.sh now pre-creates the three auth dirs and ~/.claude.json (empty if missing) before sandbox bring-up so docker can't auto-create them root-owned, and claude-host.yml / codex-host.yml / pi-host.yml are restored to default composeOverrides. UID-mismatch hosts (UID ≠ 1000) get a loud install-time warning telling them to drop the overlays from .openharness/config.json (mode-0600 credential files can't be read across UIDs). Together this restores the convenience that was lost in #194 / #195 without re-introducing the EACCES failure mode that motivated those PRs. (#196)
  • oh / claude / codex no longer fail with EACCES (or silent re-auth) on fresh install.sh installs. Removed docker-compose.claude-host.yml, docker-compose.codex-host.yml, and docker-compose.pi-host.yml from the default composeOverrides in .openharness/config.json. Each overlay's own header documents that it requires host UID 1000 + the source dir to pre-exist; shipping them as defaults broke any host where either condition wasn't met (docker auto-creates missing source dirs as root → sandbox user (UID 1000) can't write). The base compose's claude-auth / codex-auth / pi-auth named volumes now take effect by default; entrypoint.sh chowns them to UID 1000 on first boot. Single-laptop developers wanting cross-sandbox auth sharing can opt back in by appending the relevant overlay(s) to .openharness/config.json. (#194)
  • oh sandbox no longer fails on fresh install.sh installs with a Caddyfile bind-mount error. Removed docker-compose.gateway.yml and docker-compose.cloudflared.yml from the default composeOverrides in .openharness/config.json; both are additive overlays now loaded only when needed (oh expose re-adds the gateway via SandboxConfig.addOverride()). (#192)
  • install.sh next-steps now leads with a numbered "source your shell rc" step that detects $SHELL (bash → ~/.bashrc, zsh → ~/.zshrc, fish → ~/.config/fish/config.fish) so users don't have to exit + reopen their shell to pick up oh / node / pnpm. Curl-piped install runs in a child bash whose exports cannot reach the parent shell — the source step is now Step 1 of next-steps (was a buried "Reminder").
  • install.sh bootstraps PNPM_HOME before pnpm link --global so the CLI install no longer dies with ERR_PNPM_NO_GLOBAL_BIN_DIR on fresh nvm-installed Node. Runs pnpm setup (writes PNPM_HOME export to ~/.bashrc + ~/.zshrc) and also exports PNPM_HOME/PATH inline so the link step succeeds in the current shell regardless of rc state.
  • install.sh no longer silently exits when sourcing a pre-existing ~/.nvm/nvm.sh under set -euo pipefail. nvm + corepack calls are bracketed with relaxed strict mode and explicit $? checks, an ERR trap surfaces unexpected failures with the failing command and line, and pnpm is pinned to 10.33.0 (matches package.json#packageManager) instead of resolving pnpm@latest over the network on every install.
  • Slack bot no longer drops oversized agent replies with cascading msg_too_long errors. Main message is capped at 2,900 chars with a _message truncated — full response in thread_ footer; full content spills to thread replies; setWorking(false) always clears the working indicator. (#135)

Removed

  • Removed legacy /docs/{plans,wiki,launch-runbook,blog}/ and apps/docs/docs/ tree (consolidated into /docs/). (#178)
  • Nextra docs site and the .github/workflows/docs.yml deployment — documentation is now plain markdown in docs/, read in the GitHub UI.
  • Reference Next.js application at workspace/projects/next-app/, along with its CI jobs (workspace/projects/next-app paths in ci.yml / release.yml) and the release pre-flight gate referencing it.
  • Root package.json scripts: dev, docs:dev, docs:build, docs:preview.

Deprecated

Security


Release history prior to this file: see git tags and GitHub Releases. Most recent pre-changelog tag: 2026.4.22.