Bug: /design skill fails to load on zsh due to shell glob expansion errors
User context
First-time crosslink user following the design workflow guide at
https://forecast.bio/crosslink/guides/design-workflow.html.
Following the guide, I attempted to start a design session by running this in the terminal:
crosslink design "write two claude skills. the first is a technical writer..."
This produced the error unknown option '--prompt' with no indication that design is not
a crosslink CLI subcommand or that the correct invocation is /design inside Claude Code.
I eventually figured out the correct approach — open Claude Code, then type /design "<description>" — but only through trial and error, not from the error message or the guide.
This report covers both the CLI confusion (documented below as Bug 0) and the two shell
compatibility bugs that caused /design to fail once I found the correct invocation.
Summary
The /design skill fails to load entirely on zsh when the .design/ directory does not
exist, or when any of the listed architecture files are absent. Both failures manifest as
Error: Shell command failed for pattern "!..." before the skill prompt is even processed,
meaning the user's feature description is never acted on.
Environment
- Shell: zsh (macOS default)
- Skill file:
.claude/commands/design.md
Bug 0 — crosslink design gives a misleading error instead of helpful guidance
Error
error: unknown option '--prompt'
What happened
Running crosslink design "<description>" in a terminal produces this error. The error
message references --prompt, which is unrelated to what the user typed and gives no hint
that:
design is not a crosslink CLI subcommand
- The correct invocation is
/design inside a Claude Code session
- The guide at https://forecast.bio/crosslink/guides/design-workflow.html does not make
this distinction explicit enough for first-time users
Expected behavior
The crosslink CLI should either:
- Detect that
design is a known Claude Code skill and print guidance:
'design' is a Claude Code skill. Open Claude Code and type: /design "<description>"
- Or at minimum:
error: unknown command 'design'. Run 'crosslink help' for available commands.
The current error (unknown option '--prompt') is actively misleading — it implies the user
passed a bad flag rather than an unrecognized command.
Bug 1 — Glob expansion failure when .design/ does not exist
Error
Error: Shell command failed for pattern "!`ls .design/*.md 2>/dev/null`": [stderr]
(eval):1: no matches found: .design/*.md
Root cause
Line 11 of design.md runs:
ls .design/*.md 2>/dev/null
In zsh, glob patterns are expanded by the shell before the command runs. When .design/
does not exist, zsh throws no matches found: .design/*.md at the expansion stage — before
ls is invoked — so 2>/dev/null never suppresses it. The exit is non-zero and the harness
treats the skill as failed. In bash this would silently pass the literal glob to ls, which
would then fail quietly.
Fix applied
- - Existing design docs: !`ls .design/*.md 2>/dev/null`
+ - Existing design docs: !`find .design -name '*.md' 2>/dev/null`
find does not use shell glob expansion, so it returns empty output (exit 0) when
.design/ is absent.
Bug 2 — ls exits non-zero when some listed files are absent
Error
Error: Shell command failed for pattern "!`ls README.md CLAUDE.md ARCHITECTURE.md ADR.md 2>/dev/null`": [stderr]
README.md
Root cause
Line 12 of design.md runs:
ls README.md CLAUDE.md ARCHITECTURE.md ADR.md 2>/dev/null
When ls is given a list of explicit filenames and any of them do not exist, it exits with
a non-zero code even though it successfully lists the ones that do exist. 2>/dev/null
suppresses the "No such file" messages but does not change the exit code. In a typical
project that has README.md but not CLAUDE.md, ARCHITECTURE.md, or ADR.md, this
command always exits non-zero and the harness rejects the skill context.
Fix applied
- - Architecture files: !`ls README.md CLAUDE.md ARCHITECTURE.md ADR.md 2>/dev/null`
+ - Architecture files: !`find . -maxdepth 1 \( -name 'README.md' -o -name 'CLAUDE.md' -o -name 'ARCHITECTURE.md' -o -name 'ADR.md' \) 2>/dev/null`
find with explicit -name predicates always exits 0 and lists only the files that exist,
regardless of how many are absent.
Bug 3 — /check skill fails to load when Docker is not installed
Context
After successfully launching a background agent with crosslink kickoff run .design/documentation-skills.md,
the agent prompted for tool-use approval inside its tmux session. I ran /check WikX-0BtG-design-documentation-skills-md-b1be
to inspect the agent's status without attaching to tmux directly. The /check skill failed
to load entirely, making it impossible to check on or interact with the running agent. The
only recourse was to attach to the tmux session manually — defeating the purpose of /check.
Error
Error: Shell command failed for pattern "!`docker ps --filter label=crosslink-agent=true --format 'table {{.Names}}\t{{.Status}}' 2>/dev/null`":
Skill file
.claude/commands/check.md
Root cause
Line 8 of check.md runs:
docker ps --filter label=crosslink-agent=true --format 'table {{.Names}}\t{{.Status}}' 2>/dev/null
When Docker is not installed, docker is not found and the shell exits non-zero before
2>/dev/null can suppress anything. The harness treats any non-zero exit as a fatal
context-gathering failure and refuses to load the skill — even though docker is entirely
optional (the skill supports both docker containers and tmux sessions).
Fix applied
- - Running containers: !`docker ps --filter label=crosslink-agent=true --format 'table {{.Names}}\t{{.Status}}' 2>/dev/null`
+ - Running containers: !`docker ps --filter label=crosslink-agent=true --format 'table {{.Names}}\t{{.Status}}' 2>/dev/null || true`
Appending || true forces exit 0 regardless of whether docker is installed or running,
so the skill loads normally on machines that use tmux only.
Recommendation
All !...`` shell commands in skill context sections that use glob patterns or ls with
multiple filenames should be audited for this class of failure. The safe patterns are:
| Instead of |
Use |
ls dir/*.ext 2>/dev/null |
find dir -name '*.ext' 2>/dev/null |
ls file1 file2 file3 2>/dev/null |
find . -maxdepth 1 \( -name 'file1' -o -name 'file2' -o -name 'file3' \) 2>/dev/null |
ls dir/ 2>/dev/null |
find dir -maxdepth 0 2>/dev/null (or [ -d dir ] && ls dir/) |
optional-tool subcommand 2>/dev/null |
optional-tool subcommand 2>/dev/null || true |
These alternatives are portable across bash and zsh and always exit 0 when no matches
are found or when optional tooling is absent.
Bug:
/designskill fails to load on zsh due to shell glob expansion errorsUser context
First-time crosslink user following the design workflow guide at
https://forecast.bio/crosslink/guides/design-workflow.html.
Following the guide, I attempted to start a design session by running this in the terminal:
This produced the error
unknown option '--prompt'with no indication thatdesignis nota crosslink CLI subcommand or that the correct invocation is
/designinside Claude Code.I eventually figured out the correct approach — open Claude Code, then type
/design "<description>"— but only through trial and error, not from the error message or the guide.This report covers both the CLI confusion (documented below as Bug 0) and the two shell
compatibility bugs that caused
/designto fail once I found the correct invocation.Summary
The
/designskill fails to load entirely on zsh when the.design/directory does notexist, or when any of the listed architecture files are absent. Both failures manifest as
Error: Shell command failed for pattern "!..."before the skill prompt is even processed,meaning the user's feature description is never acted on.
Environment
.claude/commands/design.mdBug 0 —
crosslink designgives a misleading error instead of helpful guidanceError
What happened
Running
crosslink design "<description>"in a terminal produces this error. The errormessage references
--prompt, which is unrelated to what the user typed and gives no hintthat:
designis not a crosslink CLI subcommand/designinside a Claude Code sessionthis distinction explicit enough for first-time users
Expected behavior
The crosslink CLI should either:
designis a known Claude Code skill and print guidance:'design' is a Claude Code skill. Open Claude Code and type: /design "<description>"error: unknown command 'design'. Run 'crosslink help' for available commands.The current error (
unknown option '--prompt') is actively misleading — it implies the userpassed a bad flag rather than an unrecognized command.
Bug 1 — Glob expansion failure when
.design/does not existError
Root cause
Line 11 of
design.mdruns:In zsh, glob patterns are expanded by the shell before the command runs. When
.design/does not exist, zsh throws
no matches found: .design/*.mdat the expansion stage — beforelsis invoked — so2>/dev/nullnever suppresses it. The exit is non-zero and the harnesstreats the skill as failed. In bash this would silently pass the literal glob to
ls, whichwould then fail quietly.
Fix applied
finddoes not use shell glob expansion, so it returns empty output (exit 0) when.design/is absent.Bug 2 —
lsexits non-zero when some listed files are absentError
Root cause
Line 12 of
design.mdruns:ls README.md CLAUDE.md ARCHITECTURE.md ADR.md 2>/dev/nullWhen
lsis given a list of explicit filenames and any of them do not exist, it exits witha non-zero code even though it successfully lists the ones that do exist.
2>/dev/nullsuppresses the "No such file" messages but does not change the exit code. In a typical
project that has
README.mdbut notCLAUDE.md,ARCHITECTURE.md, orADR.md, thiscommand always exits non-zero and the harness rejects the skill context.
Fix applied
findwith explicit-namepredicates always exits 0 and lists only the files that exist,regardless of how many are absent.
Bug 3 —
/checkskill fails to load when Docker is not installedContext
After successfully launching a background agent with
crosslink kickoff run .design/documentation-skills.md,the agent prompted for tool-use approval inside its tmux session. I ran
/check WikX-0BtG-design-documentation-skills-md-b1beto inspect the agent's status without attaching to tmux directly. The
/checkskill failedto load entirely, making it impossible to check on or interact with the running agent. The
only recourse was to attach to the tmux session manually — defeating the purpose of
/check.Error
Skill file
.claude/commands/check.mdRoot cause
Line 8 of
check.mdruns:When Docker is not installed,
dockeris not found and the shell exits non-zero before2>/dev/nullcan suppress anything. The harness treats any non-zero exit as a fatalcontext-gathering failure and refuses to load the skill — even though docker is entirely
optional (the skill supports both docker containers and tmux sessions).
Fix applied
Appending
|| trueforces exit 0 regardless of whether docker is installed or running,so the skill loads normally on machines that use tmux only.
Recommendation
All
!...`` shell commands in skill context sections that use glob patterns orlswithmultiple filenames should be audited for this class of failure. The safe patterns are:
ls dir/*.ext 2>/dev/nullfind dir -name '*.ext' 2>/dev/nullls file1 file2 file3 2>/dev/nullfind . -maxdepth 1 \( -name 'file1' -o -name 'file2' -o -name 'file3' \) 2>/dev/nullls dir/ 2>/dev/nullfind dir -maxdepth 0 2>/dev/null(or[ -d dir ] && ls dir/)optional-tool subcommand 2>/dev/nulloptional-tool subcommand 2>/dev/null || trueThese alternatives are portable across bash and zsh and always exit 0 when no matches
are found or when optional tooling is absent.