feat(just): carry every ward exec verb in a repo-owned justfile #1048

Merged
coilysiren merged 1 commit from aos/claude/mg96 into main 2026-08-14 02:20:50 +00:00
Member

Spike for coilysiren/inbox#365. Additive, nothing removed, no CI switched.

Why

ward exec has good ergonomics, but routing a repo's whole build through it
makes the repo depend on out-of-band flight control. Clone this repo without
ward on PATH today and 69 verbs stop working. Ward should be mentioned in
passing, not be the build system.

What landed

  • justfile - all 69 verbs from .ward/ward.yaml, identical names and command lines.
  • docs/just-task-runner.md - usage, parity evidence, known gaps.

Generated once by a throwaway script that is deliberately not committed. No new
owned code, which was the point.

Verified on this branch

  • Verb sets are identical, 69 of 69, diffed against .ward/ward.yaml.
  • just agent-id runs, and resolves to the repo root when invoked from docs/, matching ward exec cwd normalization.
  • just agent-id -n 3 passes flags through with no -- separator, which is a strict ergonomic gain over ward exec agent-id -- -n 3.
  • just agent-terminal-test and just aos-lint pass.
  • just pre-commit-all is green, which also dogfoods the runner against the repo's own gate.

Notable findings

  • The corpus was already clean. Zero of 69 commands held shell metacharacters, braces, quotes, or newlines. Ward's own argv policy is what made removing ward mechanical.
  • Executable coupling is far smaller than the mention count. Real ward exec invocations are scripts/run-workflow-ward.sh, scripts/ci/aos-cli-release.sh, and the release workflow script asserted by tests/test_aos_cli_release.py. The other ~97 mentions are prose. .pre-commit-config.yaml has none, the two hits there are hook names.
  • Nothing depends on exec's audit or gate. No non-doc references to --audit-override-dirty or the clean-tree gate exist, so ward exec can be deleted later rather than reimplemented against justfiles.
  • just reads only the last comment line above a recipe. My first pass wrapped long descriptions and silently truncated agent-id's doc to a tail fragment. Descriptions now stay on one line.
  • 17 verb descriptions were rephrased off -- passthrough syntax. Real flags such as --dry-run and --seed were preserved, which is why this was not a blanket substitution.

Known gaps, stated rather than hidden

  • Duplication. Both files declare all 69 verbs, so a verb added to one will drift. That is the cost of keeping this additive.
  • just is absent from docker/dev-base/install-common.sh, the Homebrew formulae, and the Scoop bucket. It has to land in the dev-base image before any CI switches.
  • Recipes are @-prefixed, so the echoed-command trail is gone. just would otherwise print an unexpanded "$@" that misrepresents the real argv.
  • Argv pre-validation does not carry over. That is deliberate, since the containment boundary is the container, not the task runner.

One thing I could not do

docs/FEATURES.md sits at 3968 characters against its own 4000-character cap,
leaving 32 characters of headroom. A new inventory entry does not fit, so this
feature is undocumented there and the documentation-layout hook blocks any
addition. That collides with the "Keep FEATURES.md current" rule in AGENTS.md.
Splitting FEATURES.md is out of scope here and wants its own issue.

Open question

Whether the follow-up deletes commands: from .ward/ward.yaml and moves
agent: plus catalog: to .aos/aos.yaml, which is the direction inbox#365
points, or whether coexistence holds longer.

Spike for coilysiren/inbox#365. Additive, nothing removed, no CI switched. ## Why `ward exec` has good ergonomics, but routing a repo's whole build through it makes the repo depend on out-of-band flight control. Clone this repo without ward on `PATH` today and 69 verbs stop working. Ward should be mentioned in passing, not be the build system. ## What landed * `justfile` - all 69 verbs from `.ward/ward.yaml`, identical names and command lines. * `docs/just-task-runner.md` - usage, parity evidence, known gaps. Generated once by a throwaway script that is deliberately not committed. No new owned code, which was the point. ## Verified on this branch * Verb sets are identical, 69 of 69, diffed against `.ward/ward.yaml`. * `just agent-id` runs, and resolves to the repo root when invoked from `docs/`, matching `ward exec` cwd normalization. * `just agent-id -n 3` passes flags through with no `--` separator, which is a strict ergonomic gain over `ward exec agent-id -- -n 3`. * `just agent-terminal-test` and `just aos-lint` pass. * `just pre-commit-all` is green, which also dogfoods the runner against the repo's own gate. ## Notable findings * The corpus was already clean. Zero of 69 commands held shell metacharacters, braces, quotes, or newlines. Ward's own argv policy is what made removing ward mechanical. * Executable coupling is far smaller than the mention count. Real `ward exec` invocations are `scripts/run-workflow-ward.sh`, `scripts/ci/aos-cli-release.sh`, and the release workflow script asserted by `tests/test_aos_cli_release.py`. The other ~97 mentions are prose. `.pre-commit-config.yaml` has none, the two hits there are hook names. * Nothing depends on exec's audit or gate. No non-doc references to `--audit-override-dirty` or the clean-tree gate exist, so `ward exec` can be deleted later rather than reimplemented against justfiles. * `just` reads only the **last** comment line above a recipe. My first pass wrapped long descriptions and silently truncated `agent-id`'s doc to a tail fragment. Descriptions now stay on one line. * 17 verb descriptions were rephrased off `--` passthrough syntax. Real flags such as `--dry-run` and `--seed` were preserved, which is why this was not a blanket substitution. ## Known gaps, stated rather than hidden * Duplication. Both files declare all 69 verbs, so a verb added to one will drift. That is the cost of keeping this additive. * `just` is absent from `docker/dev-base/install-common.sh`, the Homebrew formulae, and the Scoop bucket. It has to land in the dev-base image before any CI switches. * Recipes are `@`-prefixed, so the echoed-command trail is gone. just would otherwise print an unexpanded `"$@"` that misrepresents the real argv. * Argv pre-validation does not carry over. That is deliberate, since the containment boundary is the container, not the task runner. ## One thing I could not do `docs/FEATURES.md` sits at 3968 characters against its own 4000-character cap, leaving 32 characters of headroom. A new inventory entry does not fit, so this feature is undocumented there and the `documentation-layout` hook blocks any addition. That collides with the "Keep FEATURES.md current" rule in AGENTS.md. Splitting FEATURES.md is out of scope here and wants its own issue. ## Open question Whether the follow-up deletes `commands:` from `.ward/ward.yaml` and moves `agent:` plus `catalog:` to `.aos/aos.yaml`, which is the direction inbox#365 points, or whether coexistence holds longer.
feat(just): carry every ward exec verb in a repo-owned justfile
All checks were successful
ci / aos-cli-tests (pull_request) Successful in 24s
ci / ward-doctor (pull_request) Successful in 13s
ci / gate (pull_request) Successful in 55s
d062175803
ward exec has good ergonomics, but routing a repo's whole build through it
makes the repo depend on out-of-band flight control. A clone without ward on
PATH cannot run its own tasks.

Adds a justfile with all 69 verbs from .ward/ward.yaml, identical names and
command lines. None of the 69 contained shell metacharacters, braces, quotes,
or newlines, so the conversion was mechanical: ward's own argv policy had
already normalized the corpus.

Additive only. .ward/ward.yaml stays, ward exec still works, no CI switched.

Refs coilysiren/inbox#365

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
coilysiren deleted branch aos/claude/mg96 2026-08-14 02:20:51 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agentic-os!1048
No description provided.