ArchDoc Design record
ArchDoc

Release

Versions
History

Tagged versions build with goreleaser for linux, darwin and windows on amd64 and arm64. Archives are tar.gz, or zip for windows, named archdoc_<version>_<os>_<arch> with the binary archdoc at the archive root and LICENSE and README.md beside it. A checksums.txt of SHA-256 digests is published with them. A tag carrying a prerelease identifier publishes as a prerelease.

Every release, a prerelease included, also attaches archdoc_<version>_docs.tar.gz and install.sh, and checksums.txt lists both. goreleaser writes them before it builds, through a before hook running go run ./docs/build.go build/docs <tag> <full commit>, and attaches build/docs/* through extra_files on the release and the checksums. A generator that exits non-zero stops the release before anything is published.

The generator reads docs/guides/contents.json and the guides, and refuses a .md file under docs/guides/ that the contents do not list exactly once, a listed path that is not a .md file directly under it, contents with no sections, a section with no title or no guides, a guide with no title, a key the contents do not define or a second JSON value after them, a guide whose first line is ---, after any byte order mark, and a relative link in a guide that names anything but a listed guide, with or without a fragment, or a fragment alone. A link that opens with a scheme, such as https: or mailto:, is not relative. It runs archdoc reference, built from the same checkout with the tag as its version, reads PROCESS.md from internal/template and every file under schema/, and refuses an install.sh without exactly one line release=. It refuses an output directory holding anything but files named archdoc_*_docs.tar.gz and install.sh. All of this is read before the directory is emptied and written.

The bundle holds, at its root and as files only, manifest.json, reference.json, PROCESS.md, guides/<file>.md in the contents' order and schema/<type>/v<n>.json in path order, each entry dated the Unix epoch. manifest.json carries bundle, which is 1, version, the tag, commit, schemas, the export's and the reference's schema numbers, and sections, the contents with each path under guides/. install.sh is written with the line release= set to the tag, mode 0755.

install.sh is a POSIX shell script. Everything runs from a function called on its last line, so a download cut short runs nothing. It installs the release ARCHDOC_VERSION names, or else the one its release line sets, and exits non-zero naming the variable when neither is set, as in the repository's copy. It maps uname -s to linux or darwin and uname -m to amd64 or arm64, downloads archdoc_<version>_<os>_<arch>.tar.gz and checksums.txt into a temporary directory with curl or wget from ARCHDOC_DOWNLOAD_URL, or else the release's download URL, and checks the archive with sha256sum or shasum -a 256 against the line naming it. It installs into ARCHDOC_INSTALL_DIR, or else /usr/local/bin where writable, or else $HOME/.local/bin, creating the directory, refuses an archdoc there that is a symbolic link or a directory, and copies the binary to a name mktemp creates in the directory before renaming it over archdoc. It prints the release and the path, and warns when the directory is not on PATH. On exit it removes the temporary directory and any temporary file it left.

A test builds the generator and runs it against guides holding each fault in the contents and guides it refuses, checking its message and that the output directory is unchanged, and against the repository's guides, checking the bundle's entries, manifest and copies. Others run the rendered install.sh under sh against a local server, on Linux and macOS, and check that .goreleaser.yaml runs the generator into the directory both extra_files lists name.

archdoc --version prints the tag. The version resolves in order: the ldflag goreleaser sets at build time; the module version from runtime/debug.ReadBuildInfo, which go install ...@version and @latest populate; dev.

init records the resolved version in the generated workflow as the version input of archdochq/lint. A version that is not a release tag, including dev and a pseudo-version in any of the three shapes Go produces, is written as latest with a warning that the workflow is unpinned. archdochq/setup downloads the archive for the runner's platform and checksums.txt from the release into a temporary directory, verifies the archive against the checksums, and puts the binary on PATH. With latest, the tag is read from the redirect of the releases page's latest URL.

Asset names are fixed by .goreleaser.yaml and reconstructed by archdochq/setup, which the scaffolded workflow reaches through archdochq/lint. A test renders the archive name, the archive format, the checksum filename and the binary name from that file and compares them against the names the action expects. The action's own repository checks the other side, by downloading a real release on every run.

.pre-commit-hooks.yaml at the repository root defines three hooks for the pre-commit framework. archdoc-lint runs lint, and archdoc-index and archdoc-glossary regenerate INDEX.md and GLOSSARY.md, which stops the commit when either file changes. Each builds archdoc from source at the revision the user's configuration names, and runs from the repository root on every commit, whichever files it touches.

A stable release also writes archdochq/skills, which publishes the guides as skills. A job in the release workflow, run once the release is published and skipped for a tag carrying a prerelease identifier, checks out the tag and archdochq/skills, the second through the SKILLS_DEPLOY_KEY deploy key, and runs go run ./plugin/build.go against the second with the tag less its leading v. The generator refuses a directory holding the working directory, empties the one it is given except for .git, copies the skeleton under plugin/ without build.go, writes each guide to skills/<name>/SKILL.md and LICENSE beside them, and sets version in .claude-plugin/plugin.json, .cursor-plugin/plugin.json, plugin.json and gemini-extension.json. The job commits the result as github-actions[bot], tags the commit with a lightweight tag named for the release, and pushes the branch and the tag atomically.

The repository's own continuous integration runs gofmt, go vet, go test ./... and goreleaser check on push to main and on every pull request, and the release workflow runs the test suite before publishing, with the tag in ARCHDOC_RELEASE_TAG. Under it, a test refuses any rule entry whose since, or a change, names a release later than the tag, comparing by semantic version precedence, which orders a pre-release before the release it precedes. A refusal stops the workflow before goreleaser runs. Without the variable the test is skipped, and a test checks that the release workflow sets it.

The specification under spec/ is checked by a second workflow, which builds archdoc from the commit under test rather than downloading a release. It lints through archdochq/lint with no version input, which leaves the binary just built on PATH in place and annotates each finding on the line that caused it, then runs archdoc index --check against the same binary. It carries no version pin.

The module path is archdoc.dev, which is not where the code is hosted. archdoc.dev serves a go-import meta tag naming the GitHub repository, and the Go tool reads it to find the source: it asks for the full package path first and then shorter prefixes, so a tag at the site's root answers for archdoc.dev/cmd/archdoc too. Releases made before the path changed declare github.com/archdochq/archdoc and are installable only under that path.

ArchDoc is published from the archdochq organisation. The repository and the Homebrew tap were published under ollieread before that, and neither of those names is reused.

The licence is the GNU Affero General Public License, version 3 or later, and its text ships in every archive.

Source spec/release.md · commit aa43057 · exported