diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index 39d10eb..5a42af6 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -27,6 +27,8 @@ jobs:
test -d /tmp/case/resources/speaking/showcase-demo
node skills/petition-portal/scripts/build-portal.mjs /tmp/case -o /tmp/packet.html
test -s /tmp/packet.html
+ - name: Add another petition workspace to an existing case
+ run: bash scripts/test-scaffold.sh
- name: Similarity check catches near-duplicate letters
run: |
mkdir -p /tmp/l
diff --git a/README.md b/README.md
index c5c0b37..8167079 100644
--- a/README.md
+++ b/README.md
@@ -60,7 +60,7 @@ wrappers over the skills; the logic lives in the skills themselves.
| Command | |
|---|---|
-| `/new-case
[o1a\|eb1a\|both]` | Scaffold a case workspace |
+| `/new-case [o1a\|eb1a\|both]` | Scaffold a case workspace, or add another petition type to an existing one |
| `/triage` | Interview-driven criteria feasibility assessment |
| `/status` | Stage, blockers, and prioritized next actions |
| `/add-evidence` | File a document and record it in one step |
diff --git a/commands/new-case.md b/commands/new-case.md
index 9942bfe..1733fca 100644
--- a/commands/new-case.md
+++ b/commands/new-case.md
@@ -10,6 +10,9 @@ Arguments: `$ARGUMENTS` — expected as ` [o1a|eb1a|both]`, defaulti
2. Run its scaffold script:
`${CLAUDE_PLUGIN_ROOT}/skills/petition-workspace/scripts/scaffold-case.sh `
It refuses to write into a non-empty directory — do not work around that; ask the user.
+ If the directory is already a case and the user wants another petition type alongside
+ it, use `scaffold-case.sh --add ` instead — it adds only the new
+ petition workspace and leaves everything else untouched.
3. Then help fill in `case-overview.md`, starting with the field of endeavor. Push for a
narrow, specific field statement; it is the highest-leverage line in the whole case.
4. Remind the user once that this workspace will hold sensitive records and should not go
diff --git a/package.json b/package.json
index 00b8557..6feb7a1 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,8 @@
"scripts": {
"validate": "node scripts/validate-skills.mjs",
"check-pii": "node scripts/check-pii.mjs",
- "test": "npm run validate && npm run check-pii"
+ "test": "npm run validate && npm run check-pii && npm run test-scaffold",
+ "test-scaffold": "bash scripts/test-scaffold.sh"
},
"devDependencies": {
"gray-matter": "^4.0.3",
diff --git a/scripts/test-scaffold.sh b/scripts/test-scaffold.sh
new file mode 100755
index 0000000..4fc444d
--- /dev/null
+++ b/scripts/test-scaffold.sh
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+# Exercise scaffold-case.sh end to end: fresh scaffold, and --add for another
+# petition workspace on an existing case.
+# Run: bash scripts/test-scaffold.sh
+set -euo pipefail
+
+ROOT="$(cd "$(dirname "$0")/.." && pwd)"
+SCAFFOLD="$ROOT/skills/petition-workspace/scripts/scaffold-case.sh"
+TMP="$(mktemp -d)"
+trap 'rm -rf "$TMP"' EXIT
+fails=0
+
+ok() { echo " ok $1"; }
+fail() { echo " FAIL $1" >&2; fails=$((fails + 1)); }
+check() { local name="$1"; shift; if "$@" >/dev/null 2>&1; then ok "$name"; else fail "$name"; fi; }
+refuses() { local name="$1"; shift; if "$@" >/dev/null 2>&1; then fail "$name"; else ok "$name"; fi; }
+criteria() { grep -c '^### Criterion' "$1"; }
+
+echo "scaffold-case.sh"
+
+case="$TMP/case"
+"$SCAFFOLD" "$case" o1a >/dev/null
+check "fresh o1a scaffold has 8 criteria" test "$(criteria "$case/o1a/evidence-list.md")" = 8
+check "fresh o1a scaffold has no eb1a/" test ! -e "$case/eb1a"
+refuses "plain scaffold still refuses a non-empty directory" "$SCAFFOLD" "$case" eb1a
+
+# Simulate a case in progress: user edits that --add must not touch.
+echo "Field of endeavor: industrial robotics" >> "$case/case-overview.md"
+echo "| | Org chart | [x] collected | resources/company-docs/org-chart.png |" >> "$case/o1a/evidence-list.md"
+mkdir -p "$case/resources/awards/meridian" && echo x > "$case/resources/awards/meridian/cert.pdf"
+before="$(cd "$case" && find case-overview.md README.md .gitignore resources o1a -type f -exec shasum {} + | sort)"
+
+"$SCAFFOLD" --add "$case" eb1a >/dev/null
+check "--add eb1a creates eb1a/ with 10 criteria" test "$(criteria "$case/eb1a/evidence-list.md")" = 10
+check "--add eb1a writes 10 criterion argument files" test "$(ls "$case/eb1a/evidence-by-criterion" | wc -l | tr -d ' ')" = 10
+check "--add eb1a writes overview and narrative" test -s "$case/eb1a/overview.md" -a -s "$case/eb1a/petition-narrative.md"
+after="$(cd "$case" && find case-overview.md README.md .gitignore resources o1a -type f -exec shasum {} + | sort)"
+check "--add leaves existing case files untouched" test "$before" = "$after"
+
+refuses "--add refuses an existing petition workspace" "$SCAFFOLD" --add "$case" eb1a
+refuses "--add both refuses when either already exists" "$SCAFFOLD" --add "$case" both
+refuses "--add refuses a directory that is not a case" "$SCAFFOLD" --add "$TMP/nope" o1a
+refuses "--add requires a petition type" "$SCAFFOLD" --add "$case"
+refuses "--add rejects an unknown petition type" "$SCAFFOLD" --add "$case" h1b
+
+# The added workspace must work with the rest of the toolchain.
+printf 'x' > "$TMP/f.png"
+check "add-evidence files into the added workspace" \
+ node "$ROOT/skills/petition-workspace/scripts/add-evidence.mjs" "$case" -p eb1a -c 7 -d "Showcase demo" "$TMP/f.png"
+check "added workspace's evidence-list records the exhibit" grep -q "Showcase demo" "$case/eb1a/evidence-list.md"
+check "review packet builds over both workspaces" \
+ node "$ROOT/skills/petition-portal/scripts/build-portal.mjs" "$case" -o "$TMP/packet.html"
+
+if [ "$fails" -gt 0 ]; then echo "$fails failure(s)" >&2; exit 1; fi
+echo "test-scaffold: all checks passed"
diff --git a/skills/petition-workspace/SKILL.md b/skills/petition-workspace/SKILL.md
index 578a26f..33a4fdf 100644
--- a/skills/petition-workspace/SKILL.md
+++ b/skills/petition-workspace/SKILL.md
@@ -17,6 +17,19 @@ scripts/scaffold-case.sh [o1a|eb1a|both]
Refuses to write into a non-empty directory. Creates `resources/` for raw material,
one directory per petition type, `communications/`, and `case-overview.md`.
+## Add another petition workspace to an existing case
+
+```bash
+scripts/scaffold-case.sh --add
+```
+
+For a case that started as an O-1A and is now also pursuing an EB-1A (or the reverse).
+Writes only the new petition directory — `resources/`, `case-overview.md`, and any
+existing petition directory are left untouched. Refuses if the directory is not a case
+(no `case-overview.md`) or the petition directory already exists. Afterwards, update
+*Petition type(s)* in `case-overview.md`; the new workspace numbers its exhibits
+independently and draws on the same shared `resources/`.
+
## File evidence with the tool, not by hand
```bash
diff --git a/skills/petition-workspace/scripts/scaffold-case.sh b/skills/petition-workspace/scripts/scaffold-case.sh
index da13823..ee34d47 100755
--- a/skills/petition-workspace/scripts/scaffold-case.sh
+++ b/skills/petition-workspace/scripts/scaffold-case.sh
@@ -1,21 +1,34 @@
#!/usr/bin/env bash
# Scaffold a petition case workspace.
# Usage: scaffold-case.sh [o1a|eb1a|both]
+# scaffold-case.sh --add
+#
+# --add adds another petition workspace to an existing case (an O-1A case later
+# pursuing an EB-1A). It writes only the missing petition directories and never
+# touches resources/, case-overview.md, or a petition directory that already exists.
set -euo pipefail
-TARGET="${1:?usage: scaffold-case.sh [o1a|eb1a|both]}"
-TYPE="${2:-o1a}"
+USAGE="usage: scaffold-case.sh [o1a|eb1a|both] | scaffold-case.sh --add "
+ADD=0
+if [ "${1:-}" = "--add" ]; then ADD=1; shift; fi
+
+TARGET="${1:?$USAGE}"
+if [ "$ADD" = 1 ]; then TYPE="${2:?$USAGE}"; else TYPE="${2:-o1a}"; fi
TPL="$(cd "$(dirname "$0")/../templates/case" && pwd)"
case "$TYPE" in o1a|eb1a|both) ;; *) echo "type must be o1a, eb1a, or both" >&2; exit 2 ;; esac
-if [ -e "$TARGET" ] && [ -n "$(ls -A "$TARGET" 2>/dev/null)" ]; then
+if [ "$ADD" = 1 ]; then
+ if [ ! -f "$TARGET/case-overview.md" ]; then
+ echo "not a case workspace (no case-overview.md): $TARGET — scaffold it without --add" >&2
+ exit 1
+ fi
+elif [ -e "$TARGET" ] && [ -n "$(ls -A "$TARGET" 2>/dev/null)" ]; then
echo "refusing to scaffold into non-empty directory: $TARGET" >&2
+ echo "to add another petition workspace to an existing case: scaffold-case.sh --add $TARGET " >&2
exit 1
fi
-mkdir -p "$TARGET"/{resources/{awards,membership,press,judging,patents,publications,compensation,company-docs,recommendation-letters,education,speaking,photos},communications/{attorneys,recommenders},reference}
-
petitions=()
case "$TYPE" in
o1a) petitions=(o1a) ;;
@@ -23,6 +36,18 @@ case "$TYPE" in
both) petitions=(o1a eb1a) ;;
esac
+if [ "$ADD" = 1 ]; then
+ for p in "${petitions[@]}"; do
+ if [ -e "$TARGET/$p" ]; then
+ echo "refusing to overwrite existing petition workspace: $TARGET/$p" >&2
+ exit 1
+ fi
+ done
+fi
+
+# Idempotent: on --add this only fills in shared folders an older case is missing.
+mkdir -p "$TARGET"/{resources/{awards,membership,press,judging,patents,publications,compensation,company-docs,recommendation-letters,education,speaking,photos},communications/{attorneys,recommenders},reference}
+
# Criterion names per petition type. O-1A has 8; EB-1A has 10, and the numbering
# diverges from criterion 7 onward — do not share one list between them.
o1a_criteria=(
@@ -65,6 +90,13 @@ for p in "${petitions[@]}"; do
"$(echo "$p" | tr '[:lower:]' '[:upper:]')" > "$dir/petition-narrative.md"
done
+if [ "$ADD" = 1 ]; then
+ echo "added ${petitions[*]} petition workspace to case at $TARGET"
+ echo "update 'Petition type(s)' in case-overview.md; resources/ is shared, exhibit numbering is independent"
+ for p in "${petitions[@]}"; do find "$TARGET/$p" -type f | sort | sed "s|^$TARGET|.|"; done
+ exit 0
+fi
+
cat > "$TARGET/case-overview.md" <<'EOF'
# Case Overview