Agent-First Slug v0.6: A Shape, Not a Sentence
afslug's CLI is now compiled from a closed-world registry: one source for argv parsing, typed values, legal combinations, help, and docs/cli.md. clap is gone. The visible payoff is that a constraint which used to live in a help sentence and a runtime check is now a shape the parser enforces and `--help` lists.
The previous release made afslug’s answers structured — help as a result, version as a result, errors routed separately from output. This one makes the question structured too.
It started as a forced move. afdata 0.27.0 deleted help-v1 and the
cli-help/cli-help-markdown features that afslug’s help layer was built on,
so afslug stopped resolving at all. The small fix was to port the help layer
onto whatever replaced it. The change made instead was to move the entire CLI
onto afdata’s cli-spec-v1 registry — one declaration that argv parsing, typed
values, legal combinations, output contracts, --help, and docs/cli.md are
all derived from. clap is dropped.
The constraint that was a sentence
afslug skill install writes the skill into an agent’s skills directory. It
takes --agent, which defaults to all, and --skills-dir, which names one
directory.
Those two arguments cannot both be meaningful. If the command is fanning out
across every agent it knows about, there is no single directory to write to —
each agent has its own. --skills-dir only means something when exactly one
agent is named.
Under clap that fact lived in two places, neither of them the parser: a sentence
in the help text, and a runtime check that ran after the command had already
been accepted. An agent reading --help had to notice the sentence, understand
it, and comply. Nothing structural stopped it from trying.
Now the command has two shapes, and --help returns both:
$ afslug skill install --help
skill-install-every-agent
Target every agent that supports the scope
afslug skill install [--agent all] [--scope <personal|workspace>] [--force] ...
skill-install-one-agent
Target one named agent; only this shape accepts --skills-dir
afslug skill install --agent <codex|claude-code|opencode|hermes>
[--scope ...] [--skills-dir <DIR>] [--force] ...
The combination that never made sense is not a documented mistake any more. It is absent from the grammar:
$ afslug skill install --agent all --skills-dir /tmp/skills
{"kind":"error","error":{"code":"cli_unregistered_combination",
"message":"arguments do not match a registered CLI combination",
"hint":"run `afslug skill install --help` and choose one registered combination"}}
status and uninstall split the same way, for the same reason.
This is the whole argument for a closed world. A CLI that accepts every combination of its flags and then rejects some of them at runtime has two specifications — the one the parser implements and the one the prose describes — and they drift. Registering the legal shapes collapses that into one, and the thing an agent reads before its first attempt is generated from the same source that judges the attempt.
Breaking changes
Stated plainly, because a caller pinning a caret range receives them automatically:
- No short flags exist.
-hand-Vwere clap-supplied aliases; both are nowcli_unknown_argument. Write--helpand--version. --recursiveand--output markdownare gone, replaced by--docs, which renders the whole reference document itself rather than making the caller assemble one from a recursive help dump.- Errors carry specific
cli_*codes —cli_unknown_argument,cli_unregistered_combination,cli_invalid_argument_value— instead of one genericcli_error. Branch on the code; it now says which kind of mistake the invocation made.
Nothing about slug generation changed. afslug still turns text into a slug
with the same charset options and the same output; this release is entirely
about how the command is described and parsed.
Getting it
$ brew install agentfirstkit/tap/afslug
$ cargo install agent-first-slug