fix(ai-cli): install current upstream Codex and Claude releases
- Pin official Codex 0.161.0 and Claude Code 2.1.292 binaries - Preserve Codex helpers and Claude's NixOS compatibility wrapper - Add an updater for stable upstream versions and checksums - Document CLI updates independently of stable NixOS inputs
This commit is contained in:
1 parent
2759278aff
commit
0aac36b7de
6 files changed
+155
-5
No files matched your search
@@ -104,9 +104,28 @@ Studio remains on the ThinkPads as an existing IDE/workflow choice, but its
|
||||
bundled SDK is worth reviewing if moving fully to project-local tooling.
|
||||
|
||||
Codex CLI (`codex`) and Claude Code (`claude`) are installed on every host.
|
||||
Run each command as your normal user and follow its sign-in flow. Update these
|
||||
Nix-managed packages through the flake and rebuild rather than their standalone
|
||||
installers. Authentication stays in your home directory, outside this repo.
|
||||
Run each command as your normal user and follow its sign-in flow.
|
||||
They use official upstream binaries, with versions and SHA-256 checksums pinned
|
||||
in `packages/ai-cli-versions.json`, independently of the stable NixOS release.
|
||||
`packages/ai-cli.nix` packages Codex and reuses Nixpkgs' Claude Code wrapper.
|
||||
Authentication stays in your home directory, outside this repo.
|
||||
|
||||
To update both to the latest stable upstream releases, run from this repo:
|
||||
|
||||
```sh
|
||||
nix shell nixpkgs#python3 -c python3 scripts/update-ai-cli.py
|
||||
git diff -- packages/ai-cli-versions.json
|
||||
nix build .#codex .#claude-code --no-link
|
||||
sudo nixos-rebuild switch --flake .#framework
|
||||
codex --version
|
||||
claude --version
|
||||
git add packages/ai-cli-versions.json
|
||||
git commit -m "chore(ai-cli): update upstream releases"
|
||||
```
|
||||
|
||||
Use your own host name when rebuilding. The updater changes only the CLI pins;
|
||||
`nix flake update` updates NixOS inputs but does not update these pins.
|
||||
Updates remain explicit and reproducible; no upstream self-updaters are used.
|
||||
|
||||
The official ChatGPT Linux desktop preview does not formally support NixOS.
|
||||
Our pinned `chatgpt` package supports macOS only, so it is not installed here.
|
||||
|
||||
@@ -19,6 +19,14 @@
|
||||
...
|
||||
}:
|
||||
{
|
||||
# Build the CLI packages separately before switching a host.
|
||||
packages.x86_64-linux = import ./packages/ai-cli.nix {
|
||||
pkgs = import nixpkgs {
|
||||
system = "x86_64-linux";
|
||||
config.allowUnfree = true;
|
||||
};
|
||||
};
|
||||
|
||||
nixosConfigurations = {
|
||||
t450s = nixpkgs.lib.nixosSystem {
|
||||
specialArgs.unstable = import nixpkgs-unstable {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
aiCli = import ../packages/ai-cli.nix { inherit pkgs; };
|
||||
in
|
||||
{
|
||||
# Workstation tools only; language runtimes and SDKs belong in projects.
|
||||
environment.systemPackages = with pkgs; [
|
||||
@@ -19,8 +22,8 @@
|
||||
zip
|
||||
|
||||
# Coding assistants; authenticate separately as your normal user.
|
||||
codex
|
||||
claude-code
|
||||
aiCli.codex
|
||||
aiCli.claude-code
|
||||
|
||||
# Infrastructure, containers, and structured data.
|
||||
ansible
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"codex": {
|
||||
"version": "0.161.0",
|
||||
"sha256": "04d8ab9dbcb9df0edf3c67dca5072a374babfdf762a9bc4ae649ae140b8e2cf0"
|
||||
},
|
||||
"claude-code": {
|
||||
"version": "2.1.292",
|
||||
"sha256": "a967e7b1d8b4e47ee421d5433027880347952b0c0857abf880e2c942a4ec93b3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
{ pkgs }:
|
||||
let
|
||||
versions = builtins.fromJSON (builtins.readFile ./ai-cli-versions.json);
|
||||
in
|
||||
{
|
||||
# Use the complete official package, including Code Mode and voice helpers.
|
||||
codex = pkgs.stdenvNoCC.mkDerivation {
|
||||
pname = "codex";
|
||||
inherit (versions.codex) version;
|
||||
src = pkgs.fetchurl {
|
||||
url = "https://github.com/openai/codex/releases/download/rust-v${versions.codex.version}/codex-package-x86_64-unknown-linux-musl.tar.gz";
|
||||
inherit (versions.codex) sha256;
|
||||
};
|
||||
sourceRoot = ".";
|
||||
nativeBuildInputs = [ pkgs.autoPatchelfHook pkgs.makeWrapper ];
|
||||
buildInputs = [ pkgs.glibc pkgs.ncurses ];
|
||||
dontBuild = true;
|
||||
dontStrip = true;
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p "$out"
|
||||
cp -r bin codex-path codex-resources codex-package.json "$out/"
|
||||
runHook postInstall
|
||||
'';
|
||||
postFixup = ''
|
||||
wrapProgram "$out/bin/codex" \
|
||||
--prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.ripgrep pkgs.bubblewrap ]}
|
||||
'';
|
||||
doInstallCheck = true;
|
||||
installCheckPhase = ''
|
||||
runHook preInstallCheck
|
||||
"$out/bin/codex" --version | grep -F "codex-cli ${versions.codex.version}"
|
||||
runHook postInstallCheck
|
||||
'';
|
||||
meta = {
|
||||
description = "OpenAI coding agent, official upstream binary package";
|
||||
homepage = "https://github.com/openai/codex";
|
||||
license = pkgs.lib.licenses.asl20;
|
||||
mainProgram = "codex";
|
||||
platforms = [ "x86_64-linux" ];
|
||||
sourceProvenance = [ pkgs.lib.sourceTypes.binaryNativeCode ];
|
||||
};
|
||||
};
|
||||
|
||||
# Keep Nixpkgs' NixOS compatibility fixes and sandbox dependencies.
|
||||
claude-code = pkgs.claude-code.override {
|
||||
manifest = {
|
||||
inherit (versions.claude-code) version;
|
||||
platforms.linux-x64.checksum = versions.claude-code.sha256;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Pin the latest stable upstream CLI releases without updating NixOS."""
|
||||
|
||||
import json
|
||||
import re
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def fetch_json(url):
|
||||
request = urllib.request.Request(
|
||||
url, headers={"User-Agent": "nixos-config-ai-cli-updater"}
|
||||
)
|
||||
with urllib.request.urlopen(request, timeout=60) as response:
|
||||
return json.load(response)
|
||||
|
||||
|
||||
def latest_release(repository):
|
||||
release = fetch_json(f"https://api.github.com/repos/{repository}/releases/latest")
|
||||
if release["prerelease"] or release["draft"]:
|
||||
raise ValueError(f"Expected a stable release from {repository}")
|
||||
return release
|
||||
|
||||
|
||||
codex = latest_release("openai/codex")
|
||||
codex_version = codex["tag_name"].removeprefix("rust-v")
|
||||
claude = latest_release("anthropics/claude-code")
|
||||
claude_version = claude["tag_name"].removeprefix("v")
|
||||
for version in (codex_version, claude_version):
|
||||
if not re.fullmatch(r"\d+\.\d+\.\d+", version):
|
||||
raise ValueError(f"Unexpected release version: {version}")
|
||||
|
||||
asset = next(
|
||||
item for item in codex["assets"]
|
||||
if item["name"] == "codex-package-x86_64-unknown-linux-musl.tar.gz"
|
||||
)
|
||||
digest = asset["digest"]
|
||||
if not re.fullmatch(r"sha256:[0-9a-f]{64}", digest):
|
||||
raise ValueError("Codex release asset has no valid SHA-256 digest")
|
||||
|
||||
manifest = fetch_json(
|
||||
f"https://downloads.claude.ai/claude-code-releases/{claude_version}/manifest.json"
|
||||
)
|
||||
if manifest["version"] != claude_version:
|
||||
raise ValueError("Claude release and download manifest versions differ")
|
||||
claude_hash = manifest["platforms"]["linux-x64"]["checksum"]
|
||||
if not re.fullmatch(r"[0-9a-f]{64}", claude_hash):
|
||||
raise ValueError("Claude manifest has no valid SHA-256 checksum")
|
||||
|
||||
versions = {
|
||||
"codex": {"version": codex_version, "sha256": digest.removeprefix("sha256:")},
|
||||
"claude-code": {"version": claude_version, "sha256": claude_hash},
|
||||
}
|
||||
destination = Path(__file__).resolve().parent.parent / "packages" / "ai-cli-versions.json"
|
||||
destination.write_text(json.dumps(versions, indent=2) + "\n")
|
||||
print(f"Pinned Codex {codex_version} and Claude Code {claude_version}.")
|
||||
print("Review the diff, build the packages, rebuild your host and commit the pins.")
|
||||
Reference in new issue
Block a user