Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
5014240
feat(runtime): build isolated workspace and closed bundles (U1)
nathanvale Aug 8, 2026
dd04981
fix(review): close U1 review findings
nathanvale Aug 8, 2026
2c25ad3
feat(runtime): add runtime-exec custody engine with verified shared c…
nathanvale Aug 8, 2026
1e62309
feat(runtime): add custody skill, honest skill status, and U2 proof o…
nathanvale Aug 8, 2026
c18def8
refactor(build): share shell-projection helpers across renderers
nathanvale Aug 8, 2026
649d35b
fix(review): close U2 custody-engine review findings
nathanvale Aug 8, 2026
457a649
fix(review): close PR #22 custody-engine review findings
nathanvale Aug 8, 2026
7027a0e
feat(runtime): activate Bun-only plugin payload (U3)
nathanvale Aug 8, 2026
7526beb
feat(runtime): qualify single Bun candidate (U4)
nathanvale Aug 8, 2026
4519bfa
fix(runtime): harden Bun custody qualification
nathanvale Aug 8, 2026
4cd3967
fix(review): close remaining Bun custody findings
nathanvale Aug 8, 2026
9b726d1
fix(proof): validate runtime control envelopes
nathanvale Aug 8, 2026
99dd9b7
fix(review): close Codex runtime findings
nathanvale Aug 8, 2026
b21ea49
fix(build): enforce admitted dependency graph
nathanvale Aug 8, 2026
6ae9e37
fix(build): resolve workspace lock entries
nathanvale Aug 8, 2026
36acd0e
fix(runtime): close loader and repair escapes
nathanvale Aug 8, 2026
2009fe7
fix(proof): enforce offline runtime execution
nathanvale Aug 8, 2026
4a47ff6
fix(proof): preserve isolated runner environment
nathanvale Aug 8, 2026
a49eaa8
fix(build): contain bare asset loads
nathanvale Aug 8, 2026
2cbb4c7
fix(runtime): close peer and lock failure paths
nathanvale Aug 8, 2026
50e80a5
fix(build): resolve workspace peer ranges
nathanvale Aug 8, 2026
a814e56
fix(runtime): clean up failed staged chmod
nathanvale Aug 8, 2026
92a50fc
fix(runtime): diagnose noexec cache failures
nathanvale Aug 8, 2026
d1bed8f
fix(runtime): preserve cleanup failure envelopes
nathanvale Aug 8, 2026
3501129
fix(runtime): report unreadable lock records
nathanvale Aug 8, 2026
4e3c890
fix(runtime): close corrupt recovery cleanup paths
nathanvale Aug 8, 2026
5f97910
fix(runtime): approve migrated cache recovery
nathanvale Aug 8, 2026
78c958d
fix(build): admit package import aliases
nathanvale Aug 8, 2026
4d12747
fix(runtime): harden stale lock reclamation
nathanvale Aug 8, 2026
e6b4095
fix(build): close dependency admission gaps
nathanvale Aug 8, 2026
13817ae
fix(build): bind alias and peer resolution
nathanvale Aug 8, 2026
64104f8
fix(runtime): bind closed execution claims
nathanvale Aug 8, 2026
cf17a30
fix(build): reject runtime code generation
nathanvale Aug 8, 2026
6a61d10
fix(build): make loader validation token-aware
nathanvale Aug 8, 2026
1289adf
docs(runtime): clarify bundle trust boundary
nathanvale Aug 8, 2026
bd986aa
fix(build): close loader token edge cases
nathanvale Aug 8, 2026
feae154
fix(runtime): reject symlinked repair locks
nathanvale Aug 8, 2026
0ce0895
fix(build): admit only known runtime modules
nathanvale Aug 8, 2026
7baee40
fix(build): distinguish loader call sites
nathanvale Aug 8, 2026
f65baef
fix(build): close indirect loader escapes
nathanvale Aug 8, 2026
e88b499
fix(build): reject optional ambient calls
nathanvale Aug 8, 2026
d426649
fix(build): reject computed ambient references
nathanvale Aug 8, 2026
6e247ce
fix(build): preserve contextual of operands
nathanvale Aug 8, 2026
c057bd0
fix(runtime): recover stale reclaim markers
nathanvale Aug 8, 2026
e9f3f2d
fix(runtime): bind reclaim markers to owners
nathanvale Aug 8, 2026
b0d25ac
fix(runtime): revalidate stale marker identity
nathanvale Aug 8, 2026
bcb3aad
fix: fail closed without writer identity
nathanvale Aug 8, 2026
2c4c815
fix: close remaining custody races
nathanvale Aug 8, 2026
6042e55
fix: preserve uncertain runtime owners
nathanvale Aug 8, 2026
4dd2680
fix: distinguish loader method declarations
nathanvale Aug 8, 2026
d97f3f3
fix: reject computed ambient destructuring
nathanvale Aug 8, 2026
65a83aa
fix: balance loader method parameters
nathanvale Aug 8, 2026
f758529
fix: reject nested ambient destructuring
nathanvale Aug 8, 2026
8a7867f
fix: close ambient loader aliases
nathanvale Aug 8, 2026
f3e3fd9
fix: distinguish declaration regex contexts
nathanvale Aug 8, 2026
1847b7f
fix: recognize statement block regex contexts
nathanvale Aug 8, 2026
ffd35da
fix: recognize labeled statement blocks
nathanvale Aug 8, 2026
2f0c950
fix(review): close two bundle-admission scanner bypasses
nathanvale Aug 8, 2026
1dda026
fix(review): close runtime builtin escapes
nathanvale Aug 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"plugins": [
{
"name": "harness-native-plugin-prototype",
"description": "Prove native plugin distribution with a Bun-authored portable runtime",
"description": "Dependency-closed skills using a verified, plugin-managed Bun runtime",
"author": {
"name": "Prototype"
},
Expand Down
4 changes: 1 addition & 3 deletions .github/release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@
{ "type": "json", "path": "plugin.config.json", "jsonpath": "$.version" },
{ "type": "json", "path": ".claude-plugin/marketplace.json", "jsonpath": "$.metadata.version" },
{ "type": "json", "path": "plugin/.claude-plugin/plugin.json", "jsonpath": "$.version" },
{ "type": "json", "path": "plugin/.codex-plugin/plugin.json", "jsonpath": "$.version" },
{ "type": "generic", "path": "plugin/hooks/codex/hooks.json" },
{ "type": "generic", "path": "plugin/runtime/hello-world.js" }
{ "type": "json", "path": "plugin/.codex-plugin/plugin.json", "jsonpath": "$.version" }
]
}
}
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/plugin-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
with:
bun-version: 1.3.14
- run: bun run spike:quickjs:ci
- run: bun run prove:runtime-custody

package:
name: Deterministic package
Expand All @@ -55,8 +55,8 @@ jobs:
- run: bun run release:validate
- run: bun run prove:distribution
- run: bun run prove:dx
- name: Prove generated runtime was merged with its source
run: git diff --exit-code -- plugin/runtime/hello-world.js
- name: Prove generated payload was merged with its sources
run: git diff --exit-code -- plugin/
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: agent-plugin-${{ github.sha }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ jobs:
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
with:
bun-version: 1.3.14
- run: bun run spike:quickjs:ci
- run: bun run prove:runtime-custody
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

package:
name: Prove release candidate
Expand All @@ -374,7 +374,7 @@ jobs:
bun run prove:all
bun run prove:distribution
- name: Reject generated release-surface drift
run: git diff --exit-code -- plugin/runtime/hello-world.js plugin/hooks/codex/hooks.json
run: git diff --exit-code -- plugin/
- name: Bind checksum metadata to candidate
env:
CANDIDATE_SHA: ${{ needs.resolve.outputs.candidate_sha }}
Expand Down
59 changes: 30 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
Build one Git-distributed plugin for Claude Code and Codex.

- Share skills and portable runtime behavior.
- Keep native manifests, hooks, trust, and reload behavior separate.
- Keep native manifests and reload behavior separate.
- Author in Bun and TypeScript.
- Execute offline through bundled QuickJS runtimes.
- Execute dependency-closed bundles through one verified, plugin-managed Bun runtime.
- Publish from GitHub Releases, not npm.
- Develop through each harness's native plugin workflow.

Consumers need Claude Code or Codex and Git access to the repository. They do not need Bun, Node.js, Python, npm, or a post-install download.
Consumers need Claude Code or Codex and Git access to the repository. They do not need a user-managed Bun, Node.js, Python, npm, or a setup command. The first use with a missing runtime requires one approved repair; warm use works offline.

The operator verification recipes also use a POSIX shell, `jq`, `awk`, and `diff`.

Expand Down Expand Up @@ -170,7 +170,7 @@ diff -qr "$PREFLIGHT_ROOT/repository/plugin" "$INSTALLED_PATH"
jq -e '.installed[] | select(.pluginId == "PLUGIN_NAME@PLUGIN_NAME" and .version == "X.Y.Z")' "$PREFLIGHT_ROOT/codex-plugins-after-add.json"
```

Start an isolated inspection task with `codex -C "$PREFLIGHT_ROOT"`. Keep hooks skipped while they are untrusted. Open `/hooks`, compare the exact definitions and installed executable closure with the preflight checkout, then accept trust only for that definition. Plugin enablement and hook trust are separate states. Start a second fresh task after trust review and repeat the version and byte checks.
Start an isolated task with `codex -C "$PREFLIGHT_ROOT"` and invoke one installed skill. A missing runtime returns `BUN_MISSING` without mutation. The agent previews the verified repair, asks for approval in plain language, runs `runtime/runtime-exec repair --apply` only after approval, and retries the skill. No lifecycle hook or manual setup command is involved.

The replacement recipe below preserves the marketplace source, ref, and prior `enabled` state. Remove the pinned marketplace entry only after target and restoration preflights pass.

Expand Down Expand Up @@ -246,7 +246,7 @@ codex plugin list --json > "$PREFLIGHT_ROOT/codex-plugins-restored.json"

Verify the restored source, ref, version, cache bytes, and enabled state. Codex CLI currently has no documented plugin enable/disable subcommand; restore a differing enabled state in the Codex plugin settings and confirm it with `codex plugin list --json` before continuing.

For the target install, start an isolated task with hooks skipped, review `/hooks`, restore the prior enabled state, then start a second fresh task. A version, hook command, launcher, runtime, or QuickJS executable change invalidates prior hook trust and requires another review.
For the target install, start a fresh isolated task, confirm skill discovery, and exercise the missing-runtime repair/retry journey when the reviewed Bun identity changed. A new Bun version plus executable digest requires fresh approval; archive-only metadata changes do not change the approved runtime identity.

`codex plugin marketplace upgrade PLUGIN_NAME` is the documented explicit CLI operation for refreshing the configured Git snapshot. A pinned immutable tag should resolve to the same bytes. Automatic Codex marketplace refresh is unspecified; never rely on it to move or restore a release.

Expand Down Expand Up @@ -290,55 +290,55 @@ Codex plugins are cached rather than loaded directly from the checkout. The comm

After an edit, rerun the command and start a fresh task. This is reinstall-and-restart, not hot reload.

Do not symlink or sync only `skills/` into harness-global directories. That bypasses the manifests, hooks, runtime assets, cache identity, and installation boundary being tested.
Do not symlink or sync only `skills/` into harness-global directories. That bypasses the manifests, launchers, runtime custody, cache identity, and installation boundary being tested.

## Add plugin behavior

Keep portable command logic under `runtime/src/`. Keep the QuickJS I/O adapter small. Add harness behavior through the native manifest or hook file for that Harness.
Keep portable command logic under `runtime/src/`. Add dependency-bearing skills as isolated workspace members, then register them in the one logical skill catalog and regenerate the closed bundles and launchers.

```text
plugin/
├── .claude-plugin/plugin.json
├── .codex-plugin/plugin.json
├── skills/hello-world/SKILL.md
├── hooks/
│ ├── claude/hooks.json
│ └── codex/hooks.json
├── bin/hello-world
├── QUICKJS-LICENSE
├── skills/{hello-world,runtime-custody,skill-a,skill-b}/SKILL.md
├── bin/{hello-world,skill-a,skill-b}
├── THIRD-PARTY-NOTICES.md
└── runtime/
├── runtime-exec
├── runtime-lock.sh
├── skill-catalog.sh
├── bundle-inventory.{json,sh}
├── hello-world.js
├── quickjs-assets.json
└── qjs-{darwin,linux}-{arm64,x86_64}
└── skill-{a,b}-<digest>.js
```

Both marketplace catalogs point at `./plugin`. Development staging, Git installation, packaging, and distribution proof all start from that subtree. Repository scripts, TypeScript source, Git metadata, and development state cannot enter the installed payload.

The portable process seam is:

```text
arguments + complete stdin + invocation identity
skill id + arguments + invocation identity
-> stdout + stderr + exit code
```

| Area | Shared | Claude Code | Codex |
| --- | --- | --- | --- |
| Skills | Portable Agent Skills content | `/PLUGIN:SKILL` invocation and Claude extensions | `$SKILL` invocation and Codex extensions |
| Runtime | Generated JavaScript, launcher, and QuickJS assets | Executes the shared launcher | Executes the shared launcher |
| Runtime | Closed bundles, generated launchers, and one Bun custody engine | Executes the shared launcher | Executes the shared launcher |
| Manifest | Plugin identity only | Claude-native manifest | Codex-native manifest |
| Hooks | Command implementation only | Claude-native declarations, matching, and handlers | Codex-native declarations, matching, and trust |
| Lifecycle hooks | None | None | None |
| Development refresh | Source and payload | Direct checkout plus `/reload-plugins` | Staged reinstall plus a fresh task |
| Harness-only features | Nothing by default | Keep Claude-only components native | Keep Codex-only components native |

Use [CONTEXT.md](CONTEXT.md) for canonical language. The architecture rationale lives in the ADRs for [one payload with native adapters](docs/adr/0001-one-payload-native-harness-adapters.md) and [Bun-authored QuickJS execution](docs/adr/0002-bun-authoring-quickjs-runtime.md).
Use [CONTEXT.md](CONTEXT.md) for canonical language. The architecture rationale lives in the ADRs for [one payload with native adapters](docs/adr/0001-one-payload-native-harness-adapters.md), [shared runtime custody](docs/adr/0005-shared-runtime-custody.md), [one Bun runtime](docs/adr/0006-single-bun-runtime-tier.md), and [closed workspace bundles](docs/adr/0007-workspace-authoring-bundled-distribution.md).

## Pull requests and CI

Use a Conventional Commit PR title. The title becomes the normal PR's squash commit and drives release notes:

```text
feat: add a portable command
fix(claude): correct hook matching
fix(runtime): correct custody routing
docs: clarify private installation
```

Expand All @@ -355,7 +355,7 @@ bun run release:validate
bun run prove:all
```

Hosted CI runs QuickJS natively on Linux x64, Linux arm64, macOS arm64, and macOS x64. It then creates the deterministic archive and `*.checksums.json`. The checksums JSON contains `repository`, `sourceCommit`, `tag`, `plugin`, `version`, `archive`, `archiveBytes`, `archiveSha256`, and an `evidence` note. It is integrity evidence for the named archive bytes, not independent publisher or builder authenticity. Public `main` artifacts receive GitHub artifact attestation. User-owned private repositories retain the checksums JSON and skip the unsupported attestation job.
Hosted CI builds one candidate, then on Linux x64, Linux arm64, macOS arm64, and macOS x64 acquires the locked Bun asset through `repair --apply` into isolated state, runs a packaged skill, and proves warm reuse with custody network denied. It then creates the deterministic archive and `*.checksums.json`. The checksums bind the source commit, archive, runtime lock, bundle inventory, and payload inventory. They are integrity evidence for the named bytes, not independent publisher or builder authenticity. Public `main` artifacts receive GitHub artifact attestation. User-owned private repositories retain the checksums JSON and skip the unsupported attestation job.

### Optional Codex review gate

Expand Down Expand Up @@ -484,11 +484,11 @@ Release machinery is based on [Release Please](https://github.com/googleapis/rel

- `bun test`: initializer, metadata, CLI, release, development, and canary contracts.
- `bun run generate:check`: generated manifests match `plugin.config.json`.
- `bun run build`: regenerate portable JavaScript.
- `bun run spike:quickjs`: compare Bun and QuickJS behavior on the current platform.
- `bun run prove:distribution`: build twice, compare bytes, extract offline, verify interpreter digests, and run both harness command contracts.
- `bun run build`: regenerate the Bun hello-world bundle, workspace bundles, notices, and inventory.
- `bun run prove:runtime-custody`: exercise missing, repair, corruption, concurrency, hostile-environment, and pass-through behavior.
- `bun run prove:runtime-platform -- --target <target>`: acquire the reviewed target asset, execute the packaged skill, and prove warm offline reuse.
- `bun run prove:distribution`: build twice, compare package bytes, extract the payload, prove Bun-only closure, and verify cold read-only guidance.
- `bun run prove:dx`: verify canonical marketplace paths and native development boundaries.
- `bun run prove:quickjs-ci`: reproduce runtime, distribution, matrix, pinning, and attestation CI checks.
- `bun run prove:all`: complete local gate.

## Public and private canaries
Expand All @@ -513,9 +513,10 @@ These canaries prove this repository's Git publishing transport and native Git-m
## Current boundaries

- macOS arm64/x64 and Linux arm64/x64 only.
- QuickJS NG `0.16.1` is checksum-pinned in the payload.
- A future dependency on `Bun.*`, `node:*`, native addons, or unsupported Web APIs requires a fresh runtime decision and compatibility proof.
- Bun is pinned by version and per-target archive/executable digests; users do not install or pin it themselves.
- Publisher-reviewed bundles and dependencies execute with the user's normal Bun and OS capabilities. This is not a sandbox or an untrusted-plugin runtime.
- Native addons, computed dynamic imports, undeclared assets, and runtime package installation are rejected from the closed bundle contract.
- Claude reloads a direct development plugin in the existing session. Codex needs a staged reinstall and fresh task.
- Hook declarations stay physically separate. A shared default `hooks/hooks.json` previously caused cross-harness auto-discovery.
- Runtime lifecycle hooks, prewarm, doctor, inventory, and prune commands are intentionally absent.
- Managed, workspace-installed, or non-removable plugins require administrator replacement or rollback.
- Vendor plugin specifications change. Recheck the linked official documentation when manifests, hooks, trust, or reload behavior changes.
- Vendor plugin specifications change. Recheck the linked official documentation when manifests, discovery, installation, or reload behavior changes.
36 changes: 36 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions bunfig.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Dependency custody: pnpm-style isolated linking rejects phantom dependencies,
# and lifecycle scripts never run because no dependency is trusted.
# CI-facing installs stay frozen via `bun install --frozen-lockfile` in
# scripts/build.ts; the lockfile is bun.lock, pinned with packageManager.
[install]
linker = "isolated"
ignoreScripts = true
6 changes: 6 additions & 0 deletions docs/adr/0002-bun-authoring-quickjs-runtime.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# Author with Bun and execute with bundled QuickJS

## Status

Superseded by ADR 0006 on 2026-08-06. This file preserves the original spike
rationale only; no active payload, launcher, proof, or release workflow uses
QuickJS.

Contributors use Bun and TypeScript, while each Plugin Payload includes generated standards-oriented JavaScript and checksum-pinned QuickJS executables for consumer execution. This avoids npm, post-install downloads, and requiring a contributor runtime on recipient machines; it also keeps the four-target release far smaller than bundling Bun into every executable. Dependencies on Bun, Node.js, native addons, or unsupported Web APIs reopen this decision and require compatibility proof.
Loading