Adds .pi/extensions/slack/ with Socket Mode bridge, allowlist gating,
and 4 LLM-callable tools (slack_post/reply/react/upload). Inbound
messages bridge into pi.sendUserMessage() with ctx.isIdle() guard;
turn_end posts the assistant's reply back to Slack via SlackContext.
session_shutdown tears down the Socket Mode connection.
Customizations preserved from portfolio-advisor reference:
- threadTs field on event types (7 sites in events.ts)
- threadParent routing in createSlackContext (context.ts:45)
- exported parseEventContent + buildSyntheticEvent
Tests: 27 new (3 files); 78 pre-existing tests still green; 114 total.
Plan: .claude/plans/context-study-https-github-com-ryaneggz-binary-hartmanis.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per SPEC v0.7 §"oh CLI" deprecation. Atomic file-deletion mass:
- Removed packages/sandbox/ workspace (CLI + harness/onboard/lib/tools + tests)
- Removed packages/sandbox entry from pnpm-workspace.yaml
- Removed link:cli script from root package.json
- Removed .github/workflows/build.yml (was duplicating release.yml's image
build, pushing to ghcr.io/ryaneggz/open-harness — drifted from canonical
ghcr.io/ryaneggz/openharness produced by release.yml)
- Removed .github/workflows/ci.yml (sandbox-only CI now stale)
- Removed CLI build/symlink block from .devcontainer/entrypoint.sh that
wired /usr/local/bin/openharness and /usr/local/bin/oh
- Rewrote .husky/pre-commit to run root-level lint + test (was cd'ing into
the now-deleted packages/sandbox/)
- Regenerated pnpm-lock.yaml (-49 packages)
release.yml is now the sole image producer pushing
ghcr.io/ryaneggz/openharness:<tag> + :latest.
Refs #210
Adds scripts/cron-runtime.ts (119 LOC) that reads crons/*.md frontmatter
and schedules each cron with the croner npm package, replacing the
1,900-LOC heartbeat daemon per SPEC v0.7 §"Croner runtime".
- Frontmatter parser: id, schedule, timezone, enabled, overlap, catchup
- Skips files where enabled is false
- Fires each cron's markdown body as a prompt to claude -p (CRON_AGENT_BIN
env var overrides the binary)
- Logs to crons/cron-runtime.log (ISO timestamp, cron id, status)
- PID lock at crons/.pid prevents double-firing; stale locks are stolen
- Clean SIGTERM/SIGINT cleanup unlinks the PID file
Adds 9 vitest tests covering frontmatter parsing, skip-when-disabled,
PID-lock acquisition, live-process collision, and stale-lock recovery.
Wires scripts/__tests__/ into a root vitest.config.ts so pnpm run test
picks them up.
Refs #210
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat!: extract pi-coding-agent + slack to ryaneggz/mifune
BREAKING CHANGE: pi-coding-agent dep, packages/slack, slack/pi-host
overlays, and pi-specific docs all removed. Users who want the prior
behavior install the mifune harness pack:
oh harness add @ryaneggz/mifune
See ryaneggz/mifune for the extracted code and docs (npm:
@ryaneggz/mifune, image: ghcr.io/ryaneggz/mifune:latest).
Closes Phase C of the openharness/mifune split. Phase A landed in PR
#208 (pack contract); Phase B published the mifune repo + tag 2026.5.2.
Changes:
- Drop @mariozechner/pi-coding-agent from packages/sandbox/package.json
- Add @types/node devDep (was a transitive of the dropped pi dep)
- Remove packages/slack (Mom slack bot)
- Remove .devcontainer/docker-compose.{slack,pi-host}.yml overlays
- Remove .openharness/extensions/custom-banner.ts
- Remove packages/sandbox/extensions/{sandbox,claude-rules}.ts
(only consumers were the pi-extensions API)
- Remove packages/sandbox/src/onboard/steps/slack.ts
(now contributed by the mifune pack via onboard_steps[])
- Strip slackStep from ALL_STEPS export in onboard/steps/index.ts
- Update onboard-pack-steps test: slack is no longer a core step
- Default Dockerfile AGENTS to "claude-code,codex" (was including
pi-coding-agent); drop `alias mom=...` in .bashrc
- Default .openharness/config.json drops slack/pi-host overlays
- Strip test-slack job + packages/slack path triggers from ci.yml
- Strip INSTALL_PI_AGENT / INSTALL_MOM env vars + prompts from
install/setup.sh; suggest `oh harness add @ryaneggz/mifune` instead
- Replace pi-auth symlink + Mom auto-launch in entrypoint.sh with a
generic harness-pack hook loop (/usr/local/bin/*-entrypoint-hook.sh)
- Strip .pi from the chown skip-loop in entrypoint.sh (no more
PI_HOST_BIND_MOUNT)
- Update README.md, AGENTS.md/CLAUDE.md, docs/{intro,quickstart,
installation,onboarding,agents/overview,guide/{overlays,permissions,
configuration,identity},integrations/slack}.md, apps/docs/src/pages/
index.tsx — strip pi/slack mentions, link to @ryaneggz/mifune
- Add CHANGELOG entry under [Unreleased] § Removed
Signed-off-by: OpenHarness Bot <noreply@openharness.local>
* chore: gitignore .claude/worktrees, drop stale heartbeat, log 2026-05-02
- .gitignore: ignore .claude/worktrees/ — agent worktrees registered against the
in-container git dir leak into host git status as untracked at the project root.
Their content lives on the registered branches (and via squash merge typically
ends up in development), so the host root never needs to track them.
- workspace/heartbeats/resume-bc471449-continue.md: removed (untracked). Per
workspace/memory/2026-05-02.md, the heartbeat fired and the target Claude
session ID was already gone ("No conversation found"). Stale; daemon was
emitting failures every 10:31 UTC.
- workspace/memory/2026-05-02.md: today's daily memory log — same pattern as
the 23 prior 2026-04-*.md files already tracked under workspace/memory/.
Companion to #209 (mifune extraction); cleans up loose orchestrator state.
Signed-off-by: OpenHarness Bot <noreply@openharness.local>
---------
Signed-off-by: OpenHarness Bot <noreply@openharness.local>
Co-authored-by: OpenHarness Bot <noreply@openharness.local>
* task: parameterize Dockerfile agent CLI installs via ARG AGENTS
Replace hardcoded `npm install -g @anthropic-ai/claude-code @openai/codex
@mariozechner/pi-coding-agent` with a build-arg-driven loop.
`ARG AGENTS` defaults to `claude-code,codex,pi-coding-agent` so the
default build behavior is unchanged (non-breaking). Downstream images
or future PRs can override via `--build-arg AGENTS="claude-code,codex"`.
Adds `SHELL ["/bin/bash", "-c"]` so `declare -A` (associative array
mapping agent key → npm package) is available; the previous Debian-sh
default would not parse it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* task: decouple ToolDefinition types from pi-coding-agent
* feat: add onboard step plugin contract for harness packs
Define HarnessPack and PackStep types and a registry-based loader
(loadPackSteps + orderSteps + getAllSteps) that merges core onboard
steps with steps contributed by installed harness packs. The loader
reads .openharness/harnesses.json, dynamic-imports each pack's compiled
step modules, and topo-orders the result via the after-by-id map.
Wires getAllSteps() into the onboard CLI entrypoint so pack authors can
extend onboarding without forking the core package. Slack step stays
hardcoded in ALL_STEPS for now; Phase C extracts it to mifune as the
first user of the plugin contract.
Adds 8 unit tests covering missing/empty registry, importer override,
pack step loading, error swallowing, and topo ordering.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor: migrate oh CLI to Commander.js
Replace the hand-rolled subcommand router (~260 lines of switch in
cli/index.ts plus ~324 lines of helpers in cli/cli.ts) with a
Commander.js-based program. Each subcommand is now a single
.action(...) call that lazy-loads its implementation from
src/cli/actions/*.ts via dynamic import — keeps cold-start fast for
--help and --version.
Notable changes:
- Drop `import { main, VERSION } from "@mariozechner/pi-coding-agent"`.
Bare `oh` no longer launches a TUI; Commander auto-prints help.
- `--version` returns the package.json version (no "(pi VERSION)"
suffix).
- Heartbeat is now a subcommand group: oh heartbeat start|stop|status
<name> (replaces the legacy `oh heartbeat <action> <name>` form;
drops `migrate` action entirely).
- New harness subcommand group: oh harness add|list|remove. Action
handlers print "not yet implemented (T5)" and exit 1 — wiring lands
in the harness-pack-contract PR.
- Host-only enforcement (sandbox/run/stop/clean/shell/list) moved
from an ad-hoc check to a Commander preAction hook.
- buildProgram() exported for tests so they can introspect the
registered command tree without spawning a subprocess.
Tests rewritten to verify the Commander program structure
(registered commands, required vs optional args, option flags,
subcommand groups). The legacy parseToolArgs / resolveSubcommand /
helpText / formatResult helpers are gone; the surface they tested
no longer exists.
24 test files / 349 tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: add harness-pack contract (oh harness add|list|remove)
Build the openharness side of the openharness/mifune split:
src/harness/pack.ts — pack source resolver (npm / git / local) plus
installer + uninstaller pipeline. The resolver classifies a `oh harness
add <spec>` argument into one of three modes:
- @scope/name | bare name → npm install -g
- owner/repo | https:// | git@ → git clone
- ./path | /abs → local symlink (no copy)
After source resolution, every pack runs the same install pipeline:
validate harness.json, append compose_overlays to .openharness/config.json,
run install-hook.sh, symlink entrypoint-hook.sh into /usr/local/bin/, and
register the pack in .openharness/harnesses.json. Side effects route
through a PackEnv injection bag so unit tests swap fakes.
src/harness/registry.ts — moved from onboard/registry.ts to its proper
home alongside the installer. Extended with writeHarnessRegistry,
addInstalled, removeInstalled. Defensive parser upgrades pre-T5 entries
in place (missing source/spec default to "local" + path).
src/cli/actions/harness.ts — replace the T2-era "not yet implemented"
placeholders with real installPack / uninstallPack / readHarnessRegistry
calls, formatted output for the CLI surface.
docs/guide/bring-your-own-harness.md — pack contract reference for
authors: schema, source modes, onboard-step shape, distribution options.
Adds 25 unit tests covering source resolution, manifest validation,
registry round-trip, install/uninstall against a tmp pack with mocked
PackEnv. 26 test files / 382 tests pass total.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* task: make @openharness/sandbox installable via npm link
- packages/sandbox/package.json: add postbuild chmod +x on bin scripts
(tsc strips the executable bit; npm link / npm install -g need it).
Add `files` field listing the publishable surface so `npm publish`
produces a clean tarball.
- package.json: split the broken `pnpm link --global` out of `setup`
(PNPM_HOME = /usr/local/share/pnpm is root-owned in the sandbox image
so the global link errors EACCES). Replace with an explicit
`pnpm run link:cli` script the user opts into when they have a
user-writable pnpm prefix.
- docs/contributing.md: document the build-and-link sequence + clarify
that the orchestrator sandbox's entrypoint already auto-links the
CLI on every container boot, so `pnpm run link:cli` is only needed
on a local-laptop checkout.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: OpenHarness Bot <noreply@openharness.local>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drops the docs workspace and its Next.js/Nextra dependencies from
pnpm-lock.yaml — direct consequence of removing docs/ in the parent
commit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace Nextra 2.13.4 with Fumadocs (fumadocs-core + fumadocs-ui + fumadocs-mdx)
on Next.js 16. Migrates from Pages Router to App Router with two content sources:
- /docs — static documentation (29 MDX pages migrated from Nextra)
- /wiki — LLM-generated wiki pages (symlinked from workspace/wiki/pages/)
Key changes:
- Swap nextra/nextra-theme-docs deps for fumadocs stack + Tailwind CSS 4
- Convert _meta.json nav files to Fumadocs meta.json format
- Convert Mermaid JSX components to fenced mermaid code blocks
- Update internal links from /open-harness/ to /docs/ prefix
- Add Orama search API route
- Support both dev server (tunnel) and static export (GitHub Pages)
- Update docs.yml workflow to trigger on workspace/wiki/** changes
- Update startup.sh: start docs on port 3001, support multiple tunnels
- Add wiki/pages/index.md landing page for /wiki route
Tunnel setup (manual, one-time):
~/install/cloudflared-tunnel.sh docs docs.ruska.dev 3001
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the 470-line install/heartbeat.sh with an in-process croner
daemon. New modules: config, logger, lock, gates, runner, scheduler,
daemon — all with vitest tests (110 new tests, 200 total).
- Add croner ^9.1.0 dependency for cron scheduling
- Update entrypoint.sh to start TS daemon instead of cron
- Update tools/heartbeat.ts to delegate to TS daemon
- Convert heartbeat.sh to deprecation shim
Closes#58
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add packages/slack to pnpm workspace so its dependencies (croner,
pi-agent-core, etc.) resolve in CI. Make build script skip gracefully
when tsgo is unavailable. Tests run via pnpm -r run test.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
npx vitest downloads a mismatched version in CI that can't resolve the
config. Install vitest at root and run directly via `vitest run --config`.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The slack package uses tsgo (not available in CI). Revert workspace
addition and run slack tests directly via --config flag instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove verbose tool result thread posts for successful tool calls — only
errors now surface in Slack threads. Add threadTs support to the events
system so events can target existing threads. Includes 37 new tests
covering both features, integrated into CI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>