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
1 change: 1 addition & 0 deletions .github/github.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"execution": "docs/exec.md",
"sandboxing": "docs/platform-sandboxing.md",
"tuiComposer": "docs/tui-chat-composer.md",
"updateManifest": "docs/update-manifest.md",
"rustWorkspace": "code-rs",
"upstreamMirror": "codex-rs"
},
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,20 @@ jobs:
set -euo pipefail
scripts/check-release-notes-version.sh

- name: Generate update manifest
if: steps.version.outputs.skip_push == 'true'
shell: bash
env:
NEW_VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail
scripts/release/generate-update-manifest.sh \
--version "$NEW_VERSION" \
--commit "$GITHUB_SHA" \
--repository "$GITHUB_REPOSITORY" \
--assets-dir release-assets \
--output release-assets/update-manifest.json

- name: Create GitHub Release
if: steps.version.outputs.skip_push == 'true'
uses: softprops/action-gh-release@v2
Expand Down
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Use these docs to install, configure, and operate Every Code (Code).
- [Auto Drive](auto-drive.md)
- [Agents & Subagents](agents.md)
- [Settings overlay](settings.md)
- [Update manifest](update-manifest.md)
- [Prompts](prompts.md)
- [Advanced usage](advanced.md)
- [Zed integration](integration-zed.md)
Expand Down
32 changes: 32 additions & 0 deletions docs/update-manifest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# GitHub Release Update Manifest

Every Code uses GitHub Releases as the canonical internal update source. Each
release attaches `update-manifest.json` next to the platform archives so the CLI
can discover and verify newer dogfood builds without npm or Homebrew.

The manifest is generated by `scripts/release/generate-update-manifest.sh` during
the `Release` workflow, immediately before the GitHub Release is published. The
workflow fails if any expected platform archive is missing.

## Schema

```json
{
"schema_version": 1,
"version": "v0.6.101",
"channel": "stable",
"commit": "<git sha>",
"published_at": "2026-05-24T18:00:00Z",
"platforms": {
"aarch64-apple-darwin": {
"asset": "code-aarch64-apple-darwin.tar.gz",
"url": "https://github.com/cbusillo/code/releases/download/v0.6.101/code-aarch64-apple-darwin.tar.gz",
"sha256": "<sha256>",
"size": 12345678
}
}
}
```

`stable` is the only release channel for now. Self-update logic should reject an
unknown `schema_version` and verify `sha256` before replacing any local binary.
153 changes: 153 additions & 0 deletions scripts/release/generate-update-manifest.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#!/usr/bin/env bash
set -euo pipefail

usage() {
cat >&2 <<'USAGE'
Usage: scripts/release/generate-update-manifest.sh \
--version VERSION \
--commit SHA \
--repository OWNER/REPO \
--assets-dir DIR \
--output FILE

Generates the GitHub Release update manifest used by internal dogfood builds.
USAGE
}

version=""
commit=""
repository=""
assets_dir=""
output=""
channel="stable"
published_at="${PUBLISHED_AT:-}"

while [[ $# -gt 0 ]]; do
case "$1" in
--version)
version="${2:-}"
shift 2
;;
--commit)
commit="${2:-}"
shift 2
;;
--repository)
repository="${2:-}"
shift 2
;;
--assets-dir)
assets_dir="${2:-}"
shift 2
;;
--output)
output="${2:-}"
shift 2
;;
--channel)
channel="${2:-}"
shift 2
;;
--published-at)
published_at="${2:-}"
shift 2
;;
-h | --help)
usage
exit 0
;;
*)
echo "unknown argument: $1" >&2
usage
exit 2
;;
esac
done

if [[ -z "$version" || -z "$commit" || -z "$repository" || -z "$assets_dir" || -z "$output" ]]; then
usage
exit 2
fi

if [[ ! -d "$assets_dir" ]]; then
echo "assets dir does not exist: $assets_dir" >&2
exit 1
fi

if [[ -z "$published_at" ]]; then
published_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
fi

tag="v${version#v}"
download_base="https://github.com/${repository}/releases/download/${tag}"

asset_for_target() {
local target="$1"
case "$target" in
x86_64-pc-windows-msvc)
printf '%s\n' "code-${target}.exe.zip"
;;
*)
printf '%s\n' "code-${target}.tar.gz"
;;
esac
}

tmp="$(mktemp)"
trap 'rm -f "$tmp"' EXIT

cat >"$tmp" <<JSON
{
"schema_version": 1,
"version": "$tag",
"channel": "$channel",
"commit": "$commit",
"published_at": "$published_at",
"platforms": {
JSON

targets=(
aarch64-apple-darwin
x86_64-apple-darwin
aarch64-unknown-linux-musl
x86_64-unknown-linux-musl
x86_64-pc-windows-msvc
)

first=true
for target in "${targets[@]}"; do
asset="$(asset_for_target "$target")"
path="$assets_dir/$asset"
if [[ ! -f "$path" ]]; then
echo "missing required release asset for $target: $asset" >&2
exit 1
fi
sha256="$(shasum -a 256 "$path" | awk '{print $1}')"
size="$(wc -c <"$path" | tr -d '[:space:]')"
url="${download_base}/${asset}"

if [[ "$first" == true ]]; then
first=false
else
printf ',\n' >>"$tmp"
fi

cat >>"$tmp" <<JSON
"$target": {
"asset": "$asset",
"url": "$url",
"sha256": "$sha256",
"size": $size
}
JSON
done

cat >>"$tmp" <<JSON

}
}
JSON

mkdir -p "$(dirname "$output")"
jq -e . "$tmp" >"$output"
echo "Wrote update manifest: $output" >&2