/save
Smart auto-commit with remote sync (handles pull/rebase/stash, auto-generates messages, supports multi-repo). Ensures clean working tree — every file committed or gitignored.
> /plugin marketplace add anton-abyzov/specweave > /plugin install sw@specweave
How it fires
How this command gets triggered: by you, by Claude, or both.
- Fires itselfClaude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/save
Context preview
What this command does when you run it.
Smart auto-commit with remote sync (handles pull/rebase/stash, auto-generates messages, supports multi-repo). Ensures clean working tree — every file committed or gitignored.
Command definition
save.mddisable-model-invocation: true
description: Smart auto-commit with remote sync (handles pull/rebase/stash, auto-generates messages, supports multi-repo). Ensures clean working tree — every file committed or gitignored.
argument-hint: "[message]"
sw:save - Smart Save with Auto-Sync
Project Overrides
**Skill Memories**: If `.specweave/skill-memories/save.md` exists, read and apply its learnings.
Usage
sw:save # Fully automatic - generates message, syncs, pushes
sw:save "msg" # Your message, auto-sync
sw:save -i # Interactive - asks before each step
sw:save --dry-run # Preview without executing
Core Guarantee
**After `sw:save` completes, `git status` must be clean in every repo** — zero untracked files, zero unstaged changes. Achieved by:
- Committing all important files (source, config, docs, specs, lock files)
- Gitignoring all unimportant files (build output, deps, OS junk, secrets)
- Applying this per-repo for both umbrella and all nested repositories
Execution Order (MANDATORY)
Steps 2–7 run **per repo** — first all nested repos (innermost first), then the umbrella/parent project last.
1. Scan for Nested Repos (ALWAYS FIRST)
for dir in repositories packages services apps libs workspace; do
[ -d "$dir" ] && find "$dir" -maxdepth 4 -name ".git" -type d | while read gitdir; do
repo="${gitdir%/.git}"
echo "Found: $repo"
done
done
[ -d ".git" ] && echo "Found: . (parent project)"**Three-tier detection**: (1) `umbrella.childRepos` from `.specweave/config.json` if configured, (2) git-scan of nested `.git` dirs up to 4 levels deep, (3) parent project `.git`.
2. Pre-Flight Check
git fetch origin
LOCAL=$(git rev-parse HEAD)
REMOTE=$(git rev-parse @{u} 2>/dev/null || echo "no-upstream")
BASE=$(git merge-base HEAD @{u} 2>/dev/null || echo "no-base")Determine state: `up-to-date` | `ahead` | `behind` | `diverged` | `no-tracking`.
3. Smart Sync
- **behind/diverged**: Stash dirty files, `git pull --rebase`, unstash
- **no-tracking**: `git push -u origin HEAD`
- **up-to-date/ahead**: No sync needed, proceed
4. Smart Staging (MANDATORY — replaces `git add -A`)
**Goal**: Every file in the repo is accounted for — either staged for commit or covered by `.gitignore`. Nothing left dangling.
Phase 1: Stage all tracked modifications
git add -u # Modified/deleted files already under source control — always safe
This handles: edited source files, updated configs, deleted files, submodule pointer changes.
Phase 2: Classify untracked files
git ls-files --others --exclude-standard
This lists files that are (a) not tracked and (b) not already covered by `.gitignore`. For each, classify using the table below. Match **top-down** — first match wins.
| Class | Patterns | Action | |-------|----------|--------| | **Dependencies** | `node_modules/`, `vendor/`, `bower_components/`, `.pnp.*`, `__pypackages__/`, `.venv/`, `venv/`, `env/` (Python) | `.gitignore` | | **Build output** | `dist/`, `build/`, `.next/`, `.nuxt/`, `.output/`, `out/`, `.svelte-kit/`, `.vercel/`, `.netlify/`, `.turbo/`, `storybook-static/`, `*.tsbuildinfo` | `.gitignore` | | **Cache** | `.cache/`, `.parcel-cache/`, `.eslintcache`, `.stylelintcache`, `tsconfig.tsbuildinfo` | `.gitignore` | | **Coverage** | `coverage/`, `.nyc_output/`, `lcov.info` | `.gitignore` | | **Logs** | `*.log`, `npm-debug.log*`, `yarn-debug.log*`, `pnpm-debug.log*`, `lerna-debug.log*` | `.gitignore` | | **OS artifacts** | `.DS_Store`, `Thumbs.db`, `desktop.ini`, `._*`, `ehthumbs.db` | `.gitignore` | | **Editor/IDE** | `.idea/`, `*.iml`, `*.swp`, `*.swo`, `*~`, `.project`, `.classpath`, `.settings/` | `.gitignore` | | **Runtime** | `.wrangler/`, `.dev.vars`, `*.pid`, `*.seed`, `.env.sentry-build-plugin` | `.gitignore` | | **Package artifacts** | `*.tgz`, `*.tar.gz` (in repo root or release dirs) | `.gitignore` | | **Secrets** | `.env`, `.env.local`, `.env.*.local` (**NOT** `.env.example`, `.env.template`, `.env.sample`), `*.pem`, `*.key`, `*.p12`, `*.pfx`, `*.jks`, `*.keystore` | `.gitignore` + **warn user** | | **Large binaries** | Any single file > 5 MB not inside `src/` or `assets/` | **skip** + **warn user** (don't gitignore — let user decide) | | **Source (default)** | Everything else: source files, configs, docs, specs, tests, lock files, CI files, `.specweave/`, `.github/`, `*.md` | `git add <file>` |
**Critical**: `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml` are **Source** — always commit.
Phase 3: Update .gitignore (if patterns were added)
For each pattern classified as `.gitignore` in Phase 2:
1. **Check if .gitignore exists** — if not, create it 2. **Check if pattern already present** — `grep -qxF '<pattern>' .gitignore` (exact line match) or check if a parent pattern already covers it (e.g., `node_modules/` covers `node_modules/foo/`) 3. **Append missing patterns** under a clearly marked section:
# Auto-managed by sw:save — do not edit this section manually
.DS_Store
node_modules/
dist/
.env
If the `# Auto-managed by sw:save` section already exists, append new patterns there. Otherwise create it at the end of the file.
4. **Stage .gitignore**: `git add .gitignore`
Phase 4: Stage remaining approved source files
git add <each file classified as Source in Phase 2>
Use `git add` with explicit file paths — **never** `git add -A` or `git add .`.
Phase 5: Verify clean state
untracked=$(git ls-files --others --exclude-standard)
if [ -n "$untracked" ]; then
echo "WARNING: Remaining untracked files (not staged, not gitignored):"
echo "$untracked"
fi
- If **zero untracked** remain → clean state achieved, proceed
- If **untracked remain** (missed by classification) → warn, but still proceed with commit. These files carry forward to next save.
- In `--interactive` mode: prompt user for each remaining untracked file (stage / gitignore / s
Read more
disable-model-invocation: true description: Smart auto-commit with remote sync (handles pull/rebase/stash, auto-generates messages, supports multi-repo). Ensures clean working tree — every file committed or gitignored. argument-hint: "[message]"
sw:save - Smart Save with Auto-Sync
Project Overrides
**Skill Memories**: If `.specweave/skill-memories/save.md` exists, read and apply its learnings.
Usage
sw:save # Fully automatic - generates message, syncs, pushes sw:save "msg" # Your message, auto-sync sw:save -i # Interactive - asks before each step sw:save --dry-run # Preview without executing
Core Guarantee
**After `sw:save` completes, `git status` must be clean in every repo** — zero untracked files, zero unstaged changes. Achieved by:
- Committing all important files (source, config, docs, specs, lock files)
- Gitignoring all unimportant files (build output, deps, OS junk, secrets)
- Applying this per-repo for both umbrella and all nested repositories
Execution Order (MANDATORY)
Steps 2–7 run **per repo** — first all nested repos (innermost first), then the umbrella/parent project last.
1. Scan for Nested Repos (ALWAYS FIRST)
for dir in repositories packages services apps libs workspace; do
[ -d "$dir" ] && find "$dir" -maxdepth 4 -name ".git" -type d | while read gitdir; do
repo="${gitdir%/.git}"
echo "Found: $repo"
done
done
[ -d ".git" ] && echo "Found: . (parent project)"**Three-tier detection**: (1) `umbrella.childRepos` from `.specweave/config.json` if configured, (2) git-scan of nested `.git` dirs up to 4 levels deep, (3) parent project `.git`.
2. Pre-Flight Check
git fetch origin
LOCAL=$(git rev-parse HEAD)
REMOTE=$(git rev-parse @{u} 2>/dev/null || echo "no-upstream")
BASE=$(git merge-base HEAD @{u} 2>/dev/null || echo "no-base")Determine state: `up-to-date` | `ahead` | `behind` | `diverged` | `no-tracking`.
3. Smart Sync
- **behind/diverged**: Stash dirty files, `git pull --rebase`, unstash
- **no-tracking**: `git push -u origin HEAD`
- **up-to-date/ahead**: No sync needed, proceed
4. Smart Staging (MANDATORY — replaces `git add -A`)
**Goal**: Every file in the repo is accounted for — either staged for commit or covered by `.gitignore`. Nothing left dangling.
Phase 1: Stage all tracked modifications
git add -u # Modified/deleted files already under source control — always safe
This handles: edited source files, updated configs, deleted files, submodule pointer changes.
Phase 2: Classify untracked files
git ls-files --others --exclude-standard
This lists files that are (a) not tracked and (b) not already covered by `.gitignore`. For each, classify using the table below. Match **top-down** — first match wins.
| Class | Patterns | Action | |-------|----------|--------| | **Dependencies** | `node_modules/`, `vendor/`, `bower_components/`, `.pnp.*`, `__pypackages__/`, `.venv/`, `venv/`, `env/` (Python) | `.gitignore` | | **Build output** | `dist/`, `build/`, `.next/`, `.nuxt/`, `.output/`, `out/`, `.svelte-kit/`, `.vercel/`, `.netlify/`, `.turbo/`, `storybook-static/`, `*.tsbuildinfo` | `.gitignore` | | **Cache** | `.cache/`, `.parcel-cache/`, `.eslintcache`, `.stylelintcache`, `tsconfig.tsbuildinfo` | `.gitignore` | | **Coverage** | `coverage/`, `.nyc_output/`, `lcov.info` | `.gitignore` | | **Logs** | `*.log`, `npm-debug.log*`, `yarn-debug.log*`, `pnpm-debug.log*`, `lerna-debug.log*` | `.gitignore` | | **OS artifacts** | `.DS_Store`, `Thumbs.db`, `desktop.ini`, `._*`, `ehthumbs.db` | `.gitignore` | | **Editor/IDE** | `.idea/`, `*.iml`, `*.swp`, `*.swo`, `*~`, `.project`, `.classpath`, `.settings/` | `.gitignore` | | **Runtime** | `.wrangler/`, `.dev.vars`, `*.pid`, `*.seed`, `.env.sentry-build-plugin` | `.gitignore` | | **Package artifacts** | `*.tgz`, `*.tar.gz` (in repo root or release dirs) | `.gitignore` | | **Secrets** | `.env`, `.env.local`, `.env.*.local` (**NOT** `.env.example`, `.env.template`, `.env.sample`), `*.pem`, `*.key`, `*.p12`, `*.pfx`, `*.jks`, `*.keystore` | `.gitignore` + **warn user** | | **Large binaries** | Any single file > 5 MB not inside `src/` or `assets/` | **skip** + **warn user** (don't gitignore — let user decide) | | **Source (default)** | Everything else: source files, configs, docs, specs, tests, lock files, CI files, `.specweave/`, `.github/`, `*.md` | `git add <file>` |
**Critical**: `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml` are **Source** — always commit.
Phase 3: Update .gitignore (if patterns were added)
For each pattern classified as `.gitignore` in Phase 2:
1. **Check if .gitignore exists** — if not, create it 2. **Check if pattern already present** — `grep -qxF '<pattern>' .gitignore` (exact line match) or check if a parent pattern already covers it (e.g., `node_modules/` covers `node_modules/foo/`) 3. **Append missing patterns** under a clearly marked section:
# Auto-managed by sw:save — do not edit this section manually .DS_Store node_modules/ dist/ .env
If the `# Auto-managed by sw:save` section already exists, append new patterns there. Otherwise create it at the end of the file.
4. **Stage .gitignore**: `git add .gitignore`
Phase 4: Stage remaining approved source files
git add <each file classified as Source in Phase 2>
Use `git add` with explicit file paths — **never** `git add -A` or `git add .`.
Phase 5: Verify clean state
untracked=$(git ls-files --others --exclude-standard) if [ -n "$untracked" ]; then echo "WARNING: Remaining untracked files (not staged, not gitignored):" echo "$untracked" fi
- If **zero untracked** remain → clean state achieved, proceed
- If **untracked remain** (missed by classification) → warn, but still proceed with commit. These files carry forward to next save.
- In `--interactive` mode: prompt user for each remaining untracked file (stage / gitignore / s
Spec-first AI development: describe a feature → AI creates spec + plan + tasks, builds autonomously, syncs to GitHub/JIRA. Domain-expert skills for PM, Architect, Frontend, QA learn your patterns permanently. Claude Code, Codex, Cursor, Copilot & more.
Repo: anton-abyzov/specweave
Other commands on specweave.
- /abandon
Abandon an incomplete increment (requirements changed, obsolete)
Open command - /ado-cleanup-duplicates
Clean up duplicate Azure DevOps work items for a Feature. Finds work items with duplicate titles and closes all except the first created item.
Open command - /ado-clone
Clone Azure DevOps repositories to local workspace. Use after init if cloning was skipped, or to add repos later.
Open command - /ado-close
Close Azure DevOps work item when increment complete
Open command - /ado-create
Create Azure DevOps work item from SpecWeave increment
Open command - /ado-import-areas
Import Azure DevOps area paths from a project and map them to SpecWeave projects. Creates 2-level directory structure with area path-based organization.
Open command

