diff --git a/CHANGELOG.md b/CHANGELOG.md index 44233a1..b970a71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ draft, so pin a conformance claim to a commit or date. ## [Unreleased] +## [0.2.0] - 2026-10-22 + ### Added - **A one-line install for the `asdd` CLI.** `sh -c "$(curl -fsSL .../releases/latest/download/install.sh)"` (add `sh --version X.Y.Z` after it to pin, in CI) downloads a release archive, verifies its SHA-256, checks that it holds @@ -15,7 +17,8 @@ draft, so pin a conformance claim to a commit or date. `/versions/X.Y.Z` trees carrying its own marker, and has an `uninstall`. A new `release.yml` builds the archive from a `vX.Y.Z` tag, installs from it, and only then publishes. The installer's tests run it confined (fake `HOME`, an `rm` shim, and an OS sandbox on macOS), and `install.mutation.sh` removes each - safety check in turn and requires the tests to fail. + safety check in turn and requires the tests to fail. The install guide and the pages that told readers to + `pip install` now document it. - **The audit trail is complete: every agent's records reach the sink, not only the reviewer's.** Before, only the review exported, so a deployment that turned on `audit.sink` captured the reviewer's decisions but lost the produce side (the developer/council "coding"), the test and documentation agents, and the @@ -154,4 +157,5 @@ Initial public release. runtime does and records each run). The tester never runs automatically on an untrusted open PR. - Optional profiles: **Assure** (integrity attestation) and the **spec-driven** profile. +[0.2.0]: https://github.com/OneHillAI/ASDD/releases/tag/v0.2.0 [0.1.0]: https://github.com/OneHillAI/ASDD/releases/tag/v0.1.0 diff --git a/README.md b/README.md index 9e17cf0..231d4f0 100644 --- a/README.md +++ b/README.md @@ -77,10 +77,10 @@ sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/i asdd init --goose /path/to/your-repo ``` -The installer puts `asdd` in `~/.local/bin` and keeps each version under `~/.asdd/versions/`. Before it installs anything it checks the archive's SHA-256, checks that the archive holds one `asdd-X.Y.Z/` tree with no absolute paths, `..` or links, and runs the extracted CLI once to confirm the version. It never overwrites an `asdd` or a directory it did not create, and `sh install.sh uninstall` removes only what it installed. To pin a version in CI, add one step; the installer puts its bin directory on `$GITHUB_PATH` for the steps after it: +The installer puts `asdd` in `~/.local/bin` and keeps each version under `~/.asdd/versions/`. It checks the archive's SHA-256 and layout before installing anything, never overwrites an `asdd` or a directory it did not create, and running the same command with `sh uninstall` at the end removes only what it installed. The [install guide](docs/guides/deploy.md#2-scaffold-asdd-into-your-repo) lists every check. To pin a version in CI, add one step; the installer puts its bin directory on `$GITHUB_PATH` for the steps after it: ```yaml -- run: sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/install.sh)" sh --version 0.1.0 +- run: sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/install.sh)" sh --version 0.2.0 - run: asdd doctor ``` diff --git a/asdd_cli.py b/asdd_cli.py index 2671321..a015eff 100755 --- a/asdd_cli.py +++ b/asdd_cli.py @@ -15,7 +15,7 @@ import subprocess import sys -__version__ = "0.1.0" # keep in sync with pyproject.toml +__version__ = "0.2.0" # keep in sync with pyproject.toml HERE = os.path.dirname(os.path.realpath(__file__)) # realpath: a symlink resolves to the checkout diff --git a/cli/README.md b/cli/README.md index acb9d82..f1b36b6 100644 --- a/cli/README.md +++ b/cli/README.md @@ -3,7 +3,9 @@ ## asdd (the unified CLI) One command for the whole toolkit, so you don't call the scripts by path. It dispatches to the -tools below (which stay the single source of truth). Put it on your PATH by symlinking the launcher +tools below (which stay the single source of truth). To install a release, use the one-line installer +(`sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/install.sh)"`; see the +[install guide](../docs/guides/deploy.md#2-scaffold-asdd-into-your-repo)). From a checkout, put it on your PATH by symlinking the launcher (`ln -s "$PWD/asdd_cli.py" ~/.local/bin/asdd`; it resolves the symlink to find the tools) or, with a recent pip, `pip install -e .`. Or run it straight from a checkout: `python3 asdd_cli.py `. See the [Goose quickstart](../docs/guides/operate-goose.md) for the end-to-end setup. diff --git a/cli/asdd-mcp.py b/cli/asdd-mcp.py index 3096e5a..973d84f 100755 --- a/cli/asdd-mcp.py +++ b/cli/asdd-mcp.py @@ -193,7 +193,7 @@ def main(): if method == "initialize": result = {"protocolVersion": msg.get("params", {}).get("protocolVersion", "2025-06-18"), "capabilities": {"tools": {}}, - "serverInfo": {"name": "asdd-gates", "version": "0.1.0"}} + "serverInfo": {"name": "asdd-gates", "version": "0.2.0"}} elif method == "notifications/initialized": continue elif method == "ping": diff --git a/docs/guides/adopt-govern.md b/docs/guides/adopt-govern.md index f496b82..9244c89 100644 --- a/docs/guides/adopt-govern.md +++ b/docs/guides/adopt-govern.md @@ -9,11 +9,12 @@ covered by [operate-goose](operate-goose.md) and [operate-other](operate-other.m Install the CLI, then scaffold your repo: ```bash -pip install git+https://github.com/OneHillAI/ASDD +sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/install.sh)" asdd init /path/to/your-repo ``` -Or run `bash cli/init.sh /path/to/your-repo` from a checkout. +To pin the version in CI, see [Install in CI](deploy.md#install-in-ci). Or run +`bash cli/init.sh /path/to/your-repo` from a checkout. It writes [`AGENTS.md`](https://github.com/OneHillAI/ASDD/blob/main/AGENTS.md) (the constitution), `.asdd.yml` (config), the PR template (the disclosure block), and `CODEOWNERS` from your protected paths, and ensures the lane labels. Add `--goose` diff --git a/docs/guides/deploy.md b/docs/guides/deploy.md index fdd5fde..bdca025 100644 --- a/docs/guides/deploy.md +++ b/docs/guides/deploy.md @@ -51,11 +51,39 @@ The ASDD recipes are provider-neutral; you set the model per run. See Install the CLI, then scaffold your repo: ```bash -pip install git+https://github.com/OneHillAI/ASDD +sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/install.sh)" asdd init --goose /path/to/your-repo ``` -Or run `bash cli/init.sh --goose /path/to/your-repo` from a checkout. +The installer puts `asdd` in `~/.local/bin` and keeps each version under `~/.asdd/versions/`. Flags go after the +command: `--version X.Y.Z` pins a release, and `--prefix DIR` and `--bin-dir DIR` change those two locations, for +example `sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/install.sh)" sh --prefix DIR`. To remove it, run the same command with `sh uninstall` +at the end; it removes what it installed and nothing else. + +### Install in CI + +Pin a version so a pipeline never changes under you. The installer adds its bin directory to `$GITHUB_PATH`, so +the steps after it can call `asdd`: + +```yaml +- run: sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/install.sh)" sh --version 0.2.0 +- run: asdd doctor +``` + +### What the installer checks + +Before it installs anything it downloads the release archive and its SHA-256 and stops if they differ. It also +stops if the archive holds anything but one `asdd-X.Y.Z/` tree, if a path is absolute or contains `..`, or if the +archive contains links. It then runs the extracted CLI once and stops unless it reports the version you asked for. +It never overwrites an `asdd` launcher or a directory it did not create, never edits your shell profile, and never +uses `sudo`. + +The checksum and the archive come from the same release, so the checksum catches a corrupted or swapped download +but does not prove who published it. Pin a version, and read +[`install.sh`](https://github.com/OneHillAI/ASDD/blob/main/install.sh) first if you want to be sure what it does. + +To skip the installer, `pip install git+https://github.com/OneHillAI/ASDD` works, or run +`bash cli/init.sh --goose /path/to/your-repo` from a checkout. This writes the constitution (`AGENTS.md`) and a pointer to it for the common assistants (`CLAUDE.md`, `.cursor/rules/asdd.mdc`; Codex reads `AGENTS.md` directly), `.asdd.yml`, the PR template and `CODEOWNERS`, diff --git a/docs/guides/operate-goose.md b/docs/guides/operate-goose.md index e9ab57a..78a25c2 100644 --- a/docs/guides/operate-goose.md +++ b/docs/guides/operate-goose.md @@ -16,7 +16,14 @@ Zero to a governed agentic-dev loop. You need Python 3.9+ and [Goose](https://bl ## 1. Get the CLI on your PATH -Clone ASDD, then either symlink the launcher (pip-free) or install it: +The quickest route is the one-line installer; it puts a pinned, checksum-verified release on your PATH +(see [the install guide](deploy.md#2-scaffold-asdd-into-your-repo)): + +```bash +sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/install.sh)" +``` + +To work from a checkout instead, clone ASDD, then either symlink the launcher (pip-free) or install it: ```bash ln -s "$PWD/asdd_cli.py" ~/.local/bin/asdd # pip-free; or, with a recent pip: pip install -e . diff --git a/docs/guides/slash-commands.md b/docs/guides/slash-commands.md index 58188cb..f9ccd51 100644 --- a/docs/guides/slash-commands.md +++ b/docs/guides/slash-commands.md @@ -30,8 +30,9 @@ feedback loop over the identical code, not a preview of it. Each command is a short Markdown prompt whose only job is to invoke a CLI subcommand and read back its output. To bring your assistant of choice: -1. Install the CLI: `pip install git+https://github.com/OneHillAI/ASDD` (or `pip install .` from a - checkout; the wheel is self-contained). +1. Install the CLI: `sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/install.sh)"` (see [the install guide](deploy.md#2-scaffold-asdd-into-your-repo)), + or `pip install git+https://github.com/OneHillAI/ASDD`, or `pip install .` from a checkout (the wheel is + self-contained). 2. Copy the four prompts from [`.claude/commands/asdd/`](../../.claude/commands/asdd/) into your assistant's command format. The bodies are plain instructions; only the file location and front matter are Claude-Code-specific. diff --git a/docs/specs/one-line-install.md b/docs/specs/one-line-install.md index c2c2049..5d15121 100644 --- a/docs/specs/one-line-install.md +++ b/docs/specs/one-line-install.md @@ -26,7 +26,8 @@ on. - `install.sh` (POSIX `sh`), its test `install.test.sh`, and a mutation check `install.mutation.sh`. - `.github/workflows/release.yml` and `.github/workflows/install-test.yml`. -- The README quick start and a changelog entry. +- The README quick start, the install guide (`docs/guides/deploy.md`) and the pages that tell a reader how to + install the CLI (`adopt-govern`, `slash-commands`, `operate-goose`, `cli/README.md`), and a changelog entry. ## Out of scope diff --git a/install.sh b/install.sh index c088a37..473e22d 100755 --- a/install.sh +++ b/install.sh @@ -2,12 +2,13 @@ # ASDD installer: one line puts the `asdd` CLI on a developer machine or a CI runner. # # sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/install.sh)" -# sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/install.sh)" sh --version 0.1.0 -# sh install.sh uninstall +# sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/install.sh)" sh --version 0.2.0 +# sh install.sh uninstall (from a saved copy of this file) +# sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/install.sh)" sh uninstall (without one) # # In GitHub Actions, add one step before anything that calls `asdd`; the installer puts its bin dir on # $GITHUB_PATH for you: -# - run: sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/install.sh)" sh --version 0.1.0 +# - run: sh -c "$(curl -fsSL https://github.com/OneHillAI/ASDD/releases/latest/download/install.sh)" sh --version 0.2.0 # # What it does: downloads a release archive, verifies its SHA-256, checks the archive holds nothing but one # `asdd-X.Y.Z/` tree (no absolute paths, no `..`, no links), runs the extracted CLI once to confirm it is the @@ -239,7 +240,7 @@ main() { case "$1" in --version) [ $# -ge 2 ] && [ -n "$2" ] || die "--version needs a value (a release version, X.Y.Z)" VERSION=${2#v} - [ -n "$VERSION" ] || die "'$2' is not a release version (expected X.Y.Z, for example 0.1.0)" + [ -n "$VERSION" ] || die "'$2' is not a release version (expected X.Y.Z, for example 0.2.0)" shift 2 ;; --prefix) [ $# -ge 2 ] && [ -n "$2" ] || die "--prefix needs a directory"; PREFIX=$2; shift 2 ;; --bin-dir) [ $# -ge 2 ] && [ -n "$2" ] || die "--bin-dir needs a directory"; BIN_DIR=$2; shift 2 ;; @@ -249,7 +250,7 @@ main() { done if [ -n "$VERSION" ]; then - is_release_version "$VERSION" || die "'$VERSION' is not a release version (expected X.Y.Z, for example 0.1.0)" # guard:version + is_release_version "$VERSION" || die "'$VERSION' is not a release version (expected X.Y.Z, for example 0.2.0)" # guard:version fi [ -n "$PREFIX" ] || { [ -n "${HOME:-}" ] || die "HOME is not set; pass --prefix"; PREFIX="$HOME/.asdd"; } [ -n "$BIN_DIR" ] || { [ -n "${HOME:-}" ] || die "HOME is not set; pass --bin-dir"; BIN_DIR="$HOME/.local/bin"; } diff --git a/pyproject.toml b/pyproject.toml index ffa2ffd..40d86f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ build-backend = "setuptools.build_meta" [project] name = "asdd" -version = "0.1.0" +version = "0.2.0" description = "The ASDD CLI: the deterministic gates, the installer, and the Goose MCP extension under one command" readme = "README.md" requires-python = ">=3.9"