feat(codeaf): add CodeAF coding agent package
CI / check (push) Has been cancelled

CodeAF (Agent-Field/CodeAF) is a Go coding harness that ships one binary.
Pinned to v0.7.1; the flake's nixpkgs already carries go 1.26.7 and go.mod
asks for 1.26.5, so no extra nixpkgs input is needed.

Two things about this build are not obvious from the derivation:

- `make build` runs two host-side steps before compiling: `go generate
  ./internal/manual` packs the built-in manual into the pages.pack.gz and
  chat.pack.gz that the codeaf_packed_manual tag embeds, and
  internal/furrowbin/cmd/fetch stages the pinned Agent-Field/furrow release
  into internal/furrowbin/cache for go:embed. Both are run in preBuild with
  GOOS/GOARCH unset, the way the Makefile does it, so a cross build does not
  try to run a target binary on the build machine. buildGoModule runs preBuild
  in the vendoring derivation as well, before vendor/ exists and before the
  dependencies are in reach, so the two steps are gated on vendor/.
- The furrow step gets its bytes from fetchurl and `-from`, the offline road
  upstream documents. The fetcher still checks the sha256 in
  internal/furrowbin/pin.json, so the hashes here duplicate a pin that is
  already in the source; drop the furrow entirely and codeaf still builds and
  falls back to looking for the binary on PATH.

Tests are off: the upstream suite is a make/CI matrix with network and timing
assumptions, not a `go test ./...` that fits buildGoModule.

Verified with nix build .#codeaf, `codeaf --version` reporting 0.7.1 and
`codeaf manual` listing the packed manual pages.

Refs nix-overlay-m5y
This commit is contained in:
2026-10-06 21:45:16 +03:00
parent dcbde330e4
commit 03337bc545
3 changed files with 125 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
{
pkgs,
...
}:
pkgs.callPackage ./package.nix { }
+118
View File
@@ -0,0 +1,118 @@
{
lib,
buildGoModule,
fetchFromGitHub,
fetchurl,
stdenv,
}:
# Every codeaf ships a furrow inside it: internal/furrowbin embeds a pinned
# Agent-Field/furrow release, and `make build` stages it with
# `fetch -from <file>` instead of downloading, which is the road this build
# takes. The fetcher re-checks the sha256 named in internal/furrowbin/pin.json,
# so the hashes below are a second copy of a pin already in the source. Without
# a staged furrow codeaf still builds, and looks for the binary on PATH instead.
let
furrow = (
{
x86_64-linux = {
goos = "linux";
goarch = "amd64";
source = fetchurl {
url = "https://github.com/Agent-Field/furrow/releases/download/v0.1.0/furrow-linux-amd64";
hash = "sha256-x/h+3m81Kq0F066kJRfqychmCa3rYlGHKGQRSSZj4rQ=";
};
};
aarch64-linux = {
goos = "linux";
goarch = "arm64";
source = fetchurl {
url = "https://github.com/Agent-Field/furrow/releases/download/v0.1.0/furrow-linux-arm64";
hash = "sha256-ifE9UG8vf1TSyJIMU7V4TwsBiK5w91jpErcb/v3x0dY=";
};
};
x86_64-darwin = {
goos = "darwin";
goarch = "amd64";
source = fetchurl {
url = "https://github.com/Agent-Field/furrow/releases/download/v0.1.0/furrow-darwin-amd64";
hash = "sha256-B5mP5JoqoZ9O0IdVud6mWkiwjR/WgLWFKMVbNXnLaFI=";
};
};
aarch64-darwin = {
goos = "darwin";
goarch = "arm64";
source = fetchurl {
url = "https://github.com/Agent-Field/furrow/releases/download/v0.1.0/furrow-darwin-arm64";
hash = "sha256-EJN1Fmnla1dqK2WPvZxFKcqvNWfqoJyfduDV2wL4+hY=";
};
};
}
.${stdenv.hostPlatform.system} or null
);
in
buildGoModule rec {
pname = "codeaf";
version = "0.7.1";
src = fetchFromGitHub {
owner = "Agent-Field";
repo = "CodeAF";
rev = "v${version}";
hash = "sha256-F4rRDNrTCF8/cj6g0KM41+gNdzvTWw5Vj2N0OJp+vCc=";
};
vendorHash = "sha256-eIocnhp3uGk+wG0kprRie0Csms+Deqxy3K3HuI1vJyM=";
env.CGO_ENABLED = 0;
# The shipped binary carries the packed manual rather than the raw Markdown.
tags = [ "codeaf_packed_manual" ];
subPackages = [ "cmd/codeaf" ];
# Upstream's own suite is a CI matrix (make test / make check) with network
# and timing assumptions; it is not buildGoModule-shaped.
doCheck = false;
# `make build` runs two host-side steps before compiling. Both are built for
# the build machine even when codeaf targets another platform, hence the
# unset GOOS/GOARCH; the fetcher is told the target platform by hand. The
# vendoring derivation runs preBuild too, before vendor/ exists, and these two
# need the vendored dependencies, so they wait for it.
preBuild = ''
if [ -d vendor ]; then
env -u GOOS -u GOARCH go generate ./internal/manual
${lib.optionalString (furrow != null)
"env -u GOOS -u GOARCH go run ./internal/furrowbin/cmd/fetch -goos=${furrow.goos} -goarch=${furrow.goarch} -from ${furrow.source}"
}
fi
'';
ldflags = [
"-s"
"-w"
"-X github.com/Agent-Field/codeaf/internal/buildinfo.rev=${version}"
"-X github.com/Agent-Field/codeaf/internal/buildinfo.dirty=false"
];
passthru = {
category = "AI Coding Agents";
updateScript = [
"nix-update"
"--flake"
".#codeaf"
];
};
meta = with lib; {
description = "Coding harness and software factory for open models: hand off work and watch every project from one terminal";
homepage = "https://github.com/Agent-Field/CodeAF";
changelog = "https://github.com/Agent-Field/CodeAF/blob/v${version}/CHANGELOG.md";
license = licenses.asl20;
# Not fromSource all the way down: the binary embeds the prebuilt furrow
# release named in internal/furrowbin/pin.json.
mainProgram = "codeaf";
platforms = platforms.linux ++ platforms.darwin;
};
}