Skip to content

feat(alias): user-level shorthand names for module sources#37

Open
rickliujh wants to merge 1 commit into
mainfrom
feat/module-alias
Open

feat(alias): user-level shorthand names for module sources#37
rickliujh wants to merge 1 commit into
mainfrom
feat/module-alias

Conversation

@rickliujh

Copy link
Copy Markdown
Owner

Shortens long invocations. Instead of:

loom run git@github.com:foo/bar.git//modules/svc -p foo=bar -p something=anotherthing

you get:

loom alias add bar git@github.com:foo/bar.git//modules/svc -p foo=bar -p something=anotherthing
loom :bar                  # run it
loom :bar -p foo=other     # override a param
loom diff :bar             # preview it
loom alias list | remove

An alias maps a short name to a module source plus a set of default parameters.

Design notes

A leading : marks a reference. The sigil makes the alias namespace disjoint from the subcommand namespace, which is what lets loom :bar dispatch at top level: no bare name can shadow a subcommand, so a typo like loom rnu still gets cobra's usual unknown command error and "Did you mean: run" suggestion.

Top-level dispatch is an argv rewrite (loom :bar …loom run :bar …), not a root-level handler. A root handler was tried first and fails with unknown shorthand flag: 'p' — the run flags live on runCmd, so root dispatch would have to redeclare every one of them. The rewrite inherits the whole flag set for free.

Aliases are user-level only. One file at $LOOM_CONFIG_DIR/aliases.yaml, else <user config dir>/loom/aliases.yaml. No repo-local file and no upward search, so changing branch or directory can never change what an alias resolves to.

Aliases are never module configuration. Resolution happens at the CLI boundary; module.ResolveSource stays alias-blind, so spec.modules[].source cannot depend on whichever aliases an operator happens to have defined. Modules stay portable.

Alias params are the lowest-precedence source, beneath --params-file and -p. Module spec.params defaults still apply beneath all three.

Unknown aliases don't fall through to the git-URL path, so a mistyped alias reports a mistyped alias rather than a failed clone.

Scope

loom run and loom diff accept :<name>. loom validate and loom bulk deliberately do not: neither consumes alias params, validate resolves no remote sources at all today, and bulk embeds the source it is given into the module it generates — where a reference would resolve for nobody else. Extending them is additive.

Single-segment names only. The alias file is a flat map[name]Def, so multi-segment names (loom :svc onboard) remain a lookup-loop change rather than a schema change.

Testing

  • specs/alias.md defines AL1–AL13; spectrace passes, so every rule has a covering test.
  • Full suite green (go build, go vet, go test ./...).
  • Verified end-to-end against the built binary: add → list → loom :bar renders the templated output; -p overrides the alias param; loom :typo reports unknown alias "typo" (looked in …) with no clone attempt; loom : errors on the empty name; loom rnu still reports an unknown command; loom diff :bar previews.
  • gofmt flags only files that were already unformatted on main (pkg/generate, pkg/action, pkg/llm); none touched here.

🤖 Generated with Claude Code

An alias maps a short name to a module source plus default parameters, so
`loom run git@github.com:foo/bar.git -p foo=bar` becomes `loom :bar`.

A leading ":" marks an alias reference. Because the sigil makes the alias
namespace disjoint from the subcommand namespace, `loom :bar` can dispatch to
run without any bare name shadowing a subcommand — an unknown subcommand still
gets cobra's usual "unknown command" error and suggestions.

Top-level dispatch is an argv rewrite (`loom :bar` -> `loom run :bar`) rather
than a root-level handler, so the alias form inherits the whole `loom run` flag
set instead of having to redeclare it.

Aliases are user-level only: one file at $LOOM_CONFIG_DIR/aliases.yaml (else
<user config dir>/loom/aliases.yaml), with no repo-local file and no upward
search, so changing branch or directory can never change what an alias
resolves to. Resolution happens at the CLI boundary only — module.ResolveSource
stays alias-blind so spec.modules[].source cannot depend on the operator's
local aliases, keeping modules portable.

Alias params are the lowest-precedence source, beneath --params-file and -p.

Adds `loom alias add|list|remove` and specs/alias.md (AL1-AL13) with covering
tests. `loom validate` and `loom bulk` deliberately do not accept references:
neither consumes alias params, and bulk embeds its source into generated
modules where a reference would violate AL8.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant