Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ jobs:
npm audit --json > release-evidence/audit.json
npm audit signatures > release-evidence/signatures.txt
node scripts/release-integrity.ts licenses package-lock.json docs/license-dispositions.json > release-evidence/licenses.json
node scripts/opencode-host-matrix.ts --pack-json release-evidence/pack.json --output release-evidence/opencode-host-matrix.json
sha256sum release-evidence/* opencode-artifacts-*.tgz
- uses: actions/upload-artifact@v4
with:
Expand Down
32 changes: 30 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,23 @@ dependencies automatically at startup:
}
```

Install the bundled native skill explicitly after the plugin. Project scope is the safest
default and writes only `.opencode/skills/artifact-pages` in the current project:

```bash
npx opencode-artifacts skill install --project
# or, when you intentionally want it for every project:
npx opencode-artifacts skill install --global
```

The global destination is `~/.config/opencode/skills/artifact-pages`. Repeating an identical
install is a no-op. A differing destination is left unchanged; intentional replacement must
name it exactly, for example
`--force /absolute/project/.opencode/skills/artifact-pages`, and retains the prior directory as
a sibling backup. Remove an installed skill manually only after reviewing that exact directory.
If installation fails, fix the reported source, parent, symlink, or collision layer and rerun;
the installer never relies on a repository checkout or writes from package postinstall.

The `file:` spec is only for developing this plugin itself (point OpenCode at your checkout
after `npm install && npm run build`):

Expand Down Expand Up @@ -134,8 +151,8 @@ plugin option:

This injects the bundled guidance (adapted from Claude Code's artifact-design skill) into the
session's system context — visible in the plugin source, off by default, and removable by
deleting the option. Alternative for non-plugin environments: `cp -r skills/artifact-pages
~/.agents/skills/` (don't use both).
deleting the option. Native on-demand discovery from the explicit skill installer is separate;
do not enable proactive injection merely to make the skill discoverable.

Comment triage at scale: `agents/artifact-comment-analyst.md` is a read-only subagent that
digests open comment threads into an actionable brief (blocking issues first, with the page's
Expand Down Expand Up @@ -163,6 +180,17 @@ opencode-artifacts export <id> --output ./bundle
opencode-artifacts import ./bundle
```

Stable OpenCode also injects `/artifact-reopen <exact-reference>`, backed by
`artifact_lifecycle` with `op: "reopen"`. It accepts an exact active ID, slug, contained path,
or registered URL and never guesses. If a user already owns that command name, the plugin
leaves it unchanged; `opencode-artifacts latest --open` remains the portable fallback.

Publish and lifecycle tools return the stable host's structured result shape. Human/model text
is in `output`; `metadata.artifactResult` is a bounded schema-versioned identity, revision,
path/URL, capability, visibility, outcome, and next-action envelope. Existing operation and
argument spellings remain accepted, and prior readable text/JSON stays in `output` through at
least the next supported release after this metadata contract was introduced.

## Authoring format

Full reference: [`docs/component-spec.md`](docs/component-spec.md). Short version:
Expand Down
110 changes: 110 additions & 0 deletions docs/evidence/opencode-host-verification.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,113 @@ migration exception: old Workers continue using the historical shared `ARTIFACTS
namespace, while the next release creates a worker-scoped namespace and does not
automatically copy mutable decisions, comments, or mini-DB documents. See
[`docs/hosted-cloudflare.md`](../hosted-cloudflare.md).

## Exact packed stable-host matrix — 2026-08-18

Host: Ubuntu 24.04.4 LTS, Linux 6.8.0-137-generic x86_64. Node: 24.19.0.
OpenCode stable current/oldest-tested: exact 1.18.18. V2 beta was excluded. No model provider
or inference endpoint was called.

The final Goal 4 candidate was built and packed once, then installed from
`opencode-artifacts-0.15.0.tgz` into an empty dependency prefix with candidate lifecycle
scripts disabled. It contained 69 files, measured 123,449 bytes, and had SHA-256
`df778eafd2cd17b6f2674224af85767089024d326765f34c5e10bbb60307e091`.

The first attempted shortcut—placing the `.tgz` URL directly in the `plugin` array or passing
the tarball path directly to `opencode plugin`—was rejected as evidence. Stable OpenCode treats
the first as a module URL and resolves the second as the tarball's parent package directory;
it does not unpack that input. The successful candidate procedure therefore uses `npm install`
to unpack the exact tarball into an empty prefix, then passes the resulting package-directory
`file:` URL to the official plugin command. This is distinct from the checkout-based local
development route.

`scripts/opencode-host-matrix.ts` executed two clean routes with separate project and XDG
config/data/cache/state roots:

1. the official `opencode plugin file:///…/node_modules/opencode-artifacts` command, followed
by restart from the configuration it wrote; and
2. direct `plugin` array configuration of that same extracted exact package.

Both loopback servers returned `{"healthy":true,"version":"1.18.18"}` and exposed these
candidate tools through live discovery and full JSON-schema comparison:

```text
artifact_publish
artifact_lifecycle
artifact_db
artifact_state
artifact_comments
```

A direct execution of the packed plugin's `artifact_lifecycle list` returned schema version 1
with an empty artifact list and left the prepared manifest byte-for-byte unchanged. This
exercises safe shipped tool code without asking a provider model to select a tool. The matrix
recorded one deduplicated version cell because current stable and oldest-tested are identical;
it explicitly sets `broaderRangeProven: false`.

The local JSON result is `/tmp/goal4-finalpack/opencode-host-matrix.json`; CI generates the same
record as `release-evidence/opencode-host-matrix.json` and retains it with the exact tarball.
The `/tmp` path is transient and is not itself release evidence. Bare registry-coordinate
verification of future candidate bytes remains a post-publication gate; the dated published-
package probe above covers the already published route only.

### Stable permission policy probe

An additional isolated OpenCode 1.18.18 server loaded this inline policy without a plugin or
provider turn:

```json
{
"permission": {
"*": "allow",
"artifact_publish": "ask",
"artifact_datasource": "ask",
"artifact_deploy": "deny",
"artifact_audience": "deny"
}
}
```

`GET /config` returned those five entries unchanged. This proves the stable host accepts the
four independent resources and preserves explicit deploy/audience denies beneath broad auto
allow. It does not claim a provider-selected tool execution: doing that through the native
server requires a provider turn, which this gate deliberately excludes. The exact ask order,
denial at every transition, no-write/no-runner result, bounded metadata, and auto-deny property
are exercised by `test/plugin.test.ts`, `test/opencode-permissions.test.ts`, and the bounded
model in `test/model/opencode-permission-model.ts`. CI repeats the effective-config assertion
inside the packed config-array cell.

### Lifecycle result and reopen observation

Both packed routes advertised the prior lifecycle operations plus additive `reopen`. Effective
configuration contained `/artifact-reopen` with the exact-reference prompt template. The
packed direct `list` smoke returned the legacy-readable JSON text and left its fixture
unchanged; unit/contract tests bind the stable `{title, output, metadata}` result, schema-1
`metadata.artifactResult`, 16 KiB output cap, 8 KiB metadata cap, exact reopen selection, and
launch-failure refusal. Provider-free server discovery cannot select and execute a model tool,
so exact launcher behavior remains injected integration evidence rather than a claimed native
provider turn.

### Native skill install and load observation

The final harness executed the CLI shipped in the extracted tarball:

```text
opencode-artifacts skill install --project
```

It installed exactly these bytes into `.opencode/skills/artifact-pages`:

| File | Bytes | SHA-256 |
|---|---:|---|
| `SKILL.md` | 6,454 | `1f8a6377b312d4f7b3759d897e4901cdbc8c82aeb39c60e788913db3e961a117` |
| `reference/components.md` | 5,047 | `9096365cd1ca3d74fbd86c09051cbca083606839cc12a5431900237f5326df0a` |
| `reference/visuals.md` | 2,280 | `0228e8d7f496da912e9ba1102bcccb9a82584c1b1ae84f5a9d5734e4a8dd1b99` |

The harness then removed the entire installed candidate package tree and started a fresh stable
host with external compatibility skill roots disabled. Native `GET /skill` returned exactly
the project-installed `artifact-pages` location, its complete description, and 5,961-byte body
with SHA-256 `86dcbaa3b04513cdc08cb60f715419acf1147f7d52cfddc3759f81b7c77589af`.
This proves official-path advertisement and native body loading without a checkout, proactive
plugin injection, or provider inference. Reference files were independently readable and
hash-bound after source removal.
14 changes: 13 additions & 1 deletion docs/governance-policy.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"schemaVersion": 1,
"policyVersion": 1,
"reviewedAt": "2026-08-16",
"reviewedAt": "2026-08-18",
"owners": {
"security": "Security maintainer",
"privacy": "Privacy maintainer",
Expand Down Expand Up @@ -37,6 +37,18 @@
"testedAt": "2026-08-16",
"evidence": "docs/evidence/governance/ubuntu-packed-observation-2026-08-16.md"
},
{
"id": "packed-opencode-stable",
"class": "tested",
"status": "tested",
"os": "Ubuntu 24.04.4 LTS, Linux 6.8.0-137-generic, x86_64",
"node": "24.19.0",
"opencode": "current stable and oldest-tested 1.18.18 (one deduplicated exact cell)",
"browser": "not exercised; native host boundary only",
"scope": "Exact candidate tarball install, official CLI config mutation, direct config-array load, live health/tool schema discovery, and non-mutating packed lifecycle list without provider inference",
"testedAt": "2026-08-18",
"evidence": "docs/evidence/opencode-host-verification.md"
},
{
"id": "ubuntu-lts-desktop",
"class": "target",
Expand Down
12 changes: 8 additions & 4 deletions docs/support-policy.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Support and release policy

Policy version: 1. Last reviewed: 2026-08-16.
Policy version: 1. Last reviewed: 2026-08-18.

This document owns the Phase 0 D-01 platform decision and D-06 release/supply-chain decision.
The machine-readable status record is [`governance-policy.json`](governance-policy.json).
Expand Down Expand Up @@ -35,9 +35,13 @@ contains the exact OS, Node, OpenCode, browser/device, packed package digest, te
result. Failed evidence makes a cell unsupported; missing or stale evidence keeps it
unverified. Family resemblance and CI configuration do not promote a cell.

The initial current and oldest-supported OpenCode versions are the same exact stable 1.x
version once a complete cell passes. A second host version is not claimed until it receives
the same packed-host coverage. Re-run a cell when its OS/browser generation changes, the Node
The initial current and oldest-tested OpenCode versions are both exact `1.18.18`. On
2026-08-18, one deduplicated packed-host cell passed the official CLI configuration mutation,
direct config-array loading, live health/tool-schema discovery, and a non-mutating lifecycle
smoke under clean roots. This is host compatibility evidence, not a supported desktop/browser
claim. The peer SDK dependency is therefore exact `@opencode-ai/plugin@1.18.18`; no broader
1.x or V2 beta range is claimed. A second host version is not claimed until it receives the
same packed-host coverage. Re-run a cell when its OS/browser generation changes, the Node
or OpenCode support line changes, a relevant runtime/renderer dependency changes, or a defect
shows the evidence no longer represents users.

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

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

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@
"vega-lite": "^6.4.3"
},
"peerDependencies": {
"@opencode-ai/plugin": ">=1.0.0"
"@opencode-ai/plugin": "1.18.18"
},
"devDependencies": {
"@opencode-ai/plugin": "^1.0.0",
"@opencode-ai/plugin": "1.18.18",
"@types/markdown-it": "^14.1.2",
"@types/node": "^24.0.0",
"typescript": "^5.8.0"
Expand Down
Loading
Loading