Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .aps/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# The toolchain pin and runtime path defaults the global `aps` binary
# discovers by walking up from cwd. Explicit flags (--plans, ...) override.
cli_version: 0.8.1
cli_version: 0.9.0
profile: solo
plans_dir: plans/
docs_dir: docs/
Expand Down
62 changes: 61 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,70 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### Added

- **`aps release` (REL-005, Rust phase)** — `new` scaffolds a release record
from the template, `status` summarises a release's modules and work-item
completion, `notes` drafts markdown from Complete items since the previous
release, and `close` reads the prose release record plus the plan tree and
advances `Merged`/`Released` items to `Complete` with a release-evidence
line, reporting every item advanced or skipped. Dry-run is the default;
`--apply` mutates, and refuses a record that has not shipped unless
`--force`. The prose record drives the closeout — no JSON sidecar.
**Not yet in the bash or PowerShell CLIs**, so per D-039 the work item stays
In Progress until all three agree with shared-fixture coverage.

## [0.9.0] - 2026-09-12

**Release narrative:** [plans/releases/v0.9.0.md](./plans/releases/v0.9.0.md).

### Added

- **`aps update --global`** upgrades the machine-wide CLI at `~/.aps` (or
`$APS_HOME`) from GitHub releases. Project `aps update` is unchanged. Bash
and PowerShell `--global` no longer overwrite a native binary with the
script runtime.
script runtime. Fails closed rather than damaging a working install:
`--global` is rejected alongside a project directory, symlink payloads in
release archives are refused, and an unreadable native binary aborts the
update (CLI-003).
- **Release-plan lint in the bash and PowerShell CLIs (CIB-006)** — both
fallback linters now discover `plans/releases/v*.md` (excluding `README.md`
and the dotfile template) and apply R001–R004 with the same codes,
severities, and messages as the Rust binary. Release fixtures in the shared
parity suite pin the three-way identity. Previously these rules existed in
Rust only, so bash checked 42 of this repo's 50 plan files and a malformed
release plan passed the fallback CLIs silently — closing the last known
D-039 lockstep gap.

### Fixed

- **`plan-doctor` no longer floods healthy plans with false warnings
(CIB-005)** — status is normalised through the documented alias table
(`Proposed` → `Draft`, `Done` → `Complete`) before any rule evaluates, W04
counts `Done` as terminal, the "no `NN-` filename prefix" half of W02 is
demoted to an Info code reported once per directory, and a consistently
applied undocumented status (`Archived` on archived index rows) reports under
its own Info code instead of W03. A consumer plan previously drew roughly 385
warnings with no real defects, which made the bundled skill unusable.
Resolves [#132](https://github.com/eddacraft/anvil-plan-spec/issues/132).
- **Installer manifests carry every bash rule module** — a rule module sourced
by `bin/aps` but absent from the installer file lists broke a vendored or
scaffolded bash CLI on startup with "No such file or directory". All fourteen
manifest sites now list `lib/rules/release.sh` (and `Release.psm1`), and a
new test derives the required list from `bin/aps` itself so the next rule
module cannot repeat it.
- **Dependency patches** — markdownlint-cli 0.49.1 pulls patched js-yaml,
linkify-it, and brace-expansion; the MCP SDK transitives are overridden to
patched hono, `@hono/node-server`, fast-uri, ip-address, and body-parser.
Together these resolve 17 Dependabot alerts.

### Changed

- **Plan accuracy sweep** — PROMPTS-001 and EXAMPLES-001 are marked Complete
(both had landed but the status lagged), the `prompts` and `examples` modules
close, `cli-redesign` moves Draft → In Progress, D-045 is recorded as decided
rather than proposed, and the roadmap overview is rewritten to match what
actually shipped through v0.8. The completed-work archive no longer files
v0.3.0–v0.7.0 task tables under an `Unreleased` heading; the missing
v0.4.0–v0.8.1 roll is tracked as ISS-012 against REL-005.

## [0.8.1] - 2026-07-31

Expand Down
50 changes: 30 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!-- markdownlint-disable MD041 -->

[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
[![Version](https://img.shields.io/badge/version-0.8.1-green.svg)](https://github.com/EddaCraft/anvil-plan-spec/releases/tag/v0.8.1)
[![Version](https://img.shields.io/badge/version-0.9.0-green.svg)](https://github.com/EddaCraft/anvil-plan-spec/releases/tag/v0.9.0)
[![Made for AI agents](https://img.shields.io/badge/made%20for-AI%20agents-purple.svg)](docs/ai-agent-guide.md)

<!-- markdownlint-enable MD041 -->
Expand Down Expand Up @@ -271,34 +271,44 @@ need one.

APS needs no hosted service, proprietary format, or mandatory integration.

## What's in v0.8.1

Patch release (**2026-07-31**) on top of v0.8.0's harness expansion:

- **Skill embeds carry YAML frontmatter:** the bundled `SKILL.md` files now
ship the `---`-delimited `name`/`description` block that Agent Skills
harnesses require to discover them — without it they silently skip the skill.
- **`aps update` respects the version pin:** update now gates on a
`cli_version` pin mismatch instead of refreshing against the wrong toolchain.

The v0.8.0 line (still current):

- **Seven new harnesses:** `init`/`setup`/wizard now support **Antigravity, Amp,
## What's in v0.9.0

Feature release (**2026-09-12**) — self-update and trustworthy diagnostics:

- **`aps update --global`:** the CLI upgrades itself. The machine-wide install
at `$APS_HOME/bin` (default `~/.aps/bin`) refreshes from GitHub releases,
while project `aps update` is unchanged. Fails closed rather than replacing a
working binary: symlink payloads in release archives are refused, and the
bash and PowerShell fallbacks never overwrite a native install with the
script runtime.
- **`plan-doctor` judges plans by the documented vocabulary:** status is
normalised through the accepted aliases (`Proposed` → `Draft`,
`Done` → `Complete`) before any rule evaluates, dependencies on `Done` items
count as terminal, and the filename-prefix check is advisory. A healthy plan
now reports clean instead of flagging every module.
- **Release-plan lint in all three CLIs:** the bash and PowerShell linters
discover `plans/releases/v*.md` and apply R001–R004 with the same codes and
messages as the Rust binary, pinned by release fixtures in the shared parity
suite. A malformed release plan can no longer pass the fallback CLIs.

The v0.8 line (still current):

- **Twelve harnesses:** `init`/`setup`/wizard support **Antigravity, Amp,
Gemini CLI, Windsurf, Roo Code, OpenClaw, and Cursor** alongside Claude Code,
Copilot, Codex, OpenCode, and Grok — twelve tools sharing one planning
contract. Each was added under the D-045 native-discovery gate (reads
`AGENTS.md` + auto-discovers the shared skill) at zero bespoke-asset cost, in
full Rust/bash/PowerShell parity.
- **Refreshed APS planning stack:** the bundled `aps-planning` skill and the
`aps-planner`/`aps-librarian`/`aps-conductor` agents are re-vended from the
canonical eddacraft source, and a new **`plan-doctor`** skill (structural plan
diagnostics) now installs alongside `aps-planning`.
- **Coherent command surface:** the CLI-001 redesign map (`update` vs `migrate`
vs `upgrade`, profile-aware surfacing) is recorded as the north star for
ongoing command-surface work.
canonical eddacraft source, and a **`plan-doctor`** skill (structural plan
diagnostics) installs alongside `aps-planning`.
- **Skill embeds carry YAML frontmatter:** bundled `SKILL.md` files ship the
`---`-delimited `name`/`description` block that Agent Skills harnesses
require to discover them.

Full notes: [CHANGELOG.md](CHANGELOG.md) ·
[release narrative](plans/releases/v0.8.1.md).
[release narrative](plans/releases/v0.9.0.md).

## Templates

Expand Down
19 changes: 10 additions & 9 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ to plan APS.

## Quick Overview

| Horizon | Focus | Status |
| --------------------- | ----------------------------------------------------------------- | ------- |
| **v0.2 Usability** | Scaffold, templates, docs, validation | Done |
| **v0.3 Distribution** | Install overhaul, multi-harness agents | Done |
| **Near Term** | Orchestration CLI (`next`/`start`/`complete`/`graph`), TUI wizard | Current |
| **Future** | Conductor agent, MCP server, GitHub Action, formal spec | Planned |

See [plans/index.aps.md](plans/index.aps.md) for the full breakdown with modules,
status, and work items.
| Horizon | Focus | Status |
| ------------------------- | ---------------------------------------------------------------------- | ------- |
| **v0.2 Usability** | Scaffold, templates, docs, validation | Done |
| **v0.3 Orchestration** | Orchestration CLI (`next`/`start`/`complete`/`graph`), multi-agent reach | Done |
| **v0.4 Distribution** | Crosscutting conductor modules, binary-first install, TUI wizard | Done |
| **v0.5–v0.6 Monorepo** | Federated nested plans, the tagged package tier, full-lifecycle tooling | Done |
| **v0.7 Team Foundations** | Managed skill freshness, JSON export, GitHub Action, MCP server | Done |
| **v0.8 Harnesses** | Twelve supported harnesses from one shared planning asset | Done |
| **Near Term** | Release tooling (`aps release`), plan-doctor accuracy, lint parity | Current |
| **Future** | Team coordination plane, progress journals, profile-aware CLI | Planned |

## Non-Goals

Expand Down
1 change: 1 addition & 0 deletions bin/aps
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ source "$LIB_DIR/rules/index.sh"
source "$LIB_DIR/rules/workitem.sh"
source "$LIB_DIR/rules/issues.sh"
source "$LIB_DIR/rules/design.sh"
source "$LIB_DIR/rules/release.sh"
source "$LIB_DIR/lint.sh"
source "$LIB_DIR/scaffold.sh"
source "$LIB_DIR/orchestrate.sh"
Expand Down
1 change: 1 addition & 0 deletions bin/aps.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Import-Module (Join-Path $RulesDir "Module.psm1") -Force -Global
Import-Module (Join-Path $RulesDir "Index.psm1") -Force -Global
Import-Module (Join-Path $RulesDir "Issues.psm1") -Force -Global
Import-Module (Join-Path $RulesDir "Design.psm1") -Force -Global
Import-Module (Join-Path $RulesDir "Release.psm1") -Force -Global
Import-Module (Join-Path $LibDir "Lint.psm1") -Force -Global
Import-Module (Join-Path $LibDir "Scaffold.psm1") -Force -Global

Expand Down
2 changes: 1 addition & 1 deletion cli/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "aps-cli"
version = "0.8.1"
version = "0.9.0"
edition = "2024"
license = "Apache-2.0"
description = "Anvil Plan Spec — native Rust CLI and TUI wizard"
Expand Down
1 change: 1 addition & 0 deletions cli/src/doctor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub const REQUIRED_LIB_FILES: &[&str] = &[
"rules/workitem.sh",
"rules/issues.sh",
"rules/design.sh",
"rules/release.sh",
];

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down
101 changes: 101 additions & 0 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod migrate;
mod next;
mod orchestrate;
mod parser;
mod release;
mod rollup;
mod scaffold;
mod self_update;
Expand Down Expand Up @@ -224,10 +225,73 @@ enum Command {
#[arg(long)]
json: bool,
},
/// Create, track, and close out release records under plans/releases/
Release {
#[command(subcommand)]
command: ReleaseCommand,
},
/// Diagnose migration state (global binary, cli_version, leftover CLI)
Doctor,
}

// `propagate_version` hands every subcommand an auto `--version` flag, which
// would collide with these positional `version` arguments. The release version
// is positional here, so the inherited flag is dropped.
#[derive(Subcommand)]
enum ReleaseCommand {
/// Create plans/releases/v<version>.md from the release template
#[command(disable_version_flag = true)]
New {
/// Release version (0.6.0 or v0.6.0)
version: String,
/// Plan root directory (default: plans)
#[arg(long, value_name = "DIR")]
plans: Option<String>,
},
/// Summarise work-item completion for a release (default: the newest)
#[command(disable_version_flag = true)]
Status {
/// Release version (default: the most recent record)
version: Option<String>,
/// Plan root directory (default: plans)
#[arg(long, value_name = "DIR")]
plans: Option<String>,
},
/// Draft markdown release notes from Complete items since the last release
#[command(disable_version_flag = true)]
Notes {
/// Release version (0.6.0 or v0.6.0)
version: String,
/// Plan root directory (default: plans)
#[arg(long, value_name = "DIR")]
plans: Option<String>,
},
/// Advance Merged/Released work items to Complete with release evidence
#[command(disable_version_flag = true)]
Close {
/// Release version (0.6.0 or v0.6.0)
version: String,
/// Write the changes (default: dry run)
#[arg(long)]
apply: bool,
/// Preview only — never modify files (the default)
#[arg(long)]
dry_run: bool,
/// Advance even when the record's Status is not Shipped/Released
#[arg(long)]
force: bool,
/// Tag commit for the evidence line (default: from the record's prose)
#[arg(long, value_name = "SHA")]
tag: Option<String>,
/// Release date for the evidence line (default: the record's ship date)
#[arg(long, value_name = "YYYY-MM-DD")]
date: Option<String>,
/// Plan root directory (default: plans)
#[arg(long, value_name = "DIR")]
plans: Option<String>,
},
}

fn main() {
let cli = Cli::parse();
match cli.command {
Expand Down Expand Up @@ -410,6 +474,43 @@ fn main() {
stale_days,
));
}
Some(Command::Release { command }) => {
let code = match command {
ReleaseCommand::New { version, plans } => {
let resolved = resolve_plans(plans, cli.strict, "aps release new");
release::cmd_release_new(&resolved, &version)
}
ReleaseCommand::Status { version, plans } => {
let resolved = resolve_plans(plans, cli.strict, "aps release status");
release::cmd_release_status(&resolved, version.as_deref())
}
ReleaseCommand::Notes { version, plans } => {
let resolved = resolve_plans(plans, cli.strict, "aps release notes");
release::cmd_release_notes(&resolved, &version)
}
ReleaseCommand::Close {
version,
apply,
dry_run,
force,
tag,
date,
plans,
} => {
let resolved = resolve_plans(plans, cli.strict, "aps release close");
// --dry-run is the default and always wins over --apply.
release::cmd_release_close(
&resolved,
&version,
apply && !dry_run,
force,
tag.as_deref(),
date.as_deref(),
)
}
};
std::process::exit(code);
}
Some(Command::Doctor) => {
let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
std::process::exit(doctor::run(&cwd));
Expand Down
1 change: 1 addition & 0 deletions cli/src/migrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const APS_LIB_FILES: &[&str] = &[
"rules/workitem.sh",
"rules/issues.sh",
"rules/design.sh",
"rules/release.sh",
];

/// True when every file under `dir` is a recognised APS bash-lib file — so the
Expand Down
Loading
Loading