5.9 KiB
5.9 KiB
title, date, category, module, problem_type, component, symptoms, root_cause, resolution_type, severity, related_components, tags
| title | date | category | module | problem_type | component | symptoms | root_cause | resolution_type | severity | related_components | tags | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Local development shell aliases broken by zsh word-splitting, npm dependency, and missing Codex alias | 2026-03-26 | developer-experience | developer-tooling | developer_experience | tooling |
|
incomplete_setup | documentation_update | medium |
|
|
Local development shell aliases broken by zsh word-splitting, npm dependency, and missing Codex alias
Problem
Shell aliases for local plugin development failed in multiple ways: the Codex alias installed from the remote npm package instead of the local checkout, a string-variable CLI wrapper broke in zsh, and the README organized local dev instructions across two disconnected sections.
Symptoms
codex-ceranbunx @every-env/compound-plugin install compound-engineering --to codex(remote npm) instead of the local CLI, so local changes were never testedccb feat/fix-issue-389errored:no such file or directory: bun run /Users/tmchow/code/compound-engineering-plugin/src/index.tsbecause zsh treated the$CE_CLIstring variable as a single command namebunx @every-env/compound-plugin plugin-pathfailed withUnknown command plugin-pathbecause npm publishing was broken (latest published: 2.42.0, butplugin-pathwas added in 2.54.1)- README had "Installing from a Branch" and "Local Development" as separate sections, but both are local dev scenarios
- No Codex local dev shell alias existed despite the raw command being documented
What Didn't Work
- String variable for CLI path:
CE_CLI="bun run $CE_REPO/src/index.ts"then$CE_CLI args-- zsh does not word-split unquoted variable expansions the way bash does. The entire string is treated as a single command name, causing "no such file or directory." bunxfor all aliases: Depends on the latest version being published to npm. When publishing is broken or lagging, any new CLI feature (e.g.,plugin-path) is unavailable viabunx.aliasfor functions needing positional args: Shell aliases cannot consume$1separately from remaining args. Only functions can route positional parameters.
Solution
Restructured README into a single "Local Development" section with three subsections and fixed all aliases to use the local CLI via a function wrapper:
CE_REPO=~/code/compound-engineering-plugin
ce-cli() { bun run "$CE_REPO/src/index.ts" "$@"; }
# --- Local checkout (active development) ---
alias cce='claude --plugin-dir $CE_REPO/plugins/compound-engineering'
codex-ce() {
ce-cli install "$CE_REPO/plugins/compound-engineering" --to codex "$@"
}
# --- Pushed branch (testing PRs, worktree workflows) ---
ccb() {
claude --plugin-dir "$(ce-cli plugin-path compound-engineering --branch "$1")" "${@:2}"
}
codex-ceb() {
ce-cli install compound-engineering --to codex --branch "$1" "${@:2}"
}
Key design decisions:
ce-cli()function instead of a string variable -- functions word-split correctly in both bash and zshaliasforcceworks because trailing args are automatically appended by the shell (no positional routing needed)- Functions for
ccb/codex-cebbecause they need$1routed to--branchand${@:2}forwarded separately - Short names:
cce/ccb(3 chars) for Claude Code (most common),codex-ce/codex-cebfor the less-common target - All aliases use the local CLI so there's no dependency on npm publishing
README reorganized from:
- "Installing from a Branch" (separate section)
- "Local Development" (separate section)
Into:
- "Local Development" > "From your local checkout"
- "Local Development" > "From a pushed branch"
- "Local Development" > "Shell aliases"
Why This Works
- Function wrappers avoid zsh word-splitting:
ce-cli arg1 arg2invokesbun run "/path/to/index.ts" arg1 arg2as separate arguments in both bash and zsh. String variables only work in bash due to its default word-splitting behavior. - Local CLI eliminates npm dependency:
bun run src/index.tsuses whatever code is checked out locally, so new commands work immediately without waiting for a publish cycle. - Grouped by intent, not mechanism: "Local Development" is what the user cares about. Whether the source is a local checkout or a pushed branch is a sub-detail, not a separate concept.
Prevention
- Always use function wrappers for multi-word commands in shell aliases -- zsh (macOS default since Catalina) and bash handle word-splitting of variables differently. Functions work correctly in both.
- Default to local CLI for local dev tooling -- npm publishing latency or breakage should never block local development workflows. Reserve
bunxfor consumer-facing install instructions. - Group documentation by user intent -- organize by what users are trying to do (e.g., "local development"), not by implementation mechanism (e.g., "branch installs" vs "local checkout").
- Test shell aliases in zsh before documenting -- many developers use zsh; test both simple aliases and function wrappers before adding them to README.
Related Issues
- PR #395: Added
plugin-pathcommand and initial shell alias examples that this learning fixes - branch-based-plugin-install-and-testing-2026-03-26.md: Predecessor doc that introduced the branch-based workflow; the aliases documented here are the corrected versions