
Security News
The Code You Didn't Write Is Still Yours to Defend
AI agents are pulling packages into environments no scanner is watching, creating exposure before security teams can see it.
@agent-pattern-labs/iso-harness
Advanced tools
One config for every coding agent — Cursor, Claude Code, Codex, OpenCode, Pi.
One config for every coding agent — Cursor, Claude Code, Codex, OpenCode, Pi.
Keep your instructions, subagents, commands, and MCP servers in a single
iso/ directory. iso-harness build transpiles that source to the
file layout each harness actually reads.
iso/ → CLAUDE.md (Claude Code)
├── instructions.md .claude/agents/*.md
├── instructions.agents.md* .claude/commands/*.md
├── instructions.claude.md* .mcp.json
├── instructions.cursor.md* → AGENTS.md (Codex + OpenCode + Pi)
├── instructions.opencode.md* .codex/config.toml
├── mcp.json .opencode/agents/*.md
│ .opencode/skills/*.md
│ .opencode/instructions.md* (OpenCode-only addendum)
│ .opencode/opencode-model-fallback.json (optional; from `opencodeModelFallback` in iso/config.json)
│ opencode.json
│ → .cursor/rules/*.mdc (Cursor)
│ .cursor/mcp.json
│ → .pi/skills/*/SKILL.md (Pi)
│ .pi/prompts/*.md
├── agents/ .mcp.json
│ └── researcher.md
└── commands/
└── review.md
Files marked with * are optional.
npm install
node bin/iso-harness.mjs build --source examples/minimal/iso --out /tmp/iso-demo
Or once installed as a CLI:
iso-harness build # reads ./iso, writes to ./
iso-harness build --target claude,cursor # only two targets
iso-harness build --source path/to/iso --out path/to/project
iso-harness build --dry-run # print planned writes, no disk changes
iso-harness build --watch # rebuild on every change under iso/
--dry-run validates and renders the full output plan, but prints what
would be written instead of touching disk.--watch keeps a filesystem watcher on the source directory and reruns the
build after changes. Combine it with --target when you only care about one
harness while iterating.iso/
├── instructions.md # root prompt → CLAUDE.md / AGENTS.md / .cursor/rules/main.mdc
├── instructions.agents.md # optional addendum for shared AGENTS.md targets
├── instructions.claude.md # optional Claude-only root addendum
├── instructions.cursor.md # optional Cursor-only root addendum
├── instructions.opencode.md # optional OpenCode-only addendum, loaded via opencode.json.instructions
├── config.json # optional — targets.* merges + opencodeModelFallback file emit
├── mcp.json # shared MCP server definitions
├── agents/ # subagents
│ └── <slug>.md # YAML frontmatter + body
└── commands/ # slash commands / skills
└── <slug>.md # YAML frontmatter + body
mcp.jsonA harness-neutral schema. Each server has command, optional args, optional
env. The emitter translates to the shape each harness expects (e.g.
OpenCode wants type: "local" and command as an array).
{
"servers": {
"example": {
"command": "npx",
"args": ["-y", "@example/mcp"],
"env": { "EXAMPLE_MODE": "demo" }
}
}
}
By design, mcp.json has no per-harness override mechanism. The
same MCP server should behave the same way no matter which harness
launches it — if it doesn't, that's an MCP/config issue to fix at the
server level, not something the shared config should paper over.
---
name: researcher
description: Researches technical topics.
model: sonnet
tools: [Read, Grep, WebFetch]
targets:
cursor: skip # don't emit for Cursor
codex: skip
opencode: # per-target overrides pass through verbatim
temperature: 0.2
fallback_models: [foo, bar]
---
Agent prompt body goes here.
---
name: review
description: Review the current git diff.
args: "[scope]" # argument hint
targets:
cursor: skip
---
Slash-command body goes here.
| Harness | Instructions | Agents | Commands | MCP |
|---|---|---|---|---|
| Claude Code | CLAUDE.md | .claude/agents/*.md | .claude/commands/*.md | .mcp.json |
| Cursor | .cursor/rules/main.mdc | .cursor/rules/agent-*.mdc | (no native form) | .cursor/mcp.json |
| Codex | AGENTS.md | (no native form) | (no native form) | .codex/config.toml |
| OpenCode | AGENTS.md | .opencode/agents/*.md | .opencode/skills/*.md | opencode.json |
| Pi | AGENTS.md | .pi/skills/*/SKILL.md | .pi/prompts/*.md | (extension/package only) |
The abstraction is only as good as its lowest common denominator. Four explicit hatches keep harness-specific features possible:
targets: (agents & commands).
Harness-specific fields under targets.<name> are mapped or passed
through where that target supports them. Use this for OpenCode
temperature / fallback_models, Claude Code allowed-tools, Pi
skill metadata, etc.targets.<name>: skip omits the item from a specific target —
useful when a subagent only makes sense in harnesses that support
subagents.iso/config.json with targets.<name>: { … } for top-level
harness config (not per-item). Keys under targets.opencode are
merged into the generated opencode.json — use this for OpenCode's
top-level instructions: [...] array, for example. Keys under
targets.pi are merged into .pi/settings.json.iso/config.json top-level opencodeModelFallback — JSON object
written verbatim to .opencode/opencode-model-fallback.json for the
@agent-pattern-labs/opencode-model-fallback
plugin (retryable_error_patterns, global fallback_models, etc.).
OpenCode-only; other harnesses ignore it.instructions.md is still the shared base prompt. Optional sibling files let
you add harness-specific root guidance without forking the whole source:
instructions.agents.md appends only to the shared AGENTS.md output used by Codex, OpenCode, and Pi.instructions.claude.md appends only to CLAUDE.md.instructions.cursor.md appends only to .cursor/rules/main.mdc.instructions.opencode.md is emitted to .opencode/instructions.md and automatically added to opencode.json.instructions.This is especially useful when OpenCode needs extra orchestration guidance
that should not leak into the shared AGENTS.md file that Codex and Pi also read.
// iso/config.json
{
"targets": {
"opencode": {
"instructions": ["templates/states.yml"]
},
"pi": {
"prompts": ["prompts"],
"enableSkillCommands": true
}
},
"opencodeModelFallback": {
"cooldown_seconds": 60,
"retryable_error_patterns": ["(?i)venice.*insufficient"],
"fallback_models": ["openrouter/openai/gpt-oss-120b:free"]
}
}
Per-agent OpenCode fallback_models still belong in agent frontmatter
under targets.opencode. Use opencodeModelFallback only for the
global plugin file OpenCode loads from .opencode/.
@agent-pattern-labs/iso-routeWhen @agent-pattern-labs/iso-route
writes its resolved role map to <out>/.claude/iso-route.resolved.json
(normally by running iso-route build into the same output directory
before iso-harness build), iso-harness picks it up automatically and
stamps model: onto each Claude subagent frontmatter.
Resolution order per subagent, highest to lowest:
targets.claude.model from the agent's frontmatter.model: from the agent's frontmatter.roles[agent.role ?? agent.slug].model from the resolved map.model: field.So an author can (a) hard-pin a model in the source file, (b) let iso-route drive it from policy, or (c) leave it to Claude Code's session default — without editing the agent body.
Non-Anthropic roles in the resolved map are skipped (Claude Code subagents can only run Anthropic models) and logged on stderr. Missing roles are silent — not every agent needs a role entry.
For Pi, iso-route owns .pi/settings.json model defaults. If
iso/config.json also contains targets.pi, iso-harness merges those
project settings into the existing file instead of replacing model
settings.
The contract is file-based on purpose: iso-harness and iso-route publish and version independently, so an on-disk JSON file is more robust than a TypeScript import across the two.
Releases are cut via a GitHub Release, which triggers
.github/workflows/release.yml to publish @agent-pattern-labs/iso-harness to npm
with provenance.
Prerequisites (one-time):
NPM_TOKEN — an npm automation token with publish
rights on the @agent-pattern-labs scope. Set at
https://github.com/Agent-Pattern-Labs/iso-harness/settings/secrets/actions.@agent-pattern-labs must exist and the token must have access.Cutting a release:
# 1. Bump version, commit, push. CI (Quality checks) must pass on the
# pushed commit — the release workflow refuses to publish otherwise.
npm version patch # or minor/major — bumps package.json + tags
git push && git push --tags
# 2. Create the GitHub Release off the tag. This fires release.yml.
gh release create "v$(node -p 'require(\"./package.json\").version')" \
--generate-notes
The release workflow will:
package.json version matches the tag via
scripts/release/check-source.mjs.npm publish --provenance --access public.If the publish step fails (e.g. token, 2FA, name conflict), fix the cause, delete the GitHub release + tag, and re-cut — do not amend.
v0.1 — instructions, agents, commands, MCP. Hooks, permissions, and per-harness-only features are out of scope for v1.
FAQs
One config for every coding agent — Cursor, Claude Code, Codex, OpenCode, Pi.
We found that @agent-pattern-labs/iso-harness demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
AI agents are pulling packages into environments no scanner is watching, creating exposure before security teams can see it.

Security News
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.

Product
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.