Copied to Clipboard
cd ..
echo "Build complete: bin/cagent-linux-riscv64"
}
Key decisions here:
Submodule approach - Following our pattern of using official upstream sources as git submodules rather than vendoring or forking. This keeps us synchronized with upstream, eliminates fork maintenance burden, and makes it trivial to update to any version (just git submodule update --remote)
Version embedding - Using ldflags to bake version info into the binary
Static naming - Output to cagent-linux-riscv64 for consistency with our other packages
3.1.1. Build Performance
On our BananaPi F3 RISC-V64 hardware:
Build time: 5-8 minutes (depending on Go cache state)
Resource requirements:
RAM: 2GB minimum, 4GB recommended
Disk space: ~1GB for Go dependencies and build artifacts
Network: ~200MB initial download for Go modules
Go version: Requires Go 1.21 or later for RISC-V64 support
3.2. The CI/CD Pipeline
I created three workflows following our established patterns:
3.2.1. Weekly Builds (cagent-weekly-build.yml)
Runs every Sunday at 06:00 UTC, building the latest cagent from the main branch.
The complete workflow is available at cagent-weekly-build.yml.
Key sections:
jobs:
build-cagent:
runs-on: [self-hosted, riscv64]
steps:
* name: Build cagent binary
run: |
cd cagent
GIT_TAG=$(git describe --tags --exact-match 2>/dev/null || echo "dev")
GIT_COMMIT=$(git rev-parse HEAD)
GOOS=linux GOARCH=riscv64 CGO_ENABLED=0 go build \
-ldflags "-X 'github.com/docker/cagent/pkg/version.Version=${GIT_TAG}' -X 'github.com/docker/cagent/pkg/version.Commit=${GIT_COMMIT}'" \
-o cagent-linux-riscv64 \
./main.go
Note CGO_ENABLED=0 - we want truly static binaries that don’t depend on glibc or other C libraries, ensuring maximum portability across different RISC-V64 systems. This eliminates runtime dependencies and makes the binary work identically on any RISC-V64 Linux system, regardless of library versions.
3.2.2. Release Tracking (track-cagent-releases.yml)
Checks daily for new upstream releases and automatically triggers builds.
The complete workflow is available at track-cagent-releases.yml.
Key logic:
-
name: Check for new cagent release run: | # Get latest release from docker/cagent LATEST=\$(gh api repos/docker/cagent/releases/latest --jq '.tag_name')
# Check if we've built it (cagent-v1.9.13-riscv64 format)
CLEAN_VERSION="${LATEST#v}"
OUR_TAG="cagent-v${CLEAN_VERSION}-riscv64"
if gh release view "${OUR_TAG}" >/dev/null 2>&1; then
echo "already_built=true"
else
echo "already_built=false"
# Trigger build workflow
gh workflow run cagent-weekly-build.yml -f cagent_ref=$LATEST
fi
This gives us automatic version tracking with zero manual intervention.
3.2.3. Package Builds (Debian and RPM)
The package workflows trigger automatically after successful binary builds. More on this in the packaging section.
4. The Packaging Challenge: Go Binaries Are Special
Here’s where things got interesting. Go binaries have quirks that make packaging different from traditional C/C++ software.
4.1. The Debian Package
Creating the Debian package structure in debian-cagent/.
4.1.1. Package Control File
The control file defines metadata and dependencies:
Source: cagent
Section: devel
Priority: optional
Maintainer: Bruno Verachten
Build-Depends: debhelper-compat (= 13)
Standards-Version: 4.7.2.0
Homepage: https://github.com/docker/cagent
Package: cagent
Architecture: riscv64
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: Multi-agent AI runtime by Docker Engineering for RISC-V64
cagent is a powerful, easy to use, customizable multi-agent runtime that
orchestrates AI agents with specialized capabilities and tools.
4.1.2. The debian/rules Magic
The real magic is in debian/rules, where we tell dpkg how to handle our pre-built binary:
#!/usr/bin/make -f
%:
dh $@
override_dh_auto_build:
# Binary is pre-built, skip build
override_dh_auto_install:
install -d debian/cagent/usr/bin
install -m 0755 bin/cagent-linux-riscv64 debian/cagent/usr/bin/cagent
override_dh_strip:
# Skip stripping Go binaries
override_dh_shlibdeps:
# Skip shlib dependency detection for Go binaries
override_dh_dwz:
# Skip dwz compression for Go binaries
4.1.3. Understanding the Overrides
Let me explain these overrides, because they’re critical for Go binary packaging:
Why Skip Stripping?
Go binaries embed metadata that tools like strip can corrupt. The version information we baked in with ldflags? Stripping can damage it.
Why Skip Shlib Dependencies?
Go programs are typically statically linked. They don’t depend on system shared libraries the way C programs do. Running dh_shlibdeps would either fail or add bogus dependencies.
Why Skip dwz?
The dwz tool compresses DWARF debug information, but Go’s debug format doesn’t play nicely with it. You’ll get errors about "unsupported compressed debug sections."
These overrides were hard-won knowledge from earlier Go packaging attempts.
4.2. The RPM Package
The RPM spec file (rpm-cagent/cagent.spec) has similar considerations:
Name: cagent
Version: 1.9.13
Release: 1%{?dist}
Summary: Multi-agent AI runtime by Docker Engineering for RISC-V64
BuildArch: riscv64
# Disable Go binary processing
%global __brp_strip %{nil}
%global __brp_strip_static_archive %{nil}
%global __brp_strip_comment_note %{nil}
%global _enable_debug_packages 0
%global debug_package %{nil}
%install
install -d %{buildroot}%{_bindir}
install -p -m 0755 %{SOURCE0} %{buildroot}%{_bindir}/cagent
Same principle: tell RPM to leave our Go binary alone. Don’t strip it, don’t analyze it, don’t debug-package it, just install it.
4.3. Package Detection Logic
Here’s a subtle bug I had to fix. The package build workflow needs to detect whether a release already has packages.
Initially, I used a pattern that was too strict:
# Broken (too strict - doesn't match version-suffixed filenames):
if echo "$ASSETS" | grep -q 'cagent\.deb'; then
echo "Release already has Debian packages - skipping build"
exit 0
fi
This failed to match versioned filenames like cagent_1.9.13-1_riscv64.deb because it looked for an exact .deb extension without accounting for the version string.
The corrected version:
# Fixed (properly matches versioned filenames):
ASSETS=$(gh release view "$LATEST_RELEASE" --json assets --jq '.assets[].name')
if echo "$ASSETS" | grep -q 'cagent.*\.deb$'; then
echo "Release already has Debian packages - skipping build"
exit 0
fi
The regex
cagent.
\deb\$ uses . to match any characters (including underscores, version numbers, and architecture tags) between "cagent" and ".deb", properly matching filenames like cagent_1.9.13-1_riscv64.deb.
5. Repository Integration: Making it Available
With packages built correctly and automation detecting releases properly, the next challenge was making them easily discoverable and installable through standard package managers. Building the packages is only half the battle. Users need a way to install them.
5.1. APT Repository Updates
The update-apt-repo.yml workflow now includes cagent in its triggers:
on:
workflow_run:
workflows:
* "Build Debian Package"
* "Build Docker Compose Debian Package"
* "Build Docker CLI Debian Package"
* "Build Docker Buildx Debian Package"
* "Build cagent Debian Package" # <-- Added this
types: [completed]
When a cagent Debian package is built, the workflow:
Downloads the .deb from the release
Checks out the apt-repo branch
Uses reprepro to add the package
Signs it with our GPG key
Commits and pushes to GitHub Pages
Users can now install cagent alongside Docker:
# Add our repository
wget -qO - https://github.com/gounthar/docker-for-riscv64/releases/download/gpg-key/docker-riscv64.gpg \
| sudo gpg --dearmor -o /usr/share/keyrings/docker-riscv64.gpg
echo "deb [arch=riscv64 signed-by=/usr/share/keyrings/docker-riscv64.gpg] \
https://gounthar.github.io/docker-for-riscv64 trixie main" \
| sudo tee /etc/apt/sources.list.d/docker-riscv64.list
# Install cagent
sudo apt-get update
sudo apt-get install cagent
The installation output should look like this:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
cagent
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/26.6 MB of archives.
After this operation, 73.9 MB of additional disk space will be used.
Selecting previously unselected package cagent.
(Reading database ... 145234 files and directories currently installed.)
Preparing to unpack .../cagent_1.9.13-1_riscv64.deb ...
Unpacking cagent (1.9.13-1) ...
Setting up cagent (1.9.13-1) ...
5.1.1. Verification
After installation, verify the package is working correctly:
# Check version
cagent version
# Expected output:
# cagent version 1.9.13 (commit: abc123...)
# Verify binary location
which cagent
# /usr/bin/cagent
# Test basic functionality
cagent new --help
# Should display help for creating new agent configurations
5.2. RPM Repository Updates
Similarly for RPM (update-rpm-repo.yml):
on:
workflow_run:
workflows:
* "Build Docker RPM Package"
* "Build Docker Compose RPM Package"
* "Build Docker CLI RPM Package"
* "Build Tini RPM Package"
* "Build Docker Buildx RPM Package"
* "Build cagent RPM Package" # <-- Added this
The process is similar but uses createrepo_c instead of reprepro. Fedora RISC-V users can now:
# Add our repository
sudo tee /etc/yum.repos.d/docker-riscv64.repo << EOF
[docker-riscv64]
name=Docker for RISC-V64
baseurl=https://gounthar.github.io/docker-for-riscv64/rpm
enabled=1
gpgcheck=1
gpgkey=https://github.com/gounthar/docker-for-riscv64/releases/download/gpg-key/docker-riscv64.gpg
EOF
# Install cagent
sudo dnf install cagent
The installation output should look like this:
Last metadata expiration check: 0:00:23 ago on Thu 14 Nov 2025 06:30:15 PM UTC.
Dependencies resolved.
================================================================================
Package Architecture Version Repository Size
================================================================================
Installing:
cagent riscv64 1.9.13-1 docker-riscv64 26 M
Transaction Summary
================================================================================
Install 1 Package
Total download size: 26 M
Installed size: 74 M
Is this ok [y/N]: y
Downloading Packages:
cagent-1.9.13-1.riscv64.rpm 26 MB/s | 26 MB 00:01
--------------------------------------------------------------------------------
Total 26 MB/s | 26 MB 00:01
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : cagent-1.9.13-1.riscv64 1/1
Verifying : cagent-1.9.13-1.riscv64 1/1
Installed:
cagent-1.9.13-1.riscv64
Complete!
5.2.1. Verification
After installation, verify the package is working correctly:
# Check version
cagent version
# Expected output:
# cagent version 1.9.13 (commit: abc123...)
# Verify binary location
which cagent
# /usr/bin/cagent
# Verify RPM package info
rpm -qi cagent
# Should show package information including version and description
# Test basic functionality
cagent new --help
# Should display help for creating new agent configurations
6. The First Package: What It Means
Let me emphasize this again: this is the first Linux distribution package for cagent. Period.
6.1. Why This Matters
Docker provides several distribution methods:
GitHub releases - Manual downloads of static binaries
Homebrew - Automated installation on macOS
Docker Hub - Agent configurations as OCI images
But no Linux distribution had packaged it. Not Debian, not Fedora, not Ubuntu, not Arch. We’re first.
6.2. Implications for cagent
Being packaged in a distribution (even a small, specialized one) has benefits:
Dependency management - Package managers handle updates
System integration - Standard paths, predictable locations
Distribution channels - Easier discovery for users
Validation - Packages go through quality checks
Our packaging work could serve as a template when mainstream distributions eventually package cagent.
6.3. Implications for RISC-V64
Every modern, cutting-edge tool we bring to RISC-V64 strengthens the ecosystem:
Developer mindshare - "I can run cagent on RISC-V? Interesting..."
Use case expansion - RISC-V64 as an AI development platform
Ecosystem completeness - Docker + Docker Compose + Buildx + cagent = full stack
We’re not just porting old software. We’re bringing tomorrow’s tools to RISC-V64 today.
6.4. Distribution Availability Comparison
Here’s how cagent availability looks across different Linux distributions and architectures:
<table> <colgroup> <col> <col> <col> <col> </colgroup> <thead> <tr> <th>Distribution</th> <th>Architecture</th> <th>Package Available</th> <th>Installation Method</th> </tr> </thead> <tbody> <tr> <td><p>_Debian Trixie_</p></td> <td><p>riscv64</p></td> <td><p>✅ Yes (First!)</p></td> <td><p>`apt-get install cagent`</p></td> </tr> <tr> <td><p>_Fedora_</p></td> <td><p>riscv64</p></td> <td><p>✅ Yes (First!)</p></td> <td><p>`dnf install cagent`</p></td> </tr> <tr> <td><p>_Ubuntu_</p></td> <td><p>riscv64</p></td> <td><p>⚠️ Compatible</p></td> <td><p>Our .deb packages compatible<sup>1</sup></p></td> </tr> <tr> <td><p>_Ubuntu_</p></td> <td><p>amd64/arm64</p></td> <td><p>❌ No</p></td> <td><p>Manual download from GitHub</p></td> </tr> <tr> <td><p>_Debian_</p></td> <td><p>amd64/arm64</p></td> <td><p>❌ No</p></td> <td><p>Manual download from GitHub</p></td> </tr> <tr> <td><p>_Fedora_</p></td> <td><p>x86_64/aarch64</p></td> <td><p>❌ No</p></td> <td><p>Manual download from GitHub</p></td> </tr> <tr> <td><p>_Arch Linux_</p></td> <td><p>Any</p></td> <td><p>❌ No</p></td> <td><p>Manual download or AUR</p></td> </tr> <tr> <td><p>_macOS_</p></td> <td><p>arm64/amd64</p></td> <td><p>✅ Yes</p></td> <td><p>`brew install cagent`</p></td> </tr> <tr> <td><p>_Any Linux_</p></td> <td><p>Any</p></td> <td><p>⚠️ Binary</p></td> <td><p>Download from docker/cagent releases</p></td> </tr> </tbody> </table>
<sup>1</sup> Our Debian Trixie packages use .deb format and should work on Ubuntu RISC-V64 systems, though we haven’t officially tested or certified this configuration. Ubuntu uses the same package format (dpkg/apt), so compatibility is likely but not guaranteed.
Key insight: As of November 2025, RISC-V64 is the only Linux architecture with native distribution packages for cagent. Not x8664,円 not aarch64 - RISC-V64 is leading in cagent packaging support.
7. Lessons Learned
7.1. Go Binary Packaging is Different
The biggest lesson: Go binaries need special handling. Document these overrides clearly:
Skip stripping (corrupts embedded metadata)
Skip shlib detection (static linking)
Skip dwz compression (incompatible debug format)
These aren’t optional workarounds. They’re requirements for correct Go packaging.
7.2. Automation Prevents Drift
Our automated tracking caught cagent 1.9.13’s release within 24 hours. Without automation, we’d need manual monitoring and would likely lag weeks behind upstream.
The pattern we’ve established - weekly builds + daily release tracking + automatic packaging - scales beautifully. Adding cagent required minimal new code because the infrastructure was already there.
7.3. First-Mover Advantage Exists
Being the first to package cagent gives us visibility. When people search "cagent linux package," we’re the answer. When upstream Docker considers distribution packaging, we’re the reference implementation.
Speed matters in open source. Being first isn’t everything, but it’s something.
8. Current Status and Future Work
8.1. What Works Today
As of November 14, 2025:
✅ cagent 1.9.13-1 available for Debian Trixie (riscv64)
✅ cagent 1.9.13-1 available for Fedora (riscv64)
✅ Automated weekly builds from upstream main
✅ Automated release tracking and packaging
✅ Signed APT and RPM repositories
✅ Full GitHub Pages distribution
Installation requires adding our repository first:
# Debian/Trixie - Add repository
wget -qO - https://github.com/gounthar/docker-for-riscv64/releases/download/gpg-key/docker-riscv64.gpg \
| sudo gpg --dearmor -o /usr/share/keyrings/docker-riscv64.gpg
echo "deb [arch=riscv64 signed-by=/usr/share/keyrings/docker-riscv64.gpg] \
https://gounthar.github.io/docker-for-riscv64 trixie main" \
| sudo tee /etc/apt/sources.list.d/docker-riscv64.list
# Install cagent
sudo apt-get update
sudo apt-get install cagent
# Verify
cagent version
For Fedora:
# Fedora - Add repository
sudo tee /etc/yum.repos.d/docker-riscv64.repo << EOF
[docker-riscv64]
name=Docker for RISC-V64
baseurl=https://gounthar.github.io/docker-for-riscv64/rpm/fedora/riscv64
enabled=1
gpgcheck=1
gpgkey=https://github.com/gounthar/docker-for-riscv64/releases/download/gpg-key/docker-riscv64.gpg
EOF
# Install cagent
sudo dnf install cagent
# Verify
cagent version
8.2. Troubleshooting
8.2.1. Build Issues
Problem: "cagent directory not found" error
Error: cagent directory not found
Please initialize the submodule with:
git submodule update --init --recursive
Solution: Initialize the git submodule:
git submodule update --init --recursive
Problem: "unsupported GOOS/GOARCH pair linux/riscv64" error
Solution: Update to Go 1.21 or later, which includes official RISC-V64 support:
go version # Should show go1.21 or later
Problem: Build runs out of memory
Solution: Ensure at least 2GB RAM is available. On constrained systems, reduce concurrent builds:
GOMAXPROCS=1 go build ...
8.2.2. Installation Issues
Problem: "Signature verification failed" when installing
E: The repository 'https://gounthar.github.io/docker-for-riscv64 trixie Release' is not signed.
Solution: Re-import the GPG key:
wget -qO - https://github.com/gounthar/docker-for-riscv64/releases/download/gpg-key/docker-riscv64.gpg \
| sudo gpg --dearmor -o /usr/share/keyrings/docker-riscv64.gpg
# Verify key was imported
gpg --list-keys --keyring /usr/share/keyrings/docker-riscv64.gpg
Problem: "Package cagent is not available" on apt-get install
Solution: Ensure the architecture matches:
# Check your architecture
dpkg --print-architecture
# Should show: riscv64
# Update package lists
sudo apt-get update
# Verify repository is added
apt-cache policy cagent
Problem: cagent binary fails with "cannot execute binary file: Exec format error"
Solution: This means you’re trying to run a RISC-V64 binary on a different architecture. Verify:
uname -m
# Should show: riscv64
file /usr/bin/cagent
# Should show: ELF 64-bit LSB executable, UCB RISC-V, ...
8.2.3. Runtime Issues
Problem: cagent fails with "API key not found"
Solution: cagent requires API keys for AI providers. Set them as environment variables:
export OPENAI_API_KEY="your-key-here"
export ANTHROPIC_API_KEY="your-key-here"
Or create a .env file in your agent configuration directory.
Problem: MCP server connection fails
Solution: Verify MCP servers are installed and accessible:
# Check if MCP server binary exists
which docker-mcp-server
# Test MCP server directly
docker-mcp-server --help
8.3. Real-World Example: DevOps Assistant
To demonstrate cagent’s capabilities, here’s a complete working configuration for a DevOps assistant specialized in RISC-V64 systems:
# devops-assistant.yaml
agents:
root:
model: anthropic/claude-3-5-sonnet-20241022
description: |
DevOps specialist for RISC-V64 Docker systems with expertise in
container management, system monitoring, and troubleshooting.
instruction: |
You are an expert DevOps engineer specializing in:
* Docker container management on RISC-V64 architecture
* System performance monitoring and optimization
* Build automation and CI/CD pipelines
* Linux package management (apt, dnf, rpm)
You have access to filesystem operations and can help users:
* Inspect Docker configurations and logs
* Analyze system resource usage
* Debug container issues
* Review build scripts and workflows
Always provide clear explanations and consider RISC-V64 specific
constraints like limited binary availability and build times.
toolsets:
* type: mcp
ref: docker:filesystem
config:
allowed_directories:
* /var/log/docker
* /etc/docker
* /home/${USER}/.docker
* ${PWD}
settings:
providers:
anthropic:
api_key_env: ANTHROPIC_API_KEY
model_aliases:
sonnet: claude-3-5-sonnet-20241022
Save this to devops-assistant.yaml and run:
# Set your API key
export ANTHROPIC_API_KEY="your-key-here"
# Run the agent
cagent run devops-assistant.yaml
# Example interaction:
# User: "Check my Docker daemon logs for errors"
# Agent: _uses filesystem MCP to read /var/log/docker/daemon.log_
# _analyzes logs and provides diagnostics_
This demonstrates:
Specialized knowledge - DevOps and RISC-V64 expertise in the instruction
Tool access - Filesystem MCP for reading logs and configs
Security constraints - Limited to specific directories
Provider configuration - Anthropic with model aliases
8.4. What’s Next
Several possibilities for future enhancement:
8.4.1. Configuration Package
cagent supports pre-configured agent definitions. We could create a cagent-examples package with useful agent configurations:
Development assistants (Golang expert, Python expert, DevOps specialist)
Multi-agent teams (software development team, research team)
MCP-integrated agents (GitHub integration, file system access, web search)
8.4.2. Systemd Integration
For long-running agent services, systemd units could automate:
8.4.3. MCP Server Packages
The Model Context Protocol ecosystem is growing. We could package popular MCP servers:
rust-mcp-filesystem - File system tools
mcp-server-git - Git operations
mcp-server-docker - Docker control
Combined with cagent, this creates a complete agent development environment.
9. Conclusion
Adding cagent to our RISC-V64 repository was straightforward technically - Go’s native RISC-V64 support made building trivial on our BananaPi F3 hardware, and our established packaging infrastructure made integration smooth.
But the significance goes beyond the technical implementation. We’ve brought a cutting-edge AI agent runtime to RISC-V64 before any mainstream Linux distribution packaged it. We’ve shown that RISC-V64 isn’t just catching up to existing software - it’s ready for the future.
When someone wants to build intelligent agent systems on RISC-V64, they can now:
sudo apt-get install cagent
cagent new # Generate an agent configuration
cagent run my-agent.yaml # Deploy it immediately
That’s the power of proper packaging: turning a GitHub project into a first-class system tool.
The Docker ecosystem on RISC-V64 now includes:
Docker Engine - Container runtime
Docker CLI - Command-line interface
Docker Compose - Multi-container applications
Docker Buildx - Multi-platform builds
Tini - Container init system
cagent - Multi-agent AI runtime
We’re not just building containers anymore. We’re building intelligent systems.
And that’s exciting.
10. Resources
11. License
This article is licensed under Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0).
Code examples in this article are dual-licensed under:
You are free to use, modify, and distribute the code examples under either license.
The cagent software itself is licensed under the Apache License 2.0. See the upstream repository for details.
_This work is part of the ongoing effort to bring Docker and modern development tools to RISC-V64 architecture. All code and packaging materials are available under open source licenses._
Version 1.0
Last updated 2025年11月14日 17:33:44 +0100
Last updated 2026年04月22日 08:54:59 UTC