Files
open-harness/CHANGELOG.md
T

22 KiB

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]

Removed

  • 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 daemon-startup blocks in install/entrypoint.sh 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

  • 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-runtime.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

  • 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

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