Best Practices
Always Include an Extension
Miso uses the file extension to select the interpreter. A file without a recognized extension defaults to sh, which may not be what you want:
scripts/migrate.py # runs with python3
scripts/migrate # runs with sh — probably wrongAlways be explicit.
Shebang vs. Extension
Extension-based dispatch is fine for most scripts. Use a shebang when you need a specific binary path or want the script to be portable outside of miso:
#!/usr/bin/env python3
import sys
...When both are present, the shebang takes precedence over the extension.
Organizing with Subdirectories
Group scripts by domain using subdirectories. Invoke them with a / separator:
scripts/
db/
migrate.sh
seed.sh
reset.sh
ci/
lint.sh
test.sh
release.shmiso db/migrate
miso ci/releaseNest as deeply as you need. An index file in a subdirectory acts as the default for that directory:
# scripts/db/index.sh runs when you call:
miso dbNest related commands instead of prefixing flat filenames. Prefer scripts/docker/up.sh + scripts/docker/build.sh (invoked as miso docker/up, miso docker/build) over the stuttering flat form scripts/docker-up.sh + scripts/docker-build.sh.
package.json Scripts vs. the scripts/ Folder
Pick the surface based on the command’s size:
- One-liners →
package.jsonscripts. A single command likevite --config vite.config.tsreads best as apackage.jsonscript — miso resolves it just like a folder script. (Exception: simple mode ignorespackage.json.) - Multi-line or chained commands →
scripts/folder. Once a command spans multiple lines, chains with&&, or needs real logic, a.shfile inscripts/is far more readable than a cramped JSON string.
Whichever you pick, give each command one home. If the same name lives in both your scripts folder and package.json, Miso treats it as ambiguous and stops with an error rather than guessing which one you meant.
Helper Files
Prefix files with _ to exclude them from discovery. Miso skips them during scanning, so they’re never exposed as runnable commands:
scripts/
deploy.sh
_utils.sh # shared helpers — not a command
_colors.sh # not a commandSource them from other scripts as needed:
# scripts/deploy.sh
source "$(dirname "$0")/_utils.sh"Exit Codes
Always exit with a meaningful code. Miso propagates the exit code to the calling shell, so CI pipelines and build tools see failures correctly:
if [ -z "$DEPLOY_ENV" ]; then
echo "Error: DEPLOY_ENV is not set"
exit 1
fiA script that exits 0 signals success. Any non-zero value signals failure.