Skip to content

Harness support

Each agent loads skills from a different directory and dispatches work its own way. What follows was verified on 2026-09-19 against Claude Code, pi 0.85.1, and codex-cli 0.146.0.

Claude Code Codex Pi
Payload plugin marketplace plugin Pi package
Skills .claude/skills/ plugin skills .agents/skills/, .pi/skills/
Commands skills, .claude/commands/ $thunderstorm:<skill> .pi/prompts/
Dispatch subagents built-in agents with roles a session per multiplexer tab
Checks hooks, both events a hook on commands only an extension, refusals only
Merging deny rules hook blocks the prefixes extension blocks the prefixes

On Claude Code a skill is also the slash command of its own name, so /implement loads the implement skill directly. The Claude payload carries command files only for /rev and /adv-rev, which have no skill of that name.

What happens to a command of your own with a skill’s name depends on how the loop was installed. Installed as a plugin, the skill is /thunderstorm:implement, and the bare /implement reaches it only while no other command holds that name, so your .claude/commands/implement.md keeps /implement. Installed with tstorm install, the skill sits in the repository’s .claude/skills/, and a skill there wins over a .claude/commands/ file of the same name. Your command would stop running, so install refuses it as a collision, and --replace removes it. This was checked against Claude Code’s skills documentation on 2026-10-14.

The renderer builds all three payloads from the same skills, commands, role definitions, and scripts. Codex packages the role definitions as TOML, and the orchestrator passes their instructions to built-in agents. Pi carries the Markdown definitions for reference while tstorm dispatch uses the same definitions embedded in the binary.

.agents/skills/ is read by both Codex and Pi, so one directory serves them together. Claude Code reads only .claude/skills/, which is why each agent gets its own rendered payload. The repository commits one under payloads/ for each harness, all rendered from workflow/ by tstorm render, and each harness installs from its own directory. None is edited by hand: tstorm render --check fails when a payload differs from what the workflow renders.

A SKILL.md file is the same everywhere. All three agents expect a directory holding one, with name and description in the frontmatter.

Cursor and OpenCode Go are planned too, and neither has been assessed: no Cursor agent was installed when these contracts were verified.

Codex has a multi-agent system with four concurrency slots, counting the orchestrator. Every agent it spawns shares one working directory, so the loop creates a git worktree for each worker and tells it where to go before any work starts.

Pi has no subagent mechanism. A worker there is a separate pi session running in a tmux window or Zellij tab, given its provider, model, thinking level, and tool list as command-line arguments. --multiplexer auto uses the session that contains Pi; an explicit flag chooses one in a nested setup.

The Codex orchestrator reads each packaged role and starts a built-in agent with those instructions. Reviewer roles run read-only; implementer and reviser roles may write in their worktree.

The loop denies four commands: gh pr merge, gh pr review, git push and git merge. Claude Code takes them as written, one deny rule each. Codex loads a PreToolUse hook from the enabled plugin and denies matching shell commands. An optional execpolicy file applies the same policy when the plugin is disabled. Pi’s package extension intercepts its bash tool and blocks the same prefixes. Pi still leaves process isolation to the operating system or a container.

Configuration explains what each harness loads.

The loop names a model on every dispatch so that an implementer and the reviewer reading its work are never the same model. Codex makes this easy to get wrong. A full-history fork inherits the parent’s model and reasoning effort and will reject an override, so a dispatch has to set fork_turns to "none" or to a number before it can choose anything.