Skip to content

Commit 0a33a82

Browse files
UnbreakableMJclaude
andcommitted
feat(spacecraft-cli-shell): add Brush as first-class shell per Standard §7 (v1.22)
The Steelbore Standard v1.22 added §7 Shell Environment, naming Nushell, Ion, Brush, and Bash as the four first-class shells. spacecraft-cli-shell covered Nushell/Ion/PowerShell/ash/POSIX/Bash but had zero mention of Brush. - Add references/brush.md: treat Brush as Bash for syntax (it accepts POSIX + Bash), with the Brush-vs-Bash compatibility-matrix gaps called out (exotic builtins, special vars, unset $BASH_VERSION). - SKILL.md: add Brush to the description, the Bash-family framing, the detect signals (shebang / explicit mention; no distinct extension), the rank-3 priority note, and the Step 3 reference routing. - Add a §7 tie-in to the Standard Requirements section. Note (not changed here): SKILL.md Step 3 also lists references/ash.md and references/powershell.md, which do not exist on disk — a pre-existing dangling-reference gap, left untouched to keep this commit scoped to Brush. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 6c229df commit 0a33a82

4 files changed

Lines changed: 82 additions & 7 deletions

File tree

spacecraft-cli-shell.skill

2.83 KB
Binary file not shown.

spacecraft-cli-shell.zip

2.57 KB
Binary file not shown.

spacecraft-cli-shell/SKILL.md

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ description: >
66
first time in a conversation an agent is about to run, write, or suggest a shell
77
command — one-liners, scripts, `.nu`/`.ion`/`.ps1`/`.sh` files, CI blocks, README
88
snippets, documentation. Also consult whenever the user mentions Nushell, Ion,
9-
PowerShell, ash, Redox, POSIX, bashisms, shell portability, or a `$SHELL`. Detects
10-
the target shell (Nushell / Ion / PowerShell / ash / POSIX sh / Bash), blocks
9+
Brush, PowerShell, ash, Redox, POSIX, bashisms, shell portability, or a `$SHELL`. Detects
10+
the target shell (Nushell / Ion / Brush / PowerShell / ash / POSIX sh / Bash), blocks
1111
Bash-only patterns that silently break elsewhere (`[[ ]]`, `(( ))`, `<(...)`
1212
process substitution, `${var^^}`, Bash arrays, `function` keyword, `source` for
1313
POSIX), and routes to the correct per-shell reference. Syntax priority — POSIX sh
@@ -30,12 +30,14 @@ Sibling skill to `spacecraft-cli-preference`. That skill decides **which tool**
3030

3131
Four non-Bash shells matter most here: **Nushell** (Mohamed's primary interactive + Bravais/Spacecraft Software default), **Ion** (Redox default, secondary), **PowerShell** (Windows-first, cross-platform), and **ash** (Alpine Linux / embedded POSIX). Nushell and Ion are Rust-written and neither accepts Bash scripts as-is. Bashisms that "always worked" in Bash will fail — sometimes loudly, sometimes silently — in any of them.
3232

33+
**Brush** (Bourne RUsty SHell) is a fifth Rust shell, but it sits in the *Bash family*: unlike Nushell and Ion, it is built to accept POSIX and Bash syntax, so for this skill's purposes **treat Brush as Bash** — write POSIX first, and confirm any exotic Bash feature against Brush's still-maturing compatibility matrix. The Steelbore Standard §7 names the four first-class shell environments as **Nushell, Ion, Brush, and Bash**; this skill additionally guards PowerShell and ash because they show up as real operational targets. See `references/brush.md` for the Brush-vs-Bash gaps.
34+
3335
## When to consult
3436

3537
- **First shell command in a conversation** — always, regardless of how trivial it looks.
3638
- Any time work involves `.nu`, `.ion`, `.ps1`, or `.sh` files (reading, writing, editing).
3739
- Any CI block, Makefile/`justfile` recipe, README snippet, or doc example containing shell.
38-
- Any time the user names a shell (Nushell, Ion, PowerShell, ash, bash, dash, zsh) or says "POSIX", "portable script", "bashism".
40+
- Any time the user names a shell (Nushell, Ion, Brush, PowerShell, ash, bash, dash, zsh) or says "POSIX", "portable script", "bashism".
3941

4042
After the first consult in a session, trust the decision and proceed — don't re-load on every command unless the target shell changes or a new script file is opened.
4143

@@ -47,9 +49,9 @@ Signals 1–3 are **direct evidence** — commit silently, proceed.
4749
Signal 4 is **inference** — commit *and announce the assumption in one line* so the user can correct if wrong.
4850
Signal 5 is the only one that asks.
4951

50-
1. **File extension** *(evidence)*`.nu` → Nushell; `.ion` → Ion; `.ps1` / `.psm1` / `.psd1` → PowerShell; `.sh` → POSIX; `.bash` → Bash.
51-
2. **Shebang** *(evidence)*`#!/usr/bin/env nu` → Nushell; `#!/usr/bin/env ion` → Ion; `#!/usr/bin/env pwsh` or `#!/usr/bin/env powershell` → PowerShell; `#!/bin/ash` → ash; `#!/bin/sh` or `#!/usr/bin/env sh` → POSIX; `#!/bin/bash` → Bash.
52-
3. **Explicit user mention** *(evidence)* — "in Nushell", "my Ion script", "PowerShell", "in ash", "POSIX-compatible", "bash one-liner".
52+
1. **File extension** *(evidence)*`.nu` → Nushell; `.ion` → Ion; `.ps1` / `.psm1` / `.psd1` → PowerShell; `.sh` → POSIX; `.bash` → Bash. (Brush has no distinct extension — it runs `.sh`/`.bash` files; identify it by shebang or explicit mention.)
53+
2. **Shebang** *(evidence)*`#!/usr/bin/env nu` → Nushell; `#!/usr/bin/env ion` → Ion; `#!/usr/bin/env brush` → Brush (Bash-family); `#!/usr/bin/env pwsh` or `#!/usr/bin/env powershell` → PowerShell; `#!/bin/ash` → ash; `#!/bin/sh` or `#!/usr/bin/env sh` → POSIX; `#!/bin/bash` → Bash.
54+
3. **Explicit user mention** *(evidence)* — "in Nushell", "my Ion script", "Brush", "PowerShell", "in ash", "POSIX-compatible", "bash one-liner".
5355
4. **Environmental inference** *(announce)* — state the assumption in a short sentence before/alongside the command, e.g. "Assuming Nushell (your primary) — say the word for Ion, PowerShell, or POSIX.":
5456
- `bash_tool` in an agent environment runs **Bash**. Commands executed here and now should target **POSIX** (Bash accepts all POSIX).
5557
- Spacecraft Software / Bravais / "my shell" context with no other signal → **Nushell** (Mohamed's primary). When "my shell" is used explicitly, consider offering an **Ion** secondary since Mohamed runs both.
@@ -67,7 +69,7 @@ Within the detected shell, emit constructs in this preference order:
6769
|------|---------------|----------|
6870
| 1 | **POSIX sh** | The target shell accepts POSIX (sh, dash, Bash, zsh, ash, partially Ion). Maximally portable. |
6971
| 2 | **Shell-native** (PowerShell / Ion / Nushell / ash) | Target is a shell that diverges from or rejects POSIX. Use PowerShell syntax for `.ps1`; Ion syntax when target is Ion; Nushell syntax for `.nu`; ash is POSIX-compatible — stay at rank 1 unless an ash-specific extension is explicitly needed. |
70-
| 3 | **Bash extensions** | Last resort. Only when the target is confirmed Bash *and* no POSIX or native equivalent works. |
72+
| 3 | **Bash extensions** | Last resort. Only when the target is confirmed Bash (or Brush) *and* no POSIX or native equivalent works. Under Brush, prefer the widely-implemented subset (`[[ ]]`, indexed arrays, `local`) over exotic features (`declare -A`, `mapfile`, `$PIPESTATUS`) that its compatibility matrix may not yet cover — see `references/brush.md`. |
7173

7274
"POSIX first" means *prefer constructs that happen to be both POSIX and valid in the target shell* — not *write POSIX into a `.nu` file*. Nushell scripts get Nushell syntax; Ion scripts get Ion syntax; PowerShell scripts get PowerShell syntax; the POSIX preference applies to sh / bash / dash / zsh / ash targets and to any portability crossroads.
7375

@@ -81,6 +83,7 @@ Once the target is known, read the matching file **before** writing the command.
8183

8284
- **Nushell**`references/nushell.md`
8385
- **Ion**`references/ion.md`
86+
- **Brush** (Bash-family Rust shell) → `references/brush.md` (then `references/posix-safe.md` for the syntax itself — Brush accepts POSIX)
8487
- **PowerShell**`references/powershell.md`
8588
- **ash**`references/ash.md`
8689
- **POSIX sh / dash / bash-in-POSIX-mode**`references/posix-safe.md`
@@ -127,6 +130,16 @@ CLI tools, daemons, and system utilities must be POSIX-compliant. Platform-speci
127130
extensions must go behind feature flags and must not be required for core
128131
functionality. This skill's rank-1 POSIX-first priority order directly enforces §6.1.
129132

133+
### §7 — Shell Environment (v1.22)
134+
135+
The Standard names four first-class shell environments — **Nushell, Ion, Brush,
136+
and Bash** — and §7.1 mandates POSIX-compatible scripts by default, Nushell/Ion
137+
native variants where shell-native idioms are required, and **no Bashisms in
138+
shared scripts**. This skill *is* the operational enforcement of §7.1: the
139+
detect → POSIX-first → announce-the-bashism workflow above keeps shared scripts
140+
portable across all four. Brush, being Bash-compatible, runs the POSIX default
141+
unchanged (`references/brush.md`).
142+
130143
---
131144

132145
## Handoff
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<!--
2+
SPDX-License-Identifier: GPL-3.0-or-later
3+
Copyright (C) 2026 Mohamed Hammad & Spacecraft Software
4+
-->
5+
6+
# Brush — Bash-Compatible Rust Shell
7+
8+
**Brush** (Bourne RUsty SHell) is a POSIX- and Bash-compatible shell written in
9+
Rust. The Steelbore Standard §7 lists it as one of the four first-class shell
10+
environments (Nushell, Ion, Brush, Bash). Unlike Nushell and Ion — which reject
11+
Bash syntax outright — Brush is built to *accept* the Bourne/Bash family, so the
12+
mental model is simple:
13+
14+
> **For syntax purposes, treat Brush as Bash.** Write POSIX first (it runs
15+
> unchanged); reach for a Bash extension only when POSIX cannot express the
16+
> operation. The POSIX-first / avoid-bashisms discipline from `posix-safe.md`
17+
> applies directly.
18+
19+
This file records only what is *different* from "just write Bash."
20+
21+
## What carries over unchanged
22+
23+
- **All POSIX sh constructs**`[ ]` / `test`, `name() { … }`, `$(( … ))`,
24+
`. file`, parameter expansion (`${var:-default}`, `${var#pat}`, `${var%pat}`),
25+
`case`/`esac`, command substitution `$( )`. These are the rank-1 default and
26+
the safest target in Brush.
27+
- **Common Bash extensions** Brush implements — `[[ … ]]`, `(( … ))`, arrays
28+
(`arr=(a b c)`, `${arr[@]}`), `${var^^}`/`${var,,}`, brace expansion,
29+
`local`, here-strings. When the target is genuinely Brush (not portable sh),
30+
these generally parse the same as in Bash.
31+
32+
## Where Brush differs from Bash — verify, don't assume
33+
34+
Brush is an actively maturing reimplementation. It targets Bash compatibility but
35+
does not yet cover 100% of Bash's surface. Treat the following as "confirm before
36+
relying on it," especially in scripts meant to run unattended:
37+
38+
- **Newer / exotic Bash builtins and options.** Less-common `shopt` toggles
39+
(`globstar`, `extglob`, `nocaseglob`), namerefs (`declare -n`), associative
40+
arrays (`declare -A`), `coproc`, and `mapfile`/`readarray` may be partially
41+
implemented or absent in a given Brush release. If a script needs one, test it
42+
against the installed Brush version or fall back to a POSIX formulation.
43+
- **Bash-specific special variables.** `$PIPESTATUS`, `$BASH_SOURCE`,
44+
`$FUNCNAME`, `$EPOCHSECONDS`, `$RANDOM` — presence tracks Brush's compatibility
45+
matrix, not a guarantee. Prefer portable equivalents (`date +%s`, `shuf -i`)
46+
unless Brush support is confirmed.
47+
- **`$BASH_VERSION` is unset.** Scripts that gate behavior on `$BASH_VERSION`
48+
will take their non-Bash branch under Brush. Detect by capability, not by
49+
identity string.
50+
51+
## Bottom line for this skill
52+
53+
- **Portable / shared scripts** → write POSIX (`posix-safe.md`). Runs identically
54+
in Brush, Bash, dash, ash. This is the default and needs no Brush-specific care.
55+
- **Confirmed-Brush target, POSIX insufficient** → a Bash extension is acceptable,
56+
but announce it (per SKILL.md Step 2) *and* prefer the widely-implemented subset
57+
(`[[ ]]`, indexed arrays, `local`) over the exotic tail above.
58+
- **Converting an existing Bash script to run under Brush** → it usually "just
59+
works"; the residual risk is the exotic-feature tail, not everyday syntax. See
60+
`bashisms.md` for the constructs that are Bash-only against the *non*-Bash
61+
shells — those are a non-issue for Brush itself, but matter if the same script
62+
must also run in Nushell or Ion.

0 commit comments

Comments
 (0)