This is the multi-page printable view of this section. .
Get Started
- 1: Installation
- 2: Quick Start
- 3: Your First Workspace
- 4: Core Concepts
SOW builds static RPM/YUM and DEB/APT repositories; it is not an HTTP daemon. Choose one of two isolated paths:
-
Plain:
sow createrebuilds indexes beside the packages in an ordinary directory. -
Managed: a workspace tracks package membership, Dists, architecture views, policy, signing, generations, audit history, and publication targets.
-
Installation — Choose a release archive, RPM/DEB package, or source build; verify the installed binary.
-
Quick Start — Create and serve a flat repository from a directory of packages.
-
First Workspace — Initialize Managed mode, create RPM and DEB Dists, add packages, build, and check.
-
Core Concepts — Workspace, Repository, Dist, Package Object, Desired Membership, and Built Generation.
Managed workspaces require a local POSIX filesystem with advisory locks, fsync, and atomic
rename semantics. Metadata generation is in-process; optional RPM package signing needs
rpm, while an agent:// metadata key needs gpg and gpg-agent.
1 - Installation
SOW is one executable: there is no service to enable and no runtime language environment.
Release builds target Linux and macOS on amd64 and arm64; Linux also gets RPM and DEB
packages. Windows is not supported.
Use the Download page to select the archive or Linux package that matches
your operating system and architecture. It links each published artifact, its source tag,
and SHA256SUMS.
Install an archive
Download one archive plus SHA256SUMS, then verify the matching line before extraction:
On macOS, select darwin_amd64 or darwin_arm64 and replace sha256sum -c - with
shasum -a 256 -c -. Without root, install to a directory already on your PATH, such
as ~/.local/bin.
Install a Linux package
Linux packages use the 1PGSTY release suffix:
Choose only the command and architecture that match the host. RPM installs the license at
/usr/share/licenses/sow/LICENSE; DEB installs copyright/license metadata under
/usr/share/doc/sow/.
Build from source
The module declares Go 1.27.0. Metadata generation needs no C toolchain. Replace
vX.Y.Z with the source tag linked from the Download page:
This uses the release build flags and embeds the selected tag’s product version.
Verify
sow version reports product version, target OS/architecture, and build Go toolchain.
sow help lists the command tree. Each archive also contains README.md, CHANGELOG.md,
and the Apache-2.0 LICENSE.
Upgrade a 0.3 Managed Workspace
SOW 0.4 introduces internal database schemas v11 and v12. The public layout and
schema: sow/v3 configuration identifier stay the same, but each existing v0.3 Repository must be
migrated explicitly before ordinary reads or writes. Stop Workspace writers before taking the
backup:
Repeat the last two commands for every Repository named in sow.yml. The database transition is
one-way; do not reopen a migrated Workspace with SOW 0.3. See
sow repo migrate for the repaired status, signer, and
publication evidence.
Permissions and optional tools
The invoking user needs read access to package inputs and write access to the Plain target or Managed workspace. Keep Managed workspaces on a local POSIX filesystem: locks, fsync, safe paths, and atomic rename are part of the correctness contract.
Repository parsing and metadata rendering are in-process. Only two optional paths need host tools:
- RPM package signing requires
rpmand a working GPG environment; - an
agent://metadata key requiresgpgandgpg-agent.
Next: Quick Start for Plain mode, or First Workspace for Managed mode.
2 - Quick Start
Plain mode builds a flat repository in one directory. It does not read sow.yml, create
a workspace, or keep a database.
Prepare a directory
Put RPM and/or DEB files at the directory top level. sow create does not recurse and
does not move or rename package files.
If one glob has no matches, copy the formats you actually have instead.
Generate metadata
An illustrative mixed-format result is:
The directory now contains:
Plain mode does not generate a DEB Release, InRelease, or Release.gpg. RPM and DEB
metadata are generated in one operation; a parse or render failure prevents the new
indexes from being committed.
Serve the directory
For a local check, any static file server is sufficient:
Verify the protocol entry points from another shell:
Python’s server is only a preview. Use a maintained HTTP server for persistent service.
Configure a client
Replace REPO_HOST with the address clients can reach.
Then refresh and install a package:
The APT source ends in ./ because this is a flat repository. [trusted=yes] and the
disabled DNF signature checks are appropriate only for this unsigned quick start. Use a
signed Managed repository when authenticity matters.
Update the repository
Change the package files and run the same command again:
The directory contents are the complete Plain-mode state. With unchanged package bytes,
the generated metadata is deterministic and a repeat run reports noop=true.
For automation, request the versioned JSON envelope:
When to use Managed mode
Use Plain mode when the directory already contains exactly what should be published. Use a Managed workspace when you need named Dists, architecture views, membership policy, signed metadata, generations, audit, or publication targets.
See also sow create and
Plain Flat Repositories.
3 - Your First Workspace
Managed mode keeps configuration, membership, generations, and audit state. This example starts from an empty directory.
Initialize the workspace
init creates:
Do not edit or serve .sow/. init is idempotent: rerunning it validates and converges
declared repositories and Dists; it does not reset a valid workspace.
The default architecture families are x86_64 and aarch64. Configuration accepts
amd64 and arm64 as aliases and normalizes them to those family names.
Create a Repository and two Dists
A Repository owns one public pool/ + dists/ tree and one private state database. A Dist
has exactly one format. dist new materializes a valid empty view, so empty clients receive
an empty index instead of a 404.
The public layout is now:
Add packages
Select the target Dist explicitly:
SOW reads identity and architecture from the package itself, stores accepted bytes under
local/pool/, updates Desired Membership, and builds affected Dists before returning.
The package path is only an input; later builds use the managed pool.
Use --skip to stage several membership changes without rebuilding each time, then
converge once:
While Desired Membership is ahead of the Built Generation, the Repository is dirty and
ready_to_copy=false.
Inspect and verify
status is a cheap state read. check is the delivery gate: it verifies configuration,
state, public modes, retained roots, package bytes, Desired Membership, indexes,
signatures, and the Generation manifest. It writes nothing. Only a clean Repository that
passes all layers returns success.
To see normalized configuration and defaults:
Serve the Repository
The public unit is /srv/sow/local, not the workspace root. Serve that directory at a
stable URL prefix; do not expose sow.yml or .sow/.
- DNF base URL:
https://repo.example.com/local/dists/el9/x86_64/ - APT source:
deb https://repo.example.com/local bookworm main
For a safe Nginx and filesystem-publication workflow, continue with Serve Repositories.
Selection rules
- Workspace: search upward from the current directory, or start from
-C DIR. - Repository:
-r NAME, the containing Repository, or the only configured Repository. - Dist:
-d NAME, repeatable; omission is accepted only when the command can resolve an unambiguous scope.
Ambiguity is an error; SOW does not pick an arbitrary Repository or Dist.
Next
4 - Core Concepts
Plain or Managed
The two execution paths are separate.
| Plain | Managed | |
|---|---|---|
| Entry point | sow create DIR |
init, repo, dist, add, rm, build |
| State | package directory | sow.yml plus private SQLite/journals |
| Public layout | flat RPM/DEB indexes | Repository pool/ + dists/ |
| Formats | RPM and DEB may share one directory | one format per Dist |
| Architecture views | no | yes |
| Policy and audit | no | yes |
| Metadata signing and publication targets | no | yes |
Choose Plain when directory contents already equal the desired repository. Choose Managed when SOW must own membership, policy, generations, signing, audit, or publication.
Managed hierarchy
- Workspace is the configuration and discovery boundary.
- Repository is the isolation, Generation, publication, and public-tree boundary. Repositories do not deduplicate payloads with one another.
- Dist is a named membership set in exactly one package format.
- Architecture view is derived output, not a second membership set.
noarchRPMs andallDEBs are selected into every applicable view without duplicating their pool bytes.
One canonical payload
A package object is identified by its exact-byte SHA-256. Its logical coordinate comes from the RPM header or DEB control data, not the filename.
Each accepted payload has one canonical path under the Repository pool/. RPM architecture
views contain repodata/ only; their package locations use parent-relative paths back to
the pool. APT Packages entries name the same pool directly.
Ordinary package clients and mirror tools are different contracts. Default dnf reposync
rejects the canonical RPM view’s parent traversal. When a self-contained RPM mirror leaf
is required, create a separate artifact with sow export rpm-leaf.
Desired and Built
Managed mode tracks intent and public bytes separately:
add and rm build affected Dists by default. --skip records membership changes but
leaves the Repository dirty; sow build later converges Desired into a new Built
Generation.
sow statusreads state cheaply and reportsready_to_copy.sow checkperforms the full, read-only delivery proof. Dirty or recovering state is not deliverable.sow changes [BASE_GENERATION]describes the physical difference between a recorded Generation and the current Built Generation. It is evidence and planning output, not a substitute for publication recovery or remote verification.sow publish TARGETpublishes a verified Generation through the configured provider and records target-scoped recovery/checkpoint state.
Transactions and failure states
Writes are serialized by Workspace or Repository locks and journal their intent before public mutation. Payloads and immutable metadata are prepared before mutable protocol pointers. A later writer recovers an interrupted operation before starting new work.
The operational states are:
| State | Meaning |
|---|---|
clean |
Desired and Built agree |
dirty |
Desired changed; Built is still the previous committed Generation |
recovering |
a nonterminal operation must be resolved |
error |
durable evidence conflicts; SOW refuses to guess |
Use status to diagnose and check as the release gate. Do not publish a Repository with
ready_to_copy=false.