Skip to content
Merged
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
30 changes: 30 additions & 0 deletions .github/workflows/host-acceptance-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Host acceptance release gate

on:
workflow_dispatch:
inputs:
version:
description: Release version without the v prefix (for example, 0.17.2)
required: true
type: string

permissions:
contents: read

jobs:
verify:
runs-on: ubuntu-latest
defaults:
run:
working-directory: plugins/vibespec/skills/vibespec
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: 22
- name: Verify Claude and Codex acceptance evidence
env:
RELEASE_VERSION: ${{ inputs.version }}
run: node scripts/check-host-acceptance.mjs --version "$RELEASE_VERSION"
1 change: 1 addition & 0 deletions README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ VibeSpec은 제품 구현 코드를 생성하거나 배포하지 않습니다.
- [라이브 데모](docs/live-demos.md)
- [아키텍처와 데이터 경계](docs/architecture.md)
- [개발 및 테스트](docs/development.md)
- [릴리스 수용 검증](docs/releasing.md)
- [기여 안내](CONTRIBUTING.md) · [보안](SECURITY.md)

## 라이선스
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ VibeSpec does not generate or deploy the product's implementation code. It produ
- [Live demos](docs/live-demos.md)
- [Architecture and data boundaries](docs/architecture.md)
- [Development and testing](docs/development.md)
- [Release acceptance](docs/releasing.md)
- [Contributing](CONTRIBUTING.md) · [Security](SECURITY.md)

## License
Expand Down
17 changes: 17 additions & 0 deletions acceptance/hosts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Real-host acceptance evidence

Each released VibeSpec version must include portable acceptance evidence from:

- at least one Claude-family host: `claude-code` or `cowork`; and
- at least one Codex-family host: `codex-cli` or `codex-desktop`.

Store records under `acceptance/hosts/vX.Y.Z/`. Generate them with the verifier shipped in the installed plugin. Do not hand-edit records and do not commit raw logs, product artifacts, prompts, absolute paths, usernames, or task-folder names.

The release gate validates the exact plugin version and runtime-bundle digest, then requires both host families:

```text
cd plugins/vibespec/skills/vibespec
npm run check:host-acceptance
```

See [Releasing VibeSpec](../../docs/releasing.md) for the real-host procedure.
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
- **Explore every live example:** [Live demos](live-demos.md)
- **Understand the SOT and plugin architecture:** [Architecture](architecture.md)
- **Build and test the repository:** [Development](development.md)
- **Run the release gates:** [Releasing VibeSpec](releasing.md)
- **Generate consumer app plans:** [Consumer app generation profile](reference/consumer-app-generation-profile.md)
2 changes: 2 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ npm run package:plugin
- `npm run check:all` adds the Chrome or Edge browser-flow suite.
- `npm run package:plugin` writes the minimal runtime bundle to `.dist/vibespec`.

Real Claude/Codex sessions are not launched by normal CI. Before tagging a release, generate the two required portable host records and run `npm run check:host-acceptance`. Follow [Releasing VibeSpec](releasing.md) for the full procedure.

## Validate plans and trees

Validate a generated or edited SOT:
Expand Down
4 changes: 2 additions & 2 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ In the ChatGPT desktop app, open **Codex -> Plugins**, choose the `vibespec` mar

Open a new task on a writable folder. Select **VibeSpec** in Cowork, invoke `/vibespec:vibespec` in Claude Code, or invoke `$vibespec` in Codex. Then request: "Create a compact meeting-room booking plan and save both `outputs/meeting-room.sot.json` and `outputs/meeting-room.html`." In reduced mode, VibeSpec may provide only the JSON and includes the unchanged viewer only when the host can access the installed viewer asset.

The loaded skill owns discovery of its installed path and runs doctor/preflight before it uses repository scripts. Do not guess or hard-code `<VibeSpec-skill-dir>`. For optional host acceptance after the host or loaded skill reports that path, run:
The loaded skill owns discovery of its installed path and runs doctor/preflight before it uses repository scripts. Do not guess or hard-code `<VibeSpec-skill-dir>`. For host acceptance after the host or loaded skill reports that path, run:

```text
node <VibeSpec-skill-dir>/scripts/doctor.mjs <task-folder> --json
Expand All @@ -62,7 +62,7 @@ Full-mode acceptance requires doctor/preflight to pass, both output files to exi
node <VibeSpec-skill-dir>/scripts/verify-host-output.mjs outputs/meeting-room.sot.json outputs/meeting-room.html --host <claude-code|cowork|codex-cli|codex-desktop> --record host-acceptance/<host>.json
```

The verifier checks that the host-created JSON is structurally valid and exactly matches the SOT embedded in the HTML. Repository CI cannot launch desktop hosts, so a release is described as host-accepted only after this check has run on that host. If VibeSpec is unavailable in a new task, reopen the task after installation or restart the desktop app.
The verifier checks that the host-created JSON is structurally valid and exactly matches the SOT embedded in the HTML. It writes a portable record with artifact hashes instead of local paths. Repository CI cannot launch desktop hosts, so each release requires one Claude-family and one Codex-family record produced by real full-mode sessions. Maintainers should follow [Releasing VibeSpec](releasing.md). If VibeSpec is unavailable in a new task, reopen the task after installation or restart the desktop app.

## Manual invocation

Expand Down
66 changes: 66 additions & 0 deletions docs/releasing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Releasing VibeSpec

## Required gates

A release candidate is ready to tag only after:

1. `npm run check:all` passes from `plugins/vibespec/skills/vibespec`.
2. A fresh full-mode installation succeeds on at least one Claude-family host.
3. A fresh full-mode installation succeeds on at least one Codex-family host.
4. Both portable records match the exact plugin version and `npm run check:host-acceptance` passes.
5. The **Host acceptance release gate** GitHub Actions workflow passes for that version.

Claude-family hosts are `claude-code` and `cowork`. Codex-family hosts are `codex-cli` and `codex-desktop`. Reduced-mode Cowork output does not satisfy the release gate because it cannot prove validated embedded HTML.

## Release sequence

1. Merge the release candidate and version bump to `main`, but do not create the tag yet.
2. Install that `main` candidate in fresh Claude and Codex sessions and generate independent artifacts.
3. Commit only the two portable evidence records. Do not change plugin runtime files after acceptance.
4. Run the local gate and the manual GitHub Actions gate.
5. Tag and publish the exact evidence commit.

If any runtime-bundle file changes after acceptance, its digest changes and the gate rejects the old records. Repeat both real-host checks before tagging.

## Canonical acceptance task

Use a new writable task folder and a fresh task or session for each host. Install or update the release candidate, invoke VibeSpec explicitly, and request:

> Create a compact meeting-room booking plan and save both `outputs/meeting-room.sot.json` and `outputs/meeting-room.html`.

The host must load the installed skill, run its doctor/preflight, and create both files. Do not reuse artifacts created by another host.

## Generate portable evidence

After the host reports its installed VibeSpec skill directory, run the verifier from that installed plugin:

```text
node <VibeSpec-skill-dir>/scripts/verify-host-output.mjs outputs/meeting-room.sot.json outputs/meeting-room.html --host <host> --record host-acceptance/<host>.json
```

The verifier proves that the SOT is structurally valid and exactly matches the SOT embedded in the HTML. Its record contains the installed runtime-bundle digest plus artifact basenames and SHA-256 hashes; it excludes local paths and raw task content. The bundle digest prevents evidence from being reused after runtime files change without a version bump.

Copy the generated record into the source repository without editing it:

```text
acceptance/hosts/vX.Y.Z/<host>.json
```

Repeat in the other host family. Multiple records are allowed, but at least one accepted record per family is required.

## Run the release gate

Confirm that the package and both plugin manifests already carry the intended version. Then run:

```text
cd plugins/vibespec/skills/vibespec
npm run check:host-acceptance
```

The command fails when evidence is missing, malformed, from another plugin version, or contains fields outside the portable contract.

Push the records and run **Actions -> Host acceptance release gate -> Run workflow** with the same `X.Y.Z` version. This workflow validates committed evidence; it does not launch Claude or Codex.

## Privacy and audit boundary

Commit only the generated portable JSON records. Keep raw host logs and generated product artifacts private unless they are intentionally published as release assets. Never add workstation paths, credentials, personal prompts, or customer plans to acceptance evidence.
32 changes: 32 additions & 0 deletions docs/superpowers/plans/2026-08-10-host-acceptance-release-gate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Host Acceptance Release Gate Implementation Plan

**Goal:** Require portable Claude-family and Codex-family real-host evidence before a VibeSpec release.

**Architecture:** Extend the existing installed verifier to emit privacy-safe, versioned evidence. Add a repository-aware gate that validates a version directory and connect it to tests, documentation, package scripts, and a manual release-readiness workflow.

## Task 1: Evidence contract and verifier

- Add shared host/family and evidence validation helpers.
- Write failing tests for hashes, version metadata, and path privacy.
- Update `verify-host-output.mjs` to emit the portable contract.
- Keep JSON/HTML equivalence and structural validation unchanged.

## Task 2: Release gate

- Write failing tests for missing families, mismatched versions, malformed evidence, and a valid pair.
- Add `check-host-acceptance.mjs` with library and CLI entry points.
- Add an npm script that checks `acceptance/hosts/v<package-version>/` by default.

## Task 3: Documentation and workflow

- Add the committed evidence directory contract and a non-sensitive example policy.
- Update first-install and development/release documentation.
- Add a manually triggered GitHub Actions workflow with a version input.
- Ensure repository path audits accept portable records and reject workstation paths.

## Task 4: Verification and publication

- Run focused host acceptance tests.
- Run `npm run check:all`.
- Review the diff for private paths and generated artifacts.
- Commit and push the feature branch.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Host Acceptance Release Gate Design

**Date:** 2026-08-10
**Status:** Approved

## Goal

Make real-host acceptance a release contract instead of an informal checklist. Every release must carry portable evidence from at least one Claude-family host and one Codex-family host.

## Acceptance policy

- Claude family: `claude-code` or `cowork`.
- Codex family: `codex-cli` or `codex-desktop`.
- A release is host-accepted only when one full-mode record from each family passes.
- Evidence must match the exact plugin version being released.
- Reduced-mode output cannot satisfy the release gate because it cannot prove validated embedded HTML.
- CI validates evidence; it does not claim to launch desktop hosts.

## Evidence layout

Committed evidence lives under:

```text
acceptance/hosts/vX.Y.Z/<host>.json
```

Each record contains only portable facts:

- evidence contract version
- plugin version and deterministic runtime-bundle SHA-256
- host and host family
- acceptance result and timestamp
- artifact basenames and SHA-256 digests
- SOT title and schema version

Absolute paths, usernames, task folders, prompts, and raw host logs are excluded. Raw artifacts may remain private or be attached separately to a GitHub Release.

## Tooling

`verify-host-output.mjs` remains the command run after a real host creates JSON and HTML. It will emit the portable record directly and derive the plugin version from the installed package.

A new `check-host-acceptance.mjs` command will:

1. Read the expected release version.
2. Load all JSON records from `acceptance/hosts/vX.Y.Z/`.
3. Reject malformed records, unknown hosts, absolute paths, failed records, version mismatches, and runtime-bundle digest mismatches.
4. Require at least one Claude-family and one Codex-family record.
5. Print a concise release-readiness summary.

## CI and release boundary

Normal pull-request CI must test the evidence contract and verifier without requiring current release evidence. A separate release-readiness command is the hard gate used immediately before tagging or publishing. This avoids making every development commit depend on manually produced host evidence while preventing a release from being described as accepted without it.

The repository will provide a manually triggered GitHub Actions workflow that validates the committed evidence for the requested version. The workflow verifies records only; the real host sessions must already have been run.

## Failure behavior

- Missing either family: fail.
- Record version differs from requested version: fail.
- Record contains a local absolute path: fail.
- Artifact hash or required metadata missing: fail.
- Duplicate records are allowed when all are valid; one passing record per family is sufficient.
- Unknown extra fields are rejected so the evidence contract cannot drift silently.

## Verification

Tests cover portable evidence generation, artifact mismatch rejection, privacy rejection, version mismatch, missing host family, valid two-family acceptance, and the actual release-readiness CLI exit code.
2 changes: 1 addition & 1 deletion plugins/vibespec/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vibespec",
"version": "0.17.1",
"version": "0.17.2",
"description": "VibeSpec is a free, open-source AI product-planning plugin for Claude and Codex. It turns product ideas into editable SOTs with PRDs, feature specs, IA, user flows, and semantic assurance for KPI evidence. VibeSpec은 Claude와 Codex용 무료 오픈소스 AI 제품 기획 플러그인입니다. 공식 사이트: https://vbspec.com/.",
"author": { "name": "chjoel0621" },
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion plugins/vibespec/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vibespec",
"version": "0.17.1",
"version": "0.17.2",
"description": "VibeSpec is a free, open-source AI product-planning plugin for Claude and Codex. It turns product ideas into editable SOTs with PRDs, feature specs, IA, user flows, and semantic assurance for KPI evidence. Official site: https://vbspec.com/.",
"author": {
"name": "chjoel0621",
Expand Down
18 changes: 2 additions & 16 deletions plugins/vibespec/skills/vibespec/package-plugin.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,11 @@
import { cpSync, existsSync, mkdirSync, rmSync } from "node:fs";
import { basename, dirname, join, parse, resolve } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { runtimeBundleEntries } from "./scripts/lib/runtime-bundle.mjs";

const skillRoot = dirname(fileURLToPath(import.meta.url));
const pluginRoot = resolve(skillRoot, "..", "..");

const entries = [
[".claude-plugin/plugin.json"],
[".codex-plugin/plugin.json"],
["LICENSE"],
["README.md"],
["skills/vibespec/SKILL.md"],
["skills/vibespec/agents"],
["skills/vibespec/assets/viewer.html"],
["skills/vibespec/references"],
["skills/vibespec/scripts"],
["skills/vibespec/src/js/00-config.js"],
["skills/vibespec/src/js/05-c14n.js"],
["skills/vibespec/src/js/20-state.js"]
];

function safeOutput(path) {
const output = resolve(path);
const root = parse(output).root;
Expand All @@ -35,7 +21,7 @@ export function packagePlugin(outputPath = join(skillRoot, ".dist", "vibespec"))
const output = safeOutput(outputPath);
if (existsSync(output)) rmSync(output, { recursive: true, force: true });
mkdirSync(output, { recursive: true });
for (const [relative] of entries) {
for (const relative of runtimeBundleEntries) {
const source = join(pluginRoot, relative);
if (!existsSync(source)) throw new Error(`missing runtime bundle entry ${source}`);
const destination = join(output, relative);
Expand Down
7 changes: 4 additions & 3 deletions plugins/vibespec/skills/vibespec/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "vibespec-viewer",
"private": true,
"version": "0.17.1",
"version": "0.17.2",
"description": "Modular source for the VibeSpec viewer. Build inlines src/ into a single self-contained assets/viewer.html.",
"type": "module",
"scripts": {
Expand All @@ -21,10 +21,11 @@
"migrate": "node scripts/migrate-sot.mjs",
"inspect": "node scripts/inspect.mjs",
"doctor": "node scripts/doctor.mjs",
"check:host-acceptance": "node scripts/check-host-acceptance.mjs",
"package:plugin": "node package-plugin.mjs",
"test": "node tests/run-tests.mjs && node tests/tree.test.mjs && node tests/rebase.test.mjs && node tests/product-map.test.mjs && node tests/workspace.test.mjs && node tests/change-plan.test.mjs && node tests/sot-query.test.mjs && node tests/content-review.test.mjs && node tests/semantic-review.test.mjs && node ../../../../evaluation/semantic-assurance/evaluate.mjs && node tests/migration.test.mjs && node tests/inspect.test.mjs && node tests/merge.test.mjs && node tests/embed-sot.test.mjs && node tests/demo-tree.test.mjs && node tests/host-smoke.mjs && node tests/host-runtime.test.mjs && node tests/package-plugin.test.mjs && node tests/installed-plugin-smoke.mjs",
"test": "node tests/run-tests.mjs && node tests/tree.test.mjs && node tests/rebase.test.mjs && node tests/product-map.test.mjs && node tests/workspace.test.mjs && node tests/change-plan.test.mjs && node tests/sot-query.test.mjs && node tests/content-review.test.mjs && node tests/semantic-review.test.mjs && node ../../../../evaluation/semantic-assurance/evaluate.mjs && node tests/migration.test.mjs && node tests/inspect.test.mjs && node tests/merge.test.mjs && node tests/embed-sot.test.mjs && node tests/demo-tree.test.mjs && node tests/host-smoke.mjs && node tests/host-runtime.test.mjs && node tests/host-acceptance.test.mjs && node tests/package-plugin.test.mjs && node tests/installed-plugin-smoke.mjs",
"test:browser": "npm run check:browser",
"check": "node build.mjs && node --check .build/app.js && node tests/run-tests.mjs && node tests/tree.test.mjs && node tests/rebase.test.mjs && node tests/product-map.test.mjs && node tests/workspace.test.mjs && node tests/change-plan.test.mjs && node tests/sot-query.test.mjs && node tests/content-review.test.mjs && node tests/semantic-review.test.mjs && node ../../../../evaluation/semantic-assurance/evaluate.mjs && node tests/migration.test.mjs && node tests/inspect.test.mjs && node tests/merge.test.mjs && node tests/embed-sot.test.mjs && node tests/demo-tree.test.mjs && node tests/plugin-contract.mjs && node tests/host-smoke.mjs && node tests/host-runtime.test.mjs && node tests/package-plugin.test.mjs && node tests/installed-plugin-smoke.mjs",
"check": "node build.mjs && node --check .build/app.js && node tests/run-tests.mjs && node tests/tree.test.mjs && node tests/rebase.test.mjs && node tests/product-map.test.mjs && node tests/workspace.test.mjs && node tests/change-plan.test.mjs && node tests/sot-query.test.mjs && node tests/content-review.test.mjs && node tests/semantic-review.test.mjs && node ../../../../evaluation/semantic-assurance/evaluate.mjs && node tests/migration.test.mjs && node tests/inspect.test.mjs && node tests/merge.test.mjs && node tests/embed-sot.test.mjs && node tests/demo-tree.test.mjs && node tests/plugin-contract.mjs && node tests/host-smoke.mjs && node tests/host-runtime.test.mjs && node tests/host-acceptance.test.mjs && node tests/package-plugin.test.mjs && node tests/installed-plugin-smoke.mjs",
"check:browser": "node tests/browser-flow.mjs && node tests/browser-ia.mjs && node tests/browser-catalog.mjs && node tests/browser-initiative.mjs && node tests/browser-map.mjs && node tests/browser-semantic.mjs && node tests/browser-file-connection.mjs",
"check:repo": "node --test ../../../../tools/tests/path-leak.test.mjs ../../../../tools/tests/markdown-links.test.mjs ../../../../tools/tests/marketing-runtime.test.mjs && node ../../../../tools/check-path-leaks.mjs ../../../.. && node ../../../../tools/check-doc-links.mjs ../../../..",
"check:all": "npm run check:repo && npm run check && npm run check:browser"
Expand Down
Loading