A practical guide to permanent, verifiable, machine-readable software releases using Arweave, Radicle, IPFS, and a manifest format your CI pipeline can actually reason about — including agent-native local workspaces with Rift (copy-on-write) feeding immutable, censorship-resistant releases.
The incident that made this real
In December 2021, the colors and faker npm packages — with a combined weekly download count in the hundreds of millions — were deliberately sabotaged by their maintainer. The packages had been published once and trusted indefinitely by thousands of projects. One morning, anyone who ran npm install got corrupted code instead.
This wasn’t a compromised account or an external attacker. The maintainer had full, legitimate control. And that’s the point: the platforms hosting your software artifacts were never designed to prevent the publisher from changing what was published. Tags can move. Images can be overwritten. Packages can be yanked and republished.
Most of the time, nothing goes wrong. But the threat model for software supply chains has shifted materially in the last three years, for two reasons that compound each other.
The first is that AI coding agents now autonomously pull dependencies, deploy services, and apply updates without a human reviewing each step. An agent that trusts a release because it was signed yesterday has no way to know the signed artifact was silently replaced this morning. The verification model that works for human engineers — check the changelog, read the diff, consult a colleague — doesn’t scale to autonomous deployment.
The second is that supply chain attacks are no longer theoretical. The March 2026 LiteLLM compromise. The 2024 XZ Utils backdoor, embedded in a compression library shipped in almost every Linux distribution. The 2020 SolarWinds attack. Each of these succeeded because the artifacts being distributed were trusted implicitly — because they came from the right place, with the right signature, from an account that had been legitimate until it wasn’t.
This post describes a practical architecture for making releases permanent, tamper-evident, and machine-readable. It doesn’t require abandoning GitHub or your existing workflow. It requires one CLI tool and about thirty minutes for your first release.
For how this sits in the broader ClawQL vision — IDP pipeline, inference gateway, payments — see docs.clawql.com/vision/immutable-releases. It also pairs with Part 12 of Hardened Agentic Stack (supply-chain signing) when you’re ready for admission-time Cosign/Kyverno enforcement.
What “permanent” actually means
Before describing the solution, be precise about the problem. “Immutable” gets used loosely in software. Here’s what it needs to mean for a release to be trustworthy:
Content-addressed, not location-addressed. A URL is a location. The file at that location can change while the URL stays the same. A content address — a hash of the file’s bytes — is a permanent identifier. If the content changes, the address changes. You can’t swap the file out and keep the same address. This is the fundamental property that IPFS, Arweave, and git objects all share.
Permanent, not just archived. A Wayback Machine snapshot is content-addressed but can be taken down. A GitHub release can be deleted. “Permanent” means the economics and governance of the storage system make deletion effectively impossible, not just unlikely. Arweave’s endowment model — you pay once, the network is funded to store your data for roughly 200 years — is the only production system that comes close to this guarantee for arbitrary artifacts.
Verifiable by anyone, not just by the publisher. A signature from the publishing organization tells you the artifact was signed by someone with access to that organization’s signing key. It doesn’t tell you the key wasn’t compromised, the signing process wasn’t automated without review, or the manifest wasn’t altered after signing. Verification needs to be independent of trusting the publisher.
Machine-readable policy, not just machine-readable content. A signed artifact tells a machine “this hasn’t been tampered with.” A manifest with a policy block tells a machine “here’s what to do with it, here’s what rollback looks like, here’s what signatures are required before deployment.” The difference matters as agents become deployment actors.
Lesson: location trust (“it came from GitHub/npm/Docker Hub”) is not content trust. Agents need the latter.
The architecture
The system has four layers. Each handles a distinct part of the problem. None of them require the others to work — you can adopt them incrementally — but they’re designed to compose.
| Layer | Job | Technology |
|---|---|---|
| 1 Collaboration | Day-to-day git, review, issues | Radicle (+ GitHub mirror) |
| 2 Staging / builds | Content-addressed WIP + agent workspaces | IPFS + Rift (CoW) |
| 3 Official releases | Permanent canonical artifacts | Arweave |
| 4 Release tooling | Bundle, publish, verify, pull | clawql-release CLI |
Layer 1: Collaboration — Radicle with GitHub as a mirror
Day-to-day development — branches, pull requests, code review, issues — happens on Radicle, a peer-to-peer Git-compatible collaboration network. Radicle gives every contributor a cryptographic identity, replicates repositories directly between peers without a central server, and doesn’t have a single operator who can take the service down, rewrite history, or be compelled to delete your project.
GitHub stays in the picture as a read-only mirror. Your project is still discoverable on GitHub, still cloneable, still star-able. The mirror displays a banner pointing to the canonical Arweave source for anything that matters for verification. From the outside, your project looks identical to any other GitHub project. The difference is structural.
Why Radicle and not a self-hosted Git server?
A self-hosted Forgejo or Gitea instance is a real improvement over depending on GitHub specifically. It’s not the same thing as removing the single-point-of-failure property. Whoever runs the server can still rewrite history, take it down, or have their infrastructure compromised. You’ve reduced the attack surface but not eliminated the architectural vulnerability.
Radicle’s advantage is that it provides the collaboration layer — patches, issues, code review — and peer-to-peer replication with cryptographic identity, without a central operator. The honest tradeoffs: Radicle is less mature than GitHub or GitLab, most developers haven’t used it, and its long-term maintenance trajectory is worth watching. This is why Radicle sits at the collaboration layer, not the trust layer. The trust guarantees in this architecture live in Arweave’s content-addressed permanent storage and in cryptographic signatures — not in whatever network hosts your git history. If Radicle’s ecosystem doesn’t pan out, switching collaboration tools is bounded. Your releases remain permanent and verifiable regardless.
For teams that aren’t ready for Radicle, starting with GitHub as the collaboration layer and adding Arweave for releases is a completely valid first step. Layer 1 is the most optional piece of this architecture.
Layer 2: Staging and build environments — IPFS and Rift
In-progress branches, CI build artifacts, and build environments live on IPFS — content-addressed storage where files are identified by a hash of their contents, making tampering immediately detectable.
For build environments specifically, the recommended tool is Rift, which uses copy-on-write filesystem features (btrfs on Linux, APFS on macOS) to create isolated, instantly-available workspaces:
git worktree |
Rift | |
|---|---|---|
| Time to create a workspace | Seconds (full checkout) | Under 0.1 seconds |
| Extra disk space used | High (full copy) | Near-zero until files change |
| Running many agents in parallel | Painful — shared lock files, node_modules conflicts |
Straightforward |
| Immutability | None | Built in — every snapshot has a parent and timestamp |
| Build reproducibility | Hard to guarantee | Snapshot ancestry recorded in manifest |
Rift is early-stage and maintained by a separate project. If it doesn’t work for your setup, git worktree is always a valid fallback — everything downstream works with either. The --backend flag on the CLI makes this explicit.
What Rift solves that git worktree doesn’t: when you run many AI agents in parallel — each working on a different task in an isolated environment — you need environments that spin up in milliseconds, consume near-zero disk until they diverge from the parent, and produce an auditable chain of parent→child snapshots. This is the same problem macOS snapshot-based backups and Kubernetes pod isolation solve for their respective domains. Rift brings it to developer workspaces.
Agent-native workflow in one sentence: local CoW workspaces (Rift) → content-addressed staging (IPFS) → permanent release (Arweave) with a policy-bearing manifest your cluster and agents can enforce.
Layer 3: Official releases — Arweave
This is the core of the system.
When you tag a release, the CLI bundles everything that matters — source code, container images, Helm charts, a CycloneDX SBOM, Cosign signatures, and SLSA attestations — and uploads it once to Arweave. The resulting transaction ID becomes the permanent, canonical identifier for that release. Anyone can fetch that exact release from any Arweave gateway, indefinitely, and verify it matches what was originally published.
What does this cost?
Arweave pricing is approximately $6–12 per gigabyte, paid once:
| Release contents | Approximate cost |
|---|---|
| Source + signatures only (~10 MB) | ~$0.07 |
| Source + container image + SBOM (~100 MB) | ~$0.70 |
| Full release with large images (~500 MB) | ~$3.50 |
| Large monorepo bundle (~1 GB) | ~$7–10 |
For most projects, a release costs under a dollar. Compare that to the cost of responding to a supply chain incident — the economics aren’t close.
Why Arweave and not S3 with versioning, or IPFS pinning?
S3 versioning keeps old versions but doesn’t prevent the account holder from deleting them. Your security doesn’t depend on whether the hosting organization keeps paying their AWS bill or decides to remove your project. IPFS is content-addressed but doesn’t guarantee persistence — content is available as long as someone is pinning it. Pinning services are businesses that can shut down, be compelled to remove content, or be compromised. Arweave’s endowment model is different: you pay once, the endowment funds replication for the long term, and no single operator can delete what’s been published.
The honest caveat: the endowment model works as long as the cryptoeconomic assumptions hold over a very long time horizon. For most teams, the practical comparison isn’t “Arweave vs. perfect permanent storage” — it’s “Arweave vs. GitHub releases that can be deleted.” On that comparison, Arweave wins clearly.
Layer 4: The release CLI — clawql-release
clawql-release init
clawql-release immutable-volume snapshot [--backend rift|git-worktree|cloudflare|ebs]
clawql-release golden-image build
clawql-release publish --tag v2.1.0
clawql-release verify [tx-id]
clawql-release pull [--rift]
Open source, TypeScript, works with or without Rift. The --backend git-worktree flag means there’s no hard dependency on any part of the stack you haven’t adopted yet.
The release manifest: the part that changes your deployment model
Every upload to Arweave includes a manifest — a compact JSON document that turns a pile of binary artifacts into something a machine can reason about:
{
"version": "2.1.0",
"merkleRoot": "8f3a9b...",
"artifacts": {
"source": { "cid": "bafy...", "sha256": "a1b2..." },
"image": { "cid": "bafy...", "sha256": "c3d4...", "ref": "myapp:2.1.0" },
"sbom": { "cid": "bafy...", "format": "spdx-json" }
},
"buildEnvironment": {
"type": "rift",
"snapshotId": "snap_8821",
"parentSnapshotId": "snap_8790",
"createdAt": "2026-06-01T14:22:00Z"
},
"policy": {
"requireSignatures": ["build-pipeline", "security-review"],
"canaryPercent": 5,
"blastRadiusCap": "single-region",
"rollback": {
"previousRelease": "tx_7f2a9c...",
"trigger": "error_rate > 1% for 5min"
}
},
"compatiblePolicyVersion": "1.0"
}
This isn’t just metadata. It’s a contract. Here’s what each section enables:
merkleRoot — tamper detection without trusting anyone.
The Merkle root covers every artifact in the bundle. Change one byte of anything — source code, the image, the SBOM — and the root no longer matches. Anyone can verify this independently, using only the transaction ID and standard cryptographic libraries. No API call to a verification service. No trust in ClawQL, Arweave, or any other operator. Just math.
This is fundamentally different from “the artifact was signed by the publisher.” A signature tells you the artifact was produced by someone with the signing key. A Merkle root tells you the artifact hasn’t changed since it was published, verified by anyone who has the content.
buildEnvironment — reproducible builds with a verifiable chain.
The snapshot ancestry records exactly which build environment produced this release, with a link back to its parent. This is the answer to “can you prove what built this?” The chain is: parent snapshot → this snapshot → these artifacts → this Merkle root → this Arweave transaction ID. Each link is verifiable independently. That is how Rift’s CoW workspaces become supply-chain evidence rather than a developer convenience.
policy — machine-readable deployment instructions.
This is the piece that changes deployment for AI agents and automated pipelines. A Kubernetes admission controller running Kyverno or OPA Gatekeeper can read the policy block and:
- Refuse to deploy anything that doesn’t satisfy
requireSignatures - Automatically configure a canary rollout at
canaryPercent - Know exactly what to roll back to and under what conditions when
rollback.triggerfires - Enforce
blastRadiusCapbefore allowing multi-region deployment
An autonomous agent deploying this release doesn’t need to guess what’s safe. It reads the manifest and acts on structured instructions. Rollback isn’t “try to figure out what the previous version was” — it’s previousRelease: "tx_7f2a9c...", a permanent identifier pointing to a specific, verifiable state.
compatiblePolicyVersion — auditing against a known schema.
The manifest schema is versioned and publicly documented. Auditing a release means auditing against a known, stable schema — not reverse-engineering an opaque format that might mean different things at different times.
Lesson: signatures answer “who attested?” Merkle roots answer “did bytes move?” Policy blocks answer “what should a machine do next?” Agents need all three.
Private and paid releases
Public releases are uploaded unencrypted. Private or commercial releases add one step: the bundle is encrypted with XChaCha20-Poly1305 before upload, and the manifest declares which wallet address is authorized to decrypt.
For more complex access — “decrypt after payment,” “decrypt for wallets that hold this token,” “decrypt after a time delay” — the manifest can reference Lit Protocol, which handles conditional decryption based on on-chain state.
The x402 payment flow for an AI agent consuming a paid release:
const manifest = await clawql.verify(txId);
if (manifest.access.paymentRequired) {
// x402: HTTP-native stablecoin micropayment
const payment = await x402.pay({
amount: manifest.access.price, // e.g. "0.50 USDC"
recipient: manifest.access.wallet,
resource: txId,
});
// Payment receipt presented to Lit Protocol
// Decryption key released atomically on payment verification
const decryptionKey = await lit.requestKey({
condition: manifest.access.decryptCondition,
proof: payment.receipt,
});
const bundle = await clawql.decrypt(txId, decryptionKey);
}
The agent pays, receives a key, and decrypts — one atomic flow, no human approval step for routine low-value transactions. Whether that’s appropriate without human approval is a policy decision configured in the agent’s authorization model, not a decision baked into the payment infrastructure.
This opens a distribution channel that doesn’t exist in the current ecosystem: software that autonomous agents can discover, evaluate, purchase, and deploy without human involvement at each step, with full provenance and rollback capability throughout.
Honest failure modes
A system built around “permanent and trustworthy” has to be honest about where it can fail. Skipping this section is how security documentation becomes marketing copy.
An Arweave gateway is unreachable.
Arweave data is replicated across many independent gateways run by different operators. If one is down, clawql-release pull tries another. The transaction ID is a property of the network, not of any single server. In practice this is “occasionally slower,” not “occasionally unavailable.”
The AR token price changes dramatically. The endowment model is designed to fund storage even if the token’s value drops substantially. The real risk: this is a cryptoeconomic assumption that needs to hold over decades. The practical mitigation is keeping artifact sizes modest — the manifest, signatures, and source code are what need permanence; large binary blobs can be re-derived from source plus a recorded build environment. Even if the long-term endowment assumption eventually breaks, you have far more time to migrate than if your storage provider shuts down their S3 pricing.
A compromised signing key publishes a malicious manifest.
This is the most important failure mode because it’s the one an attacker would actually pursue. Suppose someone with valid signing credentials publishes a manifest that looks legitimate — correct signatures, valid Merkle root — but contains a policy block designed to do something harmful: a rollback.previousRelease pointing to an old vulnerable version, or a canaryPercent of 100 disguised as 5.
The defenses are layered:
The manifest schema is public and versioned, so an admission controller can validate that policy values are sane — a canaryPercent outside 0–100, or a rollback target that doesn’t itself verify — independent of whether signatures check out.
policy.requireSignatures should require multiple independent signers for production releases. A build pipeline signature alone is necessary but not sufficient. Treat signing credentials with the same rigor as production deployment credentials, because that’s what they now are. That connects directly to Hardened Agentic Stack Part 2: signing keys belong in Vault / HSM-backed exchange patterns, not in long-lived CI ENV dumps.
Because every release is permanent, a malicious release doesn’t erase legitimate history. The previous good release is still there, still verifiable, still pullable. “Permanent” cuts both ways, but in this case it means rollback targets can’t be quietly removed after the fact.
This is fundamentally a credential-compromise problem. The mitigation is the same as everywhere else: protect signing keys rigorously. What’s different is that the blast radius is bounded and auditable in a way that a quietly-rewritten Git tag is not.
The Radicle ecosystem doesn’t pan out. This is a real risk worth naming. Radicle is less mature than GitHub and its long-term maintenance trajectory is uncertain. The architectural response: trust guarantees don’t live in Radicle. If you need to migrate the collaboration layer, your releases — on Arweave, with their permanent transaction IDs — are completely unaffected. You can move to any git host tomorrow and your release history remains intact and verifiable. The collaboration layer and the trust layer are deliberately separated.
Why AI agents make this urgent
The supply chain verification problem existed before autonomous agents. Agents make it acute.
A human engineer who encounters a suspicious release can pause, consult colleagues, check the changelog, compare with a known-good state. They apply judgment that isn’t specified anywhere in advance. An agent deploying software has to operate on the information available in the release artifacts themselves. If that information doesn’t include policy, rollback instructions, and verifiable provenance, the agent either proceeds blindly or stops and waits for a human — which defeats the purpose of automation.
The manifest format described here is designed to be the information layer that agents need. Not just “this artifact hasn’t been tampered with” (which Merkle roots and signatures provide) but “here’s what to do with it, here’s what rollback looks like, here’s what conditions should trigger rollback, here’s what signatures are required before you deploy this.”
The XZ Utils backdoor in 2024 was embedded in a library over years by a patient attacker who built reputation and trust gradually before introducing the malicious change. A well-configured agent with access to this manifest format would have noticed: the signing key for the release was different from previous releases, the build environment snapshot had no ancestry chain, the policy block required signatures that weren’t present. Not every attacker is as patient or as careful about covering their tracks.
None of this is a silver bullet. A sophisticated attacker who compromises the entire signing infrastructure can produce a valid manifest with valid signatures. But the marginal attacker — the one who compromises one account, or pushes a dependency update that nobody will notice — has a much harder time in a world where admission controllers validate every manifest field before deployment.
The release workflow
# One-time setup
rift init
clawql-release init
# Day-to-day — unchanged from your current workflow
rift create --name feature-42
cd .rifts/feature-42
# edit, test, commit as normal
# When ready to ship
clawql-release immutable-volume snapshot --backend rift --name build-2026-06-01
clawql-release golden-image build # produces signed images, SBOMs, attestations
clawql-release publish --tag v2.1.0 # uploads to Arweave, updates GitHub mirror banner
# Consuming a release anywhere
clawql-release pull --rift # verifies manifest + signatures, decrypts if needed
clawql-release verify tx_abc123 # verify any existing release by transaction ID
Teams not using Rift run the same commands with --backend git-worktree. Nothing changes about steps before publish.
Comparison: what this changes
| Typical GitHub + CI | This architecture | |
|---|---|---|
| Can a release be silently changed after publishing? | Yes — tags can move | No — Arweave transactions are permanent |
| Can you prove what build environment produced a release? | Usually not | Yes — snapshot ancestry in the manifest |
| Can a Kubernetes cluster enforce deployment policy automatically? | Only with custom tooling | Yes — manifest is machine-readable |
| Can an AI agent verify, purchase, and consume a release autonomously? | Not designed for this | Yes — first-class with x402 payment flow |
| Running many isolated build environments in parallel | Painful | Trivial with Rift |
| Private and paid releases | Requires custom infrastructure | Built in — XChaCha20 + Lit Protocol |
| How long does the release last? | As long as the platform exists | ~200 years (Arweave endowment model) |
| Effort to adopt Layer 3 (releases) | — | One CLI, thirty minutes, one dollar |
Adoption path
Nothing here requires an all-or-nothing migration.
Day zero: Add clawql-release alongside your existing GitHub workflow. Nothing about how you develop or review code changes.
First release: Run clawql-release publish --tag v2.1.0. Your release is now permanent and verifiable. GitHub still works exactly as before. Your users won’t notice anything different, except that this release can never be silently altered and the manifest is machine-readable.
When it makes sense: Adopt Rift for faster, isolated build environments — particularly useful if you’re running multiple AI agents in parallel. Or don’t — git worktree works indefinitely.
When it makes sense: Move day-to-day collaboration to Radicle for full peer-to-peer operation. Keep GitHub as a mirror for as long as you want.
The only required step for most teams is publishing the first release. Everything else is optional hardening you adopt when it solves a problem you actually have.
What this looks like in a real CI pipeline
For teams running GitHub Actions today, adding permanent releases is a single new job:
jobs:
release:
needs: [build, test, sign]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install clawql-release
run: npm install -g clawql-release
- name: Initialize release
run: clawql-release init
- name: Build golden image
run: clawql-release golden-image build
- name: Publish to Arweave
run: clawql-release publish --tag ${{ github.ref_name }}
env:
AR_WALLET_KEY: ${{ secrets.ARWEAVE_WALLET_KEY }}
COSIGN_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
- name: Output transaction ID
run: echo "Release published at $ARWEAVE_TX_ID"
The transaction ID goes into your release notes, your changelog, and wherever you track canonical release identifiers. It’s the permanent reference that replaces “check GitHub releases” for anything that needs to be verifiable.
Conclusion: the trust layer is missing from most release pipelines
The software supply chain problem isn’t that publishing tools are bad. GitHub releases, npm, Docker Hub — these are excellent for distribution and discovery. The problem is that they were designed for human trust, not for machine verification.
Humans can ask “does this seem right?” Machines need to ask “can I verify this is right?” Those are different questions, and the second one requires a different set of answers: content addresses that don’t depend on location, permanent storage that doesn’t depend on any operator’s continued existence, manifests that declare policy in a format admission controllers and agents can read directly.
The architecture described here addresses all of these. It doesn’t require abandoning the tools you already use. It requires one CLI, a dollar per release, and a manifest format that you define once and maintain in version control.
Local agent workspaces via Rift (CoW) give you isolated, snapshot-chained builds. IPFS keeps staging content-addressed. Arweave makes the published release censorship-resistant and permanent. The manifest makes that permanence actionable for clusters and agents.
The XZ Utils backdoor, the LiteLLM supply chain compromise, the colors sabotage — these succeeded because the artifacts being distributed were trusted without verification. That’s the property worth changing.
The clawql-release CLI and manifest schema live in ClawQL. Full platform context: Immutable Releases.