Skip to content

feat: sync harness plugins to the Claude Code plugin's surface - #49

Merged
pratikbin merged 7 commits into
mainfrom
feat/sync-harness-plugins
Sep 11, 2026
Merged

feat: sync harness plugins to the Claude Code plugin's surface#49
pratikbin merged 7 commits into
mainfrom
feat/sync-harness-plugins

Conversation

@pratikbin

Copy link
Copy Markdown
Contributor

What

  • codex: renamed @createos/codexcreateos-sandbox-codex; now ships the same cos driver + skill + session-start/pre-tool-use hooks
  • shared: new sandbox-engine.ts — TypeScript port of cos (offload, keepalive, egress presets, auto-destroy, staging excludes, computer use)
  • opencode: 33 → 38 tools (offload, fanout, desktop, computer, screenshot)
  • pi: 34 → 38 sandbox tools (45 registered)
  • scripts/sync-shared.sh + CI drift check keeps the shared driver/skill/engine copies honest
  • repo slug createos-claude-pluginscreateos-plugin throughout
  • versions: opencode 0.2.0, pi 0.3.0, codex 0.2.0

Bugs fixed

  • Codex plugin was uninstallable — Codex rejects scoped plugin names, so the documented install command could never have worked
  • Codex session hook emitted plain text; Codex parses hookSpecificOutput like Claude Code does, so it injected nothing
  • Codex skill had drifted 77 lines behind canonical
  • pullArtifacts reported success for a pull that never happened — GNU tar writes a valid empty archive for a missing path, and /bin/sh pipelines report only the last command's status, so the box holding the only copy of the output was destroyed
  • out is now validated before reaching a shell

Verified

  • engine e2e against live CreateOS: 14/14 (artifact pulled to host, box destruction confirmed via API, egress applied, retention on failed pull)
  • all four harnesses smoke-tested in fresh sandboxes: claude-code 8/8, codex 14/14, opencode 13/14, pi 9/9
  • lint clean, typecheck clean, 18 engine + 21 pi tests pass, no shared-file drift

Not included

  • docs updates live in website-04 (7 pages, incl. the broken Codex install path)
  • symlinks for the shared files are not viable: the Codex installer copies regular files only, so a symlinked repo installs with no driver and no skill, silently

The repository is now NodeOps-app/createos-plugin; these install paths
still named createos-claude-plugins, which resolved only through GitHub's
rename redirect.
The TypeScript plugins drove `createos sandbox create/exec/rm` directly,
which looks like an offload and is not: it drops egress restriction, the
keepalive that survives a dropped stream on a long build, guaranteed
auto-destroy, and the staging excludes that keep a large .git off the wire.

sandbox-engine.ts ports those semantics from scripts/cos so both plugins
can share one implementation. Egress selection and box retention are pure
functions because they are the two decisions that fail silently: an
unrestricted box works perfectly, and a box destroyed after a failed
artifact pull takes the only copy of the output with it.
Adds sandbox_offload, sandbox_fanout, sandbox_desktop, sandbox_computer
and sandbox_screenshot over the shared engine, taking the plugin from 33
to 38 tools.

The compaction context now carries the verb rule as well, so "work with a
finish line goes to sandbox_offload" survives a compact instead of the
agent falling back to create plus exec.
Adds sandbox_offload plus a compact desktop surface — sandbox_desktop,
sandbox_computer and sandbox_screenshot — matching the OpenCode plugin,
taking the extension from 34 to 38 sandbox tools (45 registered).
The Codex plugin shipped a skill that taught raw `createos` CLI verbs and
a session hook that printed plain text. Three things were wrong with it:

- The plugin could not be installed at all. Codex rejects scoped names
  ("only ASCII letters, digits, . _ and -"), so @createos/codex was
  refused; it is now createos-sandbox-codex.
- The hook injected nothing. Codex parses hookSpecificOutput the same way
  Claude Code does, so plain stdout was discarded and the agent never
  learned the driver path.
- Its skill had drifted 77 lines behind the canonical one.

It now ships the same cos driver and skill as the Claude Code plugin, with
session-start and pre-tool-use hooks. scripts/sync-shared.sh copies the
shared files and CI fails on drift; symlinks are not an option because the
Codex installer copies regular files only, so a symlinked repo installs
with no driver and no skill at all.
pullArtifacts interpolates `out` into a remote shell command unquoted, so
that globs like dist/* keep working — the same trade scripts/cos makes.

The local shell was never exposed: the whole remote script is a single
quoted argv element. And the caller that supplies `out` also supplies
`command`, which is arbitrary remote code by design, so injection through
`out` granted nothing that was not already on offer.

Guarding it anyway. It costs one regex, it keeps a future caller that
pins `command` but forwards `out` from handing over the box's shell, and
it turns a path containing a space into a clear error rather than a
baffling tar failure. Paths that would escape /work are refused too.
Codex resolves plugin manifests from .codex-plugin/plugin.json first, then
falls back to .claude-plugin/plugin.json and .cursor-plugin/plugin.json, so
the plugin was living in Claude Code's namespace on that fallback.

The marketplace entry stays in .claude-plugin/marketplace.json because that
is the only marketplace path the Codex binary knows — there is no
.codex-plugin/marketplace.json. Removing the entry makes
`codex plugin add createos-sandbox-codex` fail outright.
@pratikbin
pratikbin merged commit bb975bf into main Sep 11, 2026
2 checks passed
@pratikbin
pratikbin deleted the feat/sync-harness-plugins branch September 11, 2026 06:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant