Skip to content

feat: name an Outfit with alias/unalias and complete it with TAB - #18

Merged
outofcoffee merged 3 commits into
mainfrom
claude/outfit-alias-command-nimi9q
Jul 27, 2026
Merged

outofcoffee merged 3 commits into
mainfrom
claude/outfit-alias-command-nimi9q

Conversation

@outofcoffee

Copy link
Copy Markdown
Collaborator

Register an Outfit under a short name and use it anywhere a path goes, with tab completion for bash, zsh, and PowerShell.

Summary

  • outfit alias [path] registers an Outfit under a short name — by default its own ALIAS — and outfit unalias <name> drops it. The name then stands in wherever a path goes: apply, unapply, serve, and a leading argument to harness.
  • -n/--name overrides the name (required when the Outfit has no ALIAS), -F/--force re-points an existing name, and -l/--list shows every name with its path, marking any whose file has gone. outfit show grew an Aliases: section too.
  • outfit completion <bash|zsh|powershell> prints a tab-completion script. TAB completes commands, flags, providers, harnesses, and your registered aliases; outfit unalias <TAB> offers exactly the names you have.
  • The alias registry shares outfit's config file with the default-harness preference, so ownership of that file moves to a new leaf package internal/config where every write is read-modify-write and neither setting can clobber the other. harness keeps its LoadPreference/SavePreference API and delegates.
  • Docs (README, docs/outfit-file.md, AGENTS.md) and Homebrew completion install (.goreleaser.yaml) updated to match.

Implementation details

  • Resolution lives in one place. readOutfit is the choke point apply/unapply/serve/harness --outfit already share, so teaching it aliases gives every command the shorthand at once, with no change to those call sites.
  • A path on disk always beats a registered name. Every existing invocation passes a path, so this guarantees adding an alias can never change what an already-working command does; shadowing is reported rather than silent. The lookup is also gated on the argument being name-shaped, so a path-shaped argument never triggers a config read at all — which is what keeps serve (and the test suite) independent of outfit's own config.
  • The registry stores the Outfit file, not its directory, so serve's relative-PRESET resolution still lands next to an aliased Outfit.
  • harness positional. The first argument is taken as an Outfit only when no --outfit was given, flag parsing was not terminated by an explicit --, and it names one; a -- immediately after a consumed Outfit is dropped, so every other command line is forwarded byte-for-byte.
  • Completion is one source of truth. The hidden outfit __complete emits candidates plus a :nofile/:file/:dir directive; each shell script is a thin wrapper. bash tokenizes --outfit=foo on the = while zsh and PowerShell pass it whole, so the helper recognises both the split and attached --flag=value forms — the only way to complete --outfit/-O, whose value must be attached.

claude and others added 3 commits July 27, 2026 18:26
`outfit alias` registers an Outfit under a short name — by default its own
ALIAS — and that name then stands in wherever a path goes: apply, unapply,
serve, and a leading argument to harness. `outfit unalias` drops it.

Resolution lives in readOutfit, the choke point all four share, so one change
gives every command the shorthand. A path on disk always beats a registered
name, so adding an alias cannot change a command that already worked, and the
lookup is gated on the argument being name-shaped, so a path never causes a
config read at all. The registry stores the absolute path of the Outfit file
rather than its directory, which keeps serve's relative PRESET resolving next
to the aliased Outfit.

The registry shares outfit's config file with the default-harness preference,
so ownership of that file moves to a new leaf package, internal/config, where
every write is a read-modify-write and neither setting can clobber the other.
harness keeps its LoadPreference/SavePreference API and delegates.

Also adds `outfit completion bash`, which prints a completion script driven by
a hidden `outfit __complete`: TAB now offers commands, each command's flags,
providers, harnesses, and — the point — your registered alias names, listing
every match when several remain.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X2JtqNGP3SPhqeTzWFGf3G
`outfit completion` now prints a script for zsh and powershell as well as
bash. The `__complete` helper was already shell-agnostic — candidates plus a
:nofile/:file/:dir directive — so each shell needs only a thin script that
hands over the words and inserts a result.

The one shared change is in completions(): bash tokenizes `--outfit=foo` into
three words on the `=`, but zsh and powershell pass it as one, so the helper
now also recognises the attached `--flag=value` form. That makes `--outfit`/-O,
whose value must be attached, completable in every shell.

The zsh script doubles as a sourced script and an autoloaded `_outfit` in
$fpath; goreleaser now installs bash and zsh completions on `brew install`.
PowerShell is best-effort: it offers the same candidates and falls back to its
own path completion when none match.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0133vx4Ro9QiKySZTfgdF1rT
Two behaviour gaps on this branch went untested: completing --model/-m from
the catalogue (modelNames had no coverage at all), and the property that a
config outfit cannot parse still lets the harness launch — the leading word is
forwarded rather than erroring.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0133vx4Ro9QiKySZTfgdF1rT
@outofcoffee outofcoffee added the enhancement New feature or request label Jul 27, 2026
@outofcoffee
outofcoffee merged commit 6de3dcd into main Jul 27, 2026
1 check passed
@outofcoffee
outofcoffee deleted the claude/outfit-alias-command-nimi9q branch July 27, 2026 23:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants