Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
b18b148
[claude/vc-workflow] fix(voc): loopback product default, sane aicx PA…
div0-space Aug 18, 2026
bcbfc77
[claude/vc-workflow] style: settle formatter output after the review-…
div0-space Aug 18, 2026
cf20aa4
[claude/interactive] docs(roadmap): backlog for the next scaffold
div0-space Aug 18, 2026
833f770
[claude/vc-scaffold] docs(roadmap): scaffold 4.2.0 and correct the 4.…
div0-space Aug 18, 2026
63e5e8d
[claude/vc-scaffold] docs(roadmap): rescope W1-a after pre-flight
div0-space Aug 18, 2026
69101f2
[claude/vc-scaffold] docs(roadmap): align stop points with vc-operato…
div0-space Aug 18, 2026
838165d
[claude/vc-implement] fix(install): make the docs shim runnable on a …
div0-space Aug 18, 2026
cd13e1c
[claude/vc-implement] feat(release): snapshot dirty donors instead of…
div0-space Aug 18, 2026
e9f47da
[claude/vc-implement] test(install): guard the two install.ps1 copies…
div0-space Aug 18, 2026
01e5e18
[claude/vc-implement] refactor(core): import siblings by module path,…
div0-space Aug 18, 2026
4918c7f
[claude/vc-implement] fix(core): keep the barrel self-cycle fix past …
div0-space Aug 18, 2026
df9b633
[claude/vc-implement] docs(roadmap): record what the implement stage …
div0-space Aug 18, 2026
85cebab
[claude/vc-workflow] fix(release): refuse payloads that name the buil…
div0-space Aug 18, 2026
f08e807
[claude/vc-workflow] test: make four blind gates capable of failing
div0-space Aug 18, 2026
1f6d36c
[claude/vc-workflow] chore(release): one rm -rf guard, host-wide clea…
div0-space Aug 18, 2026
e934845
[grok/vc-workflow] feat(autonomy): treat non-destructive remote push …
div0-space Aug 18, 2026
25fe62b
[claude/vc-marbles] fix(runtime): bound worker silence, unbreak the p…
div0-space Aug 18, 2026
289cff1
[claude/vc-polarize] fix(workspace): accept every canonical UUID, min…
div0-space Aug 18, 2026
fabf0e2
[claude/vc-polarize] fix(doctor): judge an installed owner by where i…
div0-space Aug 18, 2026
0e26b07
[claude/vc-workflow] feat(init): carry resume as an automatic payload…
div0-space Aug 18, 2026
48b3d9a
[claude/vc-ship] docs(roadmap): drop the build-host path so the paylo…
div0-space Aug 18, 2026
8e872b1
[claude/vc-polarize] fix(dashboard): resolve workspace identity the w…
div0-space Aug 18, 2026
b8d0443
[claude/vc-hydrate] docs(release): stop the payload contradicting its…
div0-space Aug 18, 2026
6f8f961
[claude/vc-release] fix(release): let the tag gate run on the runner …
div0-space Aug 18, 2026
dd12427
[claude/vc-implement] fix(spawn): publish every meta.json write atomi…
div0-space Aug 18, 2026
60d9986
[claude/vc-frame] chore(config): sync vc-frame twin scripts — drop th…
div0-space Aug 18, 2026
48d78b4
[claude/vc-frame] fix(theme): ivory alternate ribbon shade is a bone …
div0-space Aug 18, 2026
bdb832b
[claude/vc-implement] fix(install): keep launcher identity across the…
div0-space Aug 18, 2026
e827dfa
[claude/interactive] fix(installer): treat killpg EPERM as alive duri…
div0-space Aug 19, 2026
870fb9b
[claude/vc-release] ci(core): run the core suite on macos-15 for pull…
div0-space Aug 19, 2026
d4c67f3
[claude/interactive] feat(config): one config home — view collapses t…
div0-space Aug 20, 2026
54aa393
[claude/interactive] fix(doctor): judge the single view shape, not pe…
div0-space Aug 20, 2026
89b439a
[claude/interactive] fix(frontier): pinners resolve one home — view s…
div0-space Aug 20, 2026
0913255
[claude/interactive] fix(app): frame config follows package truth on …
div0-space Aug 20, 2026
b568a66
[codex/headless] fix(canary): enforce language catalog contracts
div0-space Aug 20, 2026
094a831
[claude/interactive] fix(canary): fleet substrate, brief contract, fe…
div0-space Aug 20, 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
37 changes: 37 additions & 0 deletions .github/workflows/core-macos.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# The release source gate (release.yml) runs `make test-core` on macos-15 —
# but only on a tag push. Measured 2026-08-19 on v4.1.0 @ 27ad70e2: the
# repaired runner reached the core suite for the first time in five weeks and
# found 5 failures the operator host never shows (3x terminal runtime, a
# KeyError: 'env' in the cell launcher, the resume-pack red). Nothing before
# the tag had ever put the suite on a bare macOS image. This workflow closes
# that loop: the same suite, the same runner, on every pull request and on
# demand — so a tag is a confirmation, not an experiment.
name: Core runtime tests (macOS)

on:
pull_request:
paths:
- "vibecrafted-core/**"
- "Makefile"
- ".github/workflows/core-macos.yml"
workflow_dispatch:

permissions:
contents: read

jobs:
core-macos:
runs-on: macos-15
timeout-minutes: 30
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false

- name: Install uv
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6

# Exactly what release.yml's source-gate runs, so a green check here
# predicts the tag gate instead of the tag discovering the suite.
- name: Run core runtime tests
run: make test-core
13 changes: 11 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,25 @@ jobs:
- name: Build the portable release channel
run: make portable

# POSIX grep, not ripgrep: this job runs on the bare GitHub macos-15
# image, which ships neither ripgrep nor shellcheck — the latter is
# why the `brew install shellcheck` step above exists. The earlier
# spelling forced a lookup of a real rg binary on PATH, so this step
# would have failed the whole gate after every test had already
# passed: the exact shape of the v4.0.0 xcrun death, four steps
# later. It arrived in ef700e52 (3.7.1) and every tag since died
# earlier, so it has never once executed. These are literal presence
# assertions over enumerated files, which is what grep is for.
- name: Confirm publication boundary for both channels
run: |
set -euo pipefail
test -x scripts/publish-vibecrafted-release.sh
test -x scripts/build-portable-release.sh
command rg -n 'Vibecrafted_.*YYYYMMDD|DMG_NAME|\.dmg\.sha256' \
grep -nE 'Vibecrafted_.*YYYYMMDD|DMG_NAME|\.dmg\.sha256' \
scripts/build-vibecrafted-release.sh \
scripts/publish-vibecrafted-release.sh \
docs/RELEASE_KICKOFF.md
command rg -n 'PORTABLE_NAME|portable\.tar\.gz|portable-output\.json' \
grep -nE 'PORTABLE_NAME|portable\.tar\.gz|portable-output\.json' \
scripts/build-portable-release.sh \
scripts/publish-vibecrafted-release.sh \
docs/RELEASE_KICKOFF.md
90 changes: 90 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,32 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).

## Unreleased

> **4.2.0 scope — measured truths, finished seams.** Release integrity from the
> donor snapshot through to the payload a stranger downloads, and one identity
> order shared by every surface that reads a run.

### Added

- `vibecrafted init` carries unfinished work into every session. Each pass
projects this checkout's needs-attention settlement bucket, classifies every
run, and prints the exact command that continues it — newest first, with the
truncated remainder counted out loud. Silent on a clean checkout; an
unreadable ledger degrades to an honest `UNKNOWN` rather than bricking init.
Guardian-owned runs are listed without a command, because each holds a single
automatic attempt that a hand resume would burn.
- `--snapshot-donors` on `scripts/build-vibecrafted-release.sh` builds a release
from a detached worktree at each donor's `HEAD`, so a dirty donor no longer
blocks a cut and never leaves a ghost worktree registration behind. A reaper
folded into the release cleanup trap removes and prunes them.
- `--silence-timeout` on the dispatcher, and a supervisor bound on worker
**stdout silence** rather than wall-clock time. A worker that is slow but
talking is untouched; one blocked in `wait4` now settles through the existing
stall handler, which records `stall_kind=silence|wall_clock` so triage never
has to guess which bound fired.
- `make payload-hygiene` refuses any release payload that names the build host,
reporting the topmost still-host-specific ancestor instead of only the exact
checkout string.

### Changed

- Bare `vibecrafted resume <agent>` (and `--root`) opens a new interactive
Expand All @@ -13,6 +39,70 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).
- Resume pack assembler lives in `aicx_session_chain` (CLI transport + MCP
session-chain contract). Catalog rows are evidence, not a Tinder picker.
Empty-with-`-p` is `empty_project`, not a silent scanned=0.
- `vibecrafted doctor` judges an installed owner by **where it lands**, not by
what its path is called. Ownership is containment in
`$VIBECRAFTED_RUNTIME_HOME`, resolved directly or through a wrapper's `exec`
target. A new cross-check compares the reported install identity against the
`VERSION` of the root the launcher actually enters, and warns — naming both —
when they disagree, instead of reporting `ok` for a generation nothing runs.
- `workspace_id` mints UUIDv7 and accepts **any** canonical UUID. The wire
contract previously read as a validation rule; a reader that enforced it would
have dropped this repository's own v4 workspace entry from its dashboard.
Chronology comes from `created_at`, never from the id bits.
- The vc-frame default server is the canonical product origin `127.0.0.1:3024`
instead of a tailnet address compiled into the shipped binary. `VC_SERVER_URL`
and `--server` still route to any remote; that is now an operator choice
rather than a build-time one.
- `vibecrafted_core` imports siblings by module path instead of through the
package barrel. Runtime behaviour and lazy exports are unchanged; the importer
graph now names the module that owns each symbol — measured 0 breaking /
0 structural / 0 diamond cycles, repository health 74 to 80.
- Non-destructive branch push is a duty, not a stop. Force, trunk, delete, and
tag pushes remain the only git-push hard stops, and Mode B worktree workers
stay off remotes entirely.

### Fixed

- The delivery proof kernel could not run its own verification subject. The
executor scrubs the environment to `_SAFE_ENV_KEYS` — correctly dropping
`PYTHONPATH` — while the subject was declared as a `-m` module invocation
resolved through the `sys.path` that scrub had just removed. It died with
`ModuleNotFoundError`, the kernel wrote `proof.failed`, and **every run it
judged settled `failed` regardless of the worker's real outcome.** The package
location is now a contract-declared argument instead of ambient state.
- The supervisor heartbeat pulsed identically at 20 seconds and at 3 hours, so a
worker blocked in `wait4` held the supervisor open forever and the finished
`RunState.STALLED` handler was unreachable in production.
- The live dashboard resolved its workspace identity from the repository root
alone, while the runtime stamps runs from the exported
`VIBECRAFTED_WORKSPACE_ID` first. Two implementations of one question, free to
disagree — and a dispatched worker in a worktree, whose root can never equal
its dispatcher's, was structurally invisible to the LIVE RUNS filter.
- `docs/install.sh` exec'd `../install.sh` directly, but that file carries no
executable bit by design, so the shim died with exit 126 on every fresh clone.
It now execs `bash` explicitly, matching the packer contract.
- Chained keychain traps under `set -e`: `_ks_trap_cleanup` returns the
triggering status on purpose, and that non-zero return tore the shell down
before the caller's chained handler ran. Measured on a real failed release
that skipped its own reaper and left two worktree registrations behind.
- Four gates that guarded something real while being structurally unable to see
it break are now capable of failing — including the keychain regression suite,
which ran every child without `set -e`, the exact condition its target bug
requires.

### Security

- Signed artifacts no longer carry the operator's disk layout. `runtime_receipt`
dropped two hardcoded build-host absolutes (duplicates where they resolved,
dead entries shipping a private path everywhere else), Rust test-module
fixtures that the packer's `tests/` directory exclusion could not see were
neutralised, and the payload-hygiene gate now fails the build rather than the
reviewer. Measured on the 4.1.0 portable tarball: 5 offenders naming the
checkout, 12 naming the workshop one level above it.
- `install.ps1` is guarded byte-for-byte against the site repository's served
copy, so the two cannot drift apart unnoticed.
- `aicx` runs with a sanitized `PATH` (absolute, non-empty entries, system
fallback), so an implicit-cwd lookup can never pick up a stray binary.

## 4.1.0 — 2026-08-16

Expand Down
41 changes: 36 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ CARGO_BUILD_ROOT ?= $(INSTALLER_CACHE_HOME)/vibecrafted/build/$(INSTALLER_HOST_T
# in-tree cache is never read or written by install lanes.
export PYTHONPYCACHEPREFIX ?= $(INSTALLER_CACHE_HOME)/vibecrafted/pycache-$(INSTALLER_HOST_TAG)

.PHONY: help help-dev vibecrafted app dmg dmg-signed release-local notarize release portable publish-release gui-install wizard wizard-dev check test test-core test-skills test-install test-parity test-vc-frame test-iterm2-migrate test-memex test-aicx-sync test-hammerspoon test-keychain-session dispatch-test unified-product-contract-gate install install-auto install-all install-python-tools install-bundle-tools install-tools install-tools-held install-vendored-binaries install-app-binaries install-hammerspoon skills helpers setup-dev dry-run doctor list update uninstall restore migrate migrate-dry init-hooks seed-commit-msg-hooks bundle bundle-check foundations foundations-check semgrep version version-show version-bump bump-patch bump-minor bump-major iterm-plugin iterm-plugin-refresh iterm-plugin-show iterm-plugin-uninstall iterm-plugin-migrate demo demo-full commit-safe test-race-protection skill-new server server-build build-server-release server-check server-test install-server install-server-payload install-server-service server-smoke
.PHONY: help help-dev vibecrafted app dmg dmg-signed release-local notarize release portable publish-release gui-install wizard wizard-dev check test test-core test-skills test-install test-parity test-vc-frame test-iterm2-migrate test-memex test-aicx-sync test-hammerspoon test-keychain-session dispatch-test unified-product-contract-gate payload-hygiene install install-auto install-all install-python-tools install-bundle-tools install-tools install-tools-held install-vendored-binaries install-app-binaries install-hammerspoon skills helpers setup-dev dry-run doctor list update uninstall restore migrate migrate-dry init-hooks seed-commit-msg-hooks bundle bundle-check foundations foundations-check semgrep version version-show version-bump bump-patch bump-minor bump-major iterm-plugin iterm-plugin-refresh iterm-plugin-show iterm-plugin-uninstall iterm-plugin-migrate demo demo-full commit-safe test-race-protection skill-new server server-build build-server-release server-check server-test install-server install-server-payload install-server-service server-smoke

help:
@printf "\n"
Expand Down Expand Up @@ -65,24 +65,55 @@ vibecrafted: install
RELEASE_SCRIPT := scripts/build-vibecrafted-release.sh
PORTABLE_SCRIPT := scripts/build-portable-release.sh
KEYS ?= $(HOME)/.keys
# Extra builder flags, e.g. RELEASE_FLAGS=--snapshot-donors to build from
# detached worktrees at each donor HEAD instead of refusing a dirty donor.
# RELEASE_FLAGS reaches the builder as ARGV WORDS, never as shell text. Make
# expands its own variables into the recipe before zsh parses it, so the earlier
# spelling — $(RELEASE_FLAGS) spliced straight into the single-quoted `zsh -ic`
# argument — handed the value to zsh as source.
#
# MEASURED 2026-08-18, and the vector is narrower than it looks: a `;` in the
# value lands AFTER `exec`, so it never runs. Command substitution does, because
# zsh evaluates $(...) and backticks while building the exec's argv:
# RELEASE_FLAGS='--snapshot-donors $(touch /tmp/proof)' -> /tmp/proof exists
# Through the environment and split with zsh's ${=...} the same value arrives as
# four inert argv words and nothing is evaluated.
RELEASE_FLAGS ?=

app:
@zsh -ic 'cd "$(CURDIR)" && KEYS="$(KEYS)" exec bash "$(RELEASE_SCRIPT)" --app-only'
@VC_RELEASE_FLAGS='$(RELEASE_FLAGS)' zsh -ic 'cd "$(CURDIR)" && KEYS="$(KEYS)" exec bash "$(RELEASE_SCRIPT)" --app-only $${=VC_RELEASE_FLAGS}'

dmg dmg-signed release-local:
@zsh -ic 'cd "$(CURDIR)" && KEYS="$(KEYS)" exec bash "$(RELEASE_SCRIPT)" --no-notarize'
@VC_RELEASE_FLAGS='$(RELEASE_FLAGS)' zsh -ic 'cd "$(CURDIR)" && KEYS="$(KEYS)" exec bash "$(RELEASE_SCRIPT)" --no-notarize $${=VC_RELEASE_FLAGS}'

notarize:
@zsh -ic 'cd "$(CURDIR)" && KEYS="$(KEYS)" exec bash "$(RELEASE_SCRIPT)" --notarize-only'
@VC_RELEASE_FLAGS='$(RELEASE_FLAGS)' zsh -ic 'cd "$(CURDIR)" && KEYS="$(KEYS)" exec bash "$(RELEASE_SCRIPT)" --notarize-only $${=VC_RELEASE_FLAGS}'

release:
@zsh -ic 'cd "$(CURDIR)" && KEYS="$(KEYS)" exec bash "$(RELEASE_SCRIPT)"'
@VC_RELEASE_FLAGS='$(RELEASE_FLAGS)' zsh -ic 'cd "$(CURDIR)" && KEYS="$(KEYS)" exec bash "$(RELEASE_SCRIPT)" $${=VC_RELEASE_FLAGS}'

# The portable channel needs no signing identity and no notary account: it is a
# provenance-bound source distribution, so it builds anywhere git and python3 do.
portable:
@bash "$(PORTABLE_SCRIPT)"

# Ask an artifact that ALREADY EXISTS whether it names the build host. Both
# release scripts run this gate before they sign or publish, but a release is
# expensive and the artifacts from before the gate existed are still on disk —
# so the same question has to be answerable without a rebuild.
#
# make payload-hygiene ARTIFACT=dist/Vibecrafted.app
# make payload-hygiene ARTIFACT=dist/Vibecrafted_4.1.0-20260817-237d2814.dmg
#
# A .dmg is mounted read-only and detached again; nothing is written anywhere.
PAYLOAD_HYGIENE_SCRIPT := scripts/payload-hygiene-artifact.sh
ARTIFACT ?=
payload-hygiene:
@test -n "$(ARTIFACT)" || { \
printf 'usage: make payload-hygiene ARTIFACT=<path to .app, .dmg or directory>\n' >&2; \
exit 2; }
@bash "$(PAYLOAD_HYGIENE_SCRIPT)" "$(ARTIFACT)"

publish-release:
@zsh -ic 'cd "$(CURDIR)" && exec bash scripts/publish-vibecrafted-release.sh'

Expand Down
Loading
Loading