2026-05-03-allow-flag-cli-implementation-plan.md

–allow Flag CLI Support Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Add --allow <dir> flag support to jail.sh and vibe.sh to enable whitelisting additional directories with read/write access in the firejail sandbox.

Architecture: Parse --allow flags using bash’s getopts before processing commands, collect directories into an array, then add --whitelist and --read-write entries to firejail arguments for each directory.

Tech Stack: bash, firejail


Task 1: Modify jail.sh to support –allow flag

Files: - Modify: /home/btburke/projects/vibe/jail.sh

Context: The script currently takes all arguments as the command to run ($@). We need to parse --allow flags first, then treat remaining args as the command.

After line 10 (set -euo pipefail) and before line 12 (the firejail check comment), add:

# Parse --allow flags to add extra whitelisted directories
ALLOWED_DIRS=()
while [[ $# -gt 0 ]]; do
    case "$1" in
        --allow)
            if [[ $# -lt 2 ]]; then
                echo "Error: --allow requires a directory argument" >&2
                exit 1
            fi
            ALLOWED_DIRS+=("$2")
            shift 2
            ;;
        --)
            shift
            break
            ;;
        -*)
            echo "Error: Unknown flag: $1" >&2
            echo "Usage: jail [--allow <dir>]... <command> [args...]" >&2
            exit 1
            ;;
        *)
            break
            ;;
    esac
done

# Check that a command was provided
if [[ $# -eq 0 ]]; then
    echo "Error: No command specified" >&2
    echo "Usage: jail [--allow <dir>]... <command> [args...]" >&2
    exit 1
fi

After the FIREJAIL_ARGS array is fully built (around line 131, before the blacklist comment), add:

# Add user-specified allowed directories
for dir in "${ALLOWED_DIRS[@]}"; do
    FIREJAIL_ARGS+=(--whitelist="$dir")
    FIREJAIL_ARGS+=(--read-write="$dir")
done

Place this right before the “Blacklist specific tools” comment (around line 133).

jj commit -m "feat(jail): add --allow flag for additional directory whitelisting" jail.sh

Task 2: Modify vibe.sh to support –allow flag and pass through to jail

Files: - Modify: /home/btburke/projects/vibe/vibe.sh

Context: The script currently has specific handling for session tokens. We need to parse --allow flags first, collect them, then pass them to jail.sh along with the appropriate opencode arguments.

Replace lines 33-50 (everything from “Handle different argument patterns” comment to the fi) with:

# Parse --allow flags and handle session token
ALLOWED_DIRS=()
SESSION_TOKEN=""

while [[ $# -gt 0 ]]; do
    case "$1" in
        --allow)
            if [[ $# -lt 2 ]]; then
                echo "Error: --allow requires a directory argument" >&2
                exit 1
            fi
            ALLOWED_DIRS+=("$2")
            shift 2
            ;;
        -s)
            if [[ $# -lt 2 ]]; then
                echo "Error: -s requires a token argument" >&2
                exit 1
            fi
            SESSION_TOKEN="$2"
            shift 2
            ;;
        -*)
            echo "Error: Unknown flag: $1" >&2
            echo "Usage: vibe [--allow <dir>]... [<session_token>]" >&2
            exit 1
            ;;
        *)
            if [[ -z "$SESSION_TOKEN" ]]; then
                SESSION_TOKEN="$1"
                shift
            else
                echo "Error: Unexpected argument: $1" >&2
                echo "Usage: vibe [--allow <dir>]... [<session_token>]" >&2
                exit 1
            fi
            ;;
    esac
done

# Build jail command with allowed directories
JAIL_ARGS=()
for dir in "${ALLOWED_DIRS[@]}"; do
    JAIL_ARGS+=(--allow "$dir")
done

# Execute with or without session token
if [[ -n "$SESSION_TOKEN" ]]; then
    exec jail "${JAIL_ARGS[@]}" opencode -s "$SESSION_TOKEN"
else
    exec jail "${JAIL_ARGS[@]}" opencode
fi
jj commit -m "feat(vibe): add --allow flag support and pass through to jail" vibe.sh

Task 3: Test the implementation

Files: - Test manually with bash commands

Run:

./jail.sh --allow /tmp bash -c "touch /tmp/test_jail_allow && echo 'Success: can write to /tmp' && rm /tmp/test_jail_allow"

Expected: Command succeeds and prints “Success: can write to /tmp”

Run:

./jail.sh --allow /tmp --allow /var/tmp bash -c "touch /tmp/test1 /var/tmp/test2 && echo 'Success' && rm /tmp/test1 /var/tmp/test2"

Expected: Command succeeds and prints “Success”

Run:

./jail.sh bash -c "echo 'Hello from jail'"

Expected: Command succeeds and prints “Hello from jail”

Run:

./jail.sh --allow 2>&1 | head -1

Expected: Error message about missing directory argument

Run:

./jail.sh 2>&1 | head -1

Expected: Error message about missing command

Run (this will fail to start opencode without proper setup, but should show jail is called correctly):

./vibe.sh --allow /tmp 2>&1 | head -5

Expected: Should see “Starting in firejail sandbox…” message (or firejail error if opencode not in PATH)

jj commit -m "test: verify --allow flag implementation works correctly"

Task 4: Final review and squash if needed

jj log -r '::@' -p
jj squash -r @-- -r @

Or keep separate commits if preferred.


Implementation Notes

Why not use getopts?

getopts doesn’t support long options like --allow in a clean way without using GNU getopt. The manual case statement approach is more portable and clearer for this simple use case.

Argument parsing strategy

Both scripts use a while loop with a case statement to: 1. Collect all --allow <dir> pairs into an array 2. Handle vibe.sh’s -s <token> or positional token 3. Stop at first non-flag argument (for jail.sh, this is the command) 4. Validate that required arguments are present

Firejail integration

The allowed directories are added to FIREJAIL_ARGS as: - --whitelist=<dir> - Makes the directory visible in the sandbox - --read-write=<dir> - Grants read/write permissions

These are added after the default whitelist but before the blacklist, which is the correct order for firejail’s rule processing.