Signal-Enabled Release Builds¶
How amplihack's official release and snapshot binaries ship with the
Signal channel compiled in, so that an azlin fleet
obtains a Signal-capable amplihack-hooks binary automatically from
install/bootstrap/deploy — with no source rebuild and no --features signal
opt-in required on the target host.
TL;DR. Published Unix archives contain two Signal-enabled binaries:
amplihackandamplihack-hooks. The Windows release archive keeps theamplihack-hooksSignal integration compiled out because that hook path uses Unix process-management APIs at runtime. ThesignalCargo feature is enabled at the CI/release build layer for supported hook targets; library defaults are unchanged.
- Background: why this exists
- What ships
- How the fleet obtains a Signal-enabled binary
- The build commands
- Target coverage
- Verifying a release binary is Signal-enabled
- What did not change
- Rationale & decision record
- Reference
Background: why this exists¶
The per-session Signal channel is implemented in amplihack-signal and wired
into session lifecycle through the amplihack-hooks library (SessionStart).
Both the CLI binary (amplihack) and the multicall hook binary
(amplihack-hooks) are what a host actually runs — and the SessionStart hook
path lives in amplihack-hooks.
Historically the release pipeline built the workspace with default features
only. The CLI binary (bins/amplihack) force-links Signal through its
amplihack-cli dependency (features = ["signal"]), so amplihack was always
Signal-capable. But the hook binary package (amplihack-hooks-bin) declares
signal as an off-by-default feature:
Because the release build never passed --features amplihack-hooks-bin/signal,
the shipped amplihack-hooks binary had Signal compiled out. A fleet
installing an official artifact therefore received a hook binary whose
SessionStart path could not start the Signal channel — the "shipping gap."
Signal-enabled release builds close that gap by turning the feature on at the build step, so the compiled artifact everyone downloads already contains the Signal code.
What ships¶
| Artifact set | Archive | Binaries inside | Signal in amplihack |
Signal in amplihack-hooks |
|---|---|---|---|---|
| Stable release (Unix) | amplihack-<target>.tar.gz |
amplihack, amplihack-hooks |
✅ | ✅ |
| Stable release (Windows) | amplihack-x86_64-pc-windows-msvc.tar.gz |
amplihack.exe, amplihack-hooks.exe |
✅ | ❌ (Unix-only hook integration) |
| Snapshot (Unix targets) | amplihack-<target>.tar.gz (uploaded as artifact snapshot-<target>) |
amplihack, amplihack-hooks |
✅ | ✅ |
The archive layout, file names, and checksum sidecars
(amplihack-<target>.tar.gz.sha256) are unchanged. Only the contents of the Unix amplihack-hooks binaries changed: they now
link the Signal stack. The Windows hook binary remains Signal-less because the
hook-side subscriber lifecycle uses Unix process groups and signals.
How the fleet obtains a Signal-enabled binary¶
No fleet-side change is required. The existing install/bootstrap/deploy path already downloads and unpacks the official archive:
- Install / bootstrap pulls
amplihack-<target>.tar.gz(or the snapshot archive) from the GitHub Release assets. - The archive is unpacked onto the host;
amplihackandamplihack-hooksland onPATH. - On the next agent session, the
amplihack-hooksSessionStart path can now start the Signal channel because the code is present in the binary.
Because the fix is in the artifact itself, fleet distribution, install scripts, and deploy tooling need no edits. A host that previously received a Signal-less hook binary now receives a Signal-enabled one simply by upgrading to a build produced after this change.
Onboarding the runtime (linking a device, starting the local signal-cli daemon, writing config) is still handled separately by
amplihack signal setup/amplihack signal distribute— see SIGNAL_ONBOARDING.md. This document only covers the binary shipping with Signal compiled in.
The build commands¶
The feature is enabled by naming both shipped packages explicitly and turning
on the hook package's signal feature. At a virtual-workspace root,
cargo build --features … requires an explicit package selection, so the
commands use -p:
Stable release — .github/workflows/release.yml, Build release step:
feature_args=()
if [ "${{ matrix.target }}" != "x86_64-pc-windows-msvc" ]; then
feature_args=(--features amplihack-hooks-bin/signal)
fi
cargo build --release --locked --target ${{ matrix.target }} \
-p amplihack -p amplihack-hooks-bin \
"${feature_args[@]}"
Snapshot (native) — .github/workflows/publish-snapshot.yml,
Build (native) step:
cargo build --release --locked --target ${{ matrix.target }} \
-p amplihack -p amplihack-hooks-bin \
--features amplihack-hooks-bin/signal
Snapshot (cross) — .github/workflows/publish-snapshot.yml,
Build (cross) step (future-proofing for cross: true matrix entries):
cross build --release --locked --target ${{ matrix.target }} \
-p amplihack -p amplihack-hooks-bin \
--features amplihack-hooks-bin/signal
Notes:
-p amplihack -p amplihack-hooks-binbuilds exactly the two packages whose binaries are packaged. Theamplihackbinary is already Signal-enabled via its own manifest; keeping it in the selection preserves the artifact.--features amplihack-hooks-bin/signalis included via a static, allow-listed shell argument for Unix hook builds. It is deliberately omitted forx86_64-pc-windows-msvc, where the hook integration's subscriber process management is not supported.--lockedis retained on every command so the newly linked Signal stack (amplihack-signal,tokionet,libc) resolves to the pinned versions inCargo.lock.- The Package step is unchanged: it still copies
target/<target>/release/amplihackandtarget/<target>/release/amplihack-hooksintodist/.
Target coverage¶
The CLI and hook binaries have different Signal portability characteristics:
amplihacklinks the portableamplihack-signalstack throughamplihack-cli/signaland is built for every release target.amplihack-hookslinks the hook-side Signal integration only for Unix targets. That integration spawnssignal-subscriber, uses Unix process groups, and terminates subscribers with Unix signals, so the Windows release build intentionally omitsamplihack-hooks-bin/signal.
| Target | Built by | Signal in amplihack |
Signal in amplihack-hooks |
|---|---|---|---|
x86_64-unknown-linux-gnu |
release/snapshot | ✅ | ✅ |
aarch64-unknown-linux-gnu |
release/snapshot | ✅ | ✅ |
x86_64-apple-darwin |
release/snapshot | ✅ | ✅ |
aarch64-apple-darwin |
release/snapshot | ✅ | ✅ |
x86_64-pc-windows-msvc |
release | ✅ | ❌ |
PR CI validates the Unix hook builds. The release workflow keeps the Windows
artifact buildable by excluding the Unix-only hook feature for
x86_64-pc-windows-msvc, and the structural regression test locks that
conditional so a future edit cannot make tag releases fail only at publish time.
Verifying a release binary is Signal-enabled¶
After downloading and unpacking a release or snapshot archive:
# The Signal subcommand is always registered. In a Signal-enabled build it
# runs; in a Signal-less build it exits with a "rebuild with --features signal"
# error. A shipped hook binary now supports the SessionStart Signal path.
amplihack signal --help
# Heuristic only — a release build may strip symbols, so absence here does not
# prove Signal is missing. When present, these strings indicate the Signal
# stack was linked into the shipped hook binary (Linux/macOS):
strings ./amplihack-hooks | grep -i 'signal-cli\|amplihack-signal' | head
For Unix hook binaries, the authoritative release-build check is the CI/release
workflow command that compiles amplihack-hooks-bin with
--features amplihack-hooks-bin/signal. The Windows release job intentionally
proves the opposite: the archive remains buildable while omitting the Unix-only
hook feature.
What did not change¶
- Library default-feature policy is untouched.
amplihack-hooks-binstill declaresdefault = []; a plaincargo buildof the workspace still produces a Signal-less hook binary. Only the release/CI build turns the feature on. amplihack-signalbehavior and its message-validation code are unchanged. The fix compiles already-shipped logic into a second binary; it does not add or alter Signal capability.bins/amplihack/Cargo.tomlis unchanged — the CLI binary was already Signal-enabled.- No required status-check names changed. Only the
run:bodies of existing build steps were edited. Job/stepname:,env:,permissions:, packaging, upload, and release steps are identical. Required checks (Lint & Format,Test,Install Smoke Test,Build <target>,Release) are preserved.
Rationale & decision record¶
Decision: the gap is real and is fixed at the CI/release build layer — not by changing library defaults.
- Why not flip the library default to
signal? That would force Signal into every build of the hook binary, including local/dev workspace builds and any downstream consumer, changing behavior far beyond the shipping artifacts. The goal is only that official shipped binaries include Signal, so the change belongs in the release/CI build commands. - Why keep the source opt-in? Developers building the workspace without
Signal (e.g., for a minimal hook binary or to avoid the signal-cli runtime
dependency during unrelated work) retain that option. The
signalfeature remains a real, off-by-default compile-time switch. - Why enable on all targets? Parity with the already-Signal-enabled CLI binary. Selective enablement would create a matrix where the two shipped binaries disagree on Signal support per platform — confusing and unnecessary, since the stack already compiles everywhere.
Reference¶
- Signal channel — the per-session channel implementation.
- Signal onboarding —
signal setup/signal distributeruntime onboarding for hosts and fleets. - Signal external integration — integrating external systems with the Signal channel.
.github/workflows/release.yml— stable release build & packaging..github/workflows/publish-snapshot.yml— per-SHA snapshot build & packaging.bins/amplihack-hooks/Cargo.toml— thesignalfeature definition onamplihack-hooks-bin.