Stack-specific subcommands — the subcommands/ directory feature documented in
docs/subcommands.md — cannot be invoked. The loader is triggered by a --stack
argument that the CLI no longer accepts, so every route to a stack's subcommand
ends in a Click error.
Found while checking whether the extension mechanisms are documented, after
#232. Same root cause family: a refactor moved --stack and left a consumer of
it behind.
Symptoms
With a stack that has subcommands/hello.py defining a command (verbatim from
docs/subcommands.md):
$ stack --stack .../stacks/example -h
Error: No such option: --stack
$ stack example-hello --stack .../stacks/example
Usage: stack example-hello [OPTIONS]
Error: No such option: --stack
$ stack example-hello
Error: No such command 'example-hello'.
The second form is the interesting one: example-hello resolved as a command, so
the discovery and registration in load_subcommands_from_stack() still work
fine. It then fails on the option itself. Without --stack anywhere in argv the
command is never registered at all. There is no third path — the argv scan is the
only trigger.
Cause
src/stack/main.py:105 registers the subcommands by scanning sys.argv for
--stack:
for i in range(len(sys.argv)):
arg = sys.argv[i]
if arg == "--stack":
if i + 1 < len(sys.argv):
stack_path = sys.argv[i + 1]
break
if stack_path:
load_subcommands_from_stack(cli, stack_path)
but --stack was removed from the CLI group in 171f6e9 ("74: Add checklist
command (#76)", 2025-07-08). It survives only as a per-command option on init,
deploy and friends, so Click rejects it on the group and on any dynamically
added subcommand.
Worth noting this is the second time: 5803b81 (2025-05-06) is titled "Restore
--stack option at top-level", so the same coupling broke once before and was
fixed by putting the group option back.
Fix
Re-adding --stack to the group would restore the documented invocation and
match what 5803b81 did, but it is worth deciding deliberately this time, since
the option now also exists per-command and the two would coexist
(stack --stack X init --stack Y becomes expressible). The alternative is to
give the loader a trigger that does not depend on a group option — resolving the
stack the same way the rest of the CLI now does, by name as well as path.
Either way the argv-scanning at import time is what makes this fragile: it
couples command registration to the spelling of an option it does not own, and
the except Exception around it means a failure prints a warning rather than
failing. That is worth revisiting alongside the fix.
Coverage
Nothing in CI invokes a stack subcommand, which is why this went unnoticed for
five weeks. A smoke-level test that registers a trivial subcommand and runs it
would catch both this and any future re-break; tests/skill/fixture already has
a fixture stack that could carry one.
Docs
docs/subcommands.md documents the stack --stack <path> -h form throughout,
including its example help output, so it needs updating with whatever invocation
the fix settles on.
Stack-specific subcommands — the
subcommands/directory feature documented indocs/subcommands.md— cannot be invoked. The loader is triggered by a--stackargument that the CLI no longer accepts, so every route to a stack's subcommand
ends in a Click error.
Found while checking whether the extension mechanisms are documented, after
#232. Same root cause family: a refactor moved
--stackand left a consumer ofit behind.
Symptoms
With a stack that has
subcommands/hello.pydefining acommand(verbatim fromdocs/subcommands.md):The second form is the interesting one:
example-helloresolved as a command, sothe discovery and registration in
load_subcommands_from_stack()still workfine. It then fails on the option itself. Without
--stackanywhere in argv thecommand is never registered at all. There is no third path — the argv scan is the
only trigger.
Cause
src/stack/main.py:105registers the subcommands by scanningsys.argvfor--stack:but
--stackwas removed from the CLI group in 171f6e9 ("74: Add checklistcommand (#76)", 2025-07-08). It survives only as a per-command option on
init,deployand friends, so Click rejects it on the group and on any dynamicallyadded subcommand.
Worth noting this is the second time: 5803b81 (2025-05-06) is titled "Restore
--stack option at top-level", so the same coupling broke once before and was
fixed by putting the group option back.
Fix
Re-adding
--stackto the group would restore the documented invocation andmatch what 5803b81 did, but it is worth deciding deliberately this time, since
the option now also exists per-command and the two would coexist
(
stack --stack X init --stack Ybecomes expressible). The alternative is togive the loader a trigger that does not depend on a group option — resolving the
stack the same way the rest of the CLI now does, by name as well as path.
Either way the argv-scanning at import time is what makes this fragile: it
couples command registration to the spelling of an option it does not own, and
the
except Exceptionaround it means a failure prints a warning rather thanfailing. That is worth revisiting alongside the fix.
Coverage
Nothing in CI invokes a stack subcommand, which is why this went unnoticed for
five weeks. A smoke-level test that registers a trivial subcommand and runs it
would catch both this and any future re-break;
tests/skill/fixturealready hasa fixture stack that could carry one.
Docs
docs/subcommands.mddocuments thestack --stack <path> -hform throughout,including its example help output, so it needs updating with whatever invocation
the fix settles on.