Skip to content

Bug: /design skill fails to load on zsh due to shell glob expansion errors #544

@magnificentlycursed

Description

@magnificentlycursed

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:

  1. design is not a crosslink CLI subcommand
  2. The correct invocation is /design inside a Claude Code session
  3. 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.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions