Skip to content

ci: publish Sprout Agent Bundle (sprout-acp + sprout-agent + sprout-dev-mcp) to GitHub Releases#603

Merged
tlongwell-block merged 3 commits into
mainfrom
feat/sprout-agent-bundle
May 16, 2026
Merged

ci: publish Sprout Agent Bundle (sprout-acp + sprout-agent + sprout-dev-mcp) to GitHub Releases#603
tlongwell-block merged 3 commits into
mainfrom
feat/sprout-agent-bundle

Conversation

@tlongwell-block
Copy link
Copy Markdown
Collaborator

Summary

Adds a Linux release bundle for external services that need to embed a Sprout agent end-to-end (e.g. sprout-backend-blox).

The bundle contains the three binaries needed to run a Sprout agent:

Binary Role
sprout-acp ACP harness that bridges Sprout channel events to an ACP-compliant agent over stdio
sprout-agent ACP-compliant agent (spawns MCP servers, calls LLMs)
sprout-dev-mcp Developer MCP server + multicall entrypoint for rg, tree, sprout, git-credential-nostr, git-sign-nostr

What's in this PR

.github/workflows/sprout-agent-bundle.yml

  • Targets x86_64-unknown-linux-musl and aarch64-unknown-linux-musl (static musl, runs on any modern Linux)
  • Uses the same cross@0.2.5 toolchain already pinned in ci.yml — no new toolchain dependency
  • Triggers:
    • push to main → updates rolling sprout-agent-bundle-latest prerelease
    • tag sprout-agent-bundle-v* → versioned release
    • workflow_dispatch → manual build (optional publish via input)
  • Uses gh release (matches the in-repo style from release.yml) rather than introducing softprops/action-gh-release
  • Uploads <bundle>.tar.gz + <bundle>.tar.gz.sha256 per target

scripts/build-agent-bundle.sh

Single source of truth for packaging — CI calls it directly so local builds and CI builds produce byte-identical structure.

  • Builds with cross when cross-compiling, plain cargo on host (no Docker requirement for contributors)
  • Strips binaries (best-effort)
  • Emits bundle.json with {name, version, git_sha, target, binaries: [{name, sha256, size}]} — machine-readable manifest for downstream consumers
  • Deterministic-ish tarball (sorted entries, uid=0/gid=0, numeric owner), with BSD-tar fallback for local macOS use
  • SKIP_BUILD=1 re-packages without rebuilding (used in local verification)

Replaces scripts/build-agent-release.sh, which only packaged 2 binaries.

.gitignore

Adds /dist/ so the bundle script's output doesn't pollute working trees.

Verification

Ran locally on aarch64-apple-darwin with SKIP_BUILD=1:

$ tar -tzf dist/sprout-agent-bundle-0.1.0-test-aarch64-apple-darwin.tar.gz
./
./sprout-dev-mcp
./bundle.json
./README.md
./sprout-acp
./sprout-agent

bundle.json parses cleanly under jq, sha256 sidecar matches, actionlint clean on the workflow.

Out of scope (intentional)

  • sprout-backend-blox is not switched over to consume the bundle yet — that's the follow-up PR once this lands and we have a release artifact to point at.
  • macOS / Windows bundles (Linux-only, per discussion).
  • Separate git-credential-nostr / git-sign-nostr binaries — the sprout-dev-mcp multicall covers them.

…ev-mcp) to GitHub Releases

Adds a Linux release bundle for external services that need to embed a
Sprout agent end-to-end (e.g. sprout-backend-blox).

What's in the bundle:
- sprout-acp      — ACP harness that bridges Sprout events to an agent
- sprout-agent    — ACP-compliant agent (spawns MCP, calls LLMs)
- sprout-dev-mcp  — Developer MCP server (multicall: rg, tree, sprout,
                    git-credential-nostr, git-sign-nostr)

Workflow `.github/workflows/sprout-agent-bundle.yml`:
- Targets x86_64-unknown-linux-musl and aarch64-unknown-linux-musl
- Uses the same `cross@0.2.5` toolchain already pinned in ci.yml
- Triggers:
    push to main                      → updates rolling
                                        `sprout-agent-bundle-latest` release
    tag `sprout-agent-bundle-v*`      → versioned release
    workflow_dispatch                  → manual build (optional publish)
- Uses `gh release` (matches release.yml style), not a new third-party
  action
- Uploads asset + .sha256 sidecar per target

Script `scripts/build-agent-bundle.sh` is the single source of truth for
packaging (CI calls it directly). It:
- Builds with `cross` when cross-compiling, plain `cargo` on host
- Strips binaries (best-effort)
- Emits `bundle.json` with {name, version, git_sha, target, binaries:
  [{name, sha256, size}]} for downstream consumers
- Produces a deterministic-ish tarball (sorted, uid=0/gid=0) with a
  README and bundle.json
- Supports SKIP_BUILD=1 for re-packaging without rebuilding (used in
  local verification and useful for fast iteration)

Replaces `scripts/build-agent-release.sh`, which only packaged
sprout-agent + sprout-dev-mcp.

Not in this PR (intentional, per discussion):
- sprout-backend-blox is not yet switched over to consume the bundle
- macOS/Windows bundles
- sprout-mcp-server, git-credential-nostr, git-sign-nostr as separate
  binaries (the dev-mcp multicall covers them)

Verified locally on aarch64-apple-darwin with SKIP_BUILD=1: tarball
contains the 3 binaries + README.md + bundle.json, sha256 sidecar
matches, and bundle.json parses cleanly under jq.

Signed-off-by: Tyler Longwell <109685178+tlongwell-block@users.noreply.github.com>
Comment thread .github/workflows/sprout-agent-bundle.yml Fixed
…ble rolling asset names, single-source build

Addresses Max's review on #603.

Rolling release semantics:
- Force-move the `sprout-agent-bundle-latest` git tag to the current
  `main` SHA before touching the release. `gh release edit` updates
  release metadata but does not move the underlying tag, so without
  this the tag would stick to whatever SHA first created the release.
  Uses `gh api PATCH .../git/refs/tags/...` (with force=true) and
  falls back to `POST .../git/refs` for the initial-create case.
- Also pass `--target ${SHA}` to `gh release create/edit` so the
  release's "target commitish" tracks the build SHA.

Stale-asset cleanup on the rolling release:
- Rolling builds now use stable, version-less asset filenames
  (`sprout-agent-bundle-<target>.tar.gz`). `--clobber` overwrites them
  in place on every push, so the release no longer accumulates
  SHA-named tarballs.
- Tagged releases keep the versioned filename
  (`sprout-agent-bundle-<version>-<target>.tar.gz`) for traceability.
- The git SHA + version always live inside `bundle.json` regardless of
  the asset filename, so consumers/debugging never lose provenance.
- `scripts/build-agent-bundle.sh` gains an `ARCHIVE_BASENAME` env var
  override (documented in the header) so the workflow can pick the
  right filename per channel; default unchanged.

Single source of truth for the build:
- Removed the workflow's explicit `cross build` step. The script
  already auto-selects `cross` when target != host, so the previous
  setup was building everything twice.

Verified locally with `SKIP_BUILD=1`:
- Rolling-style basename → `sprout-agent-bundle-<target>.tar.gz`
  with sha sidecar `OK` under `sha256sum -c`.
- Tagged-style basename → `sprout-agent-bundle-<version>-<target>.tar.gz`.
- Both tarballs contain the 3 binaries + README + bundle.json with
  matching shas/sizes.
- actionlint + shellcheck clean.

Signed-off-by: Tyler Longwell <109685178+tlongwell-block@users.noreply.github.com>
…giene)

Per the zizmor PR review thread on #603: the SHA-pinned action comments
should match the exact upstream tag, not a broader floating tag, so the
scanner doesn't flag a metadata mismatch.

- taiki-e/install-action: `# v2` → `# v2.75.18` (the SHA's exact tag)
- actions/upload-artifact: `# v4` → `# v4.6.2`
- actions/download-artifact: `# v4` → `# v4.3.0`

Pinned SHAs are unchanged — no behavior change, just correct metadata.
`actions/checkout` and `cashapp/activate-hermit` already match (their
SHAs are the literal `v6` / `v1` commits).

Signed-off-by: Tyler Longwell <109685178+tlongwell-block@users.noreply.github.com>
@tlongwell-block tlongwell-block enabled auto-merge (squash) May 16, 2026 20:58
@tlongwell-block tlongwell-block merged commit 6ba46f2 into main May 16, 2026
15 checks passed
@tlongwell-block tlongwell-block deleted the feat/sprout-agent-bundle branch May 16, 2026 21:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants