+
+
+
+
+
+
+
+
+
diff --git a/docs/wiki/Commands-Reference.md b/docs/wiki/Commands-Reference.md
new file mode 100644
index 0000000..e4e83de
--- /dev/null
+++ b/docs/wiki/Commands-Reference.md
@@ -0,0 +1,234 @@
+# Commands Reference
+
+## Summary
+
+| Command | Description |
+|---|---|
+| `snack list [category]` | List all snippets, optionally filtered by category |
+| `snack search ` | Search snippet filenames for a keyword |
+| `snack unpack [--flat] [--force]` | Copy a snippet from the stash into the current directory |
+| `snack pack [--force]` | Copy a snippet from the current directory into the stash |
+| `snack stash create ` | Register a new named stash directory |
+| `snack stash list` | List all configured stashes |
+| `snack stash move ` | Move a stash to a new location |
+| `snack stash add-remote [--subdir] [--force]` | Copy snippets from a GitHub repo into the active stash |
+
+All commands accept `--help` for inline usage information.
+
+---
+
+## Snippet commands
+
+These commands operate on the **active stash** (set via `snack stash create` or the `SNACK_STASH` env var).
+
+### `snack list`
+
+Lists all `.py` files in the stash, sorted alphabetically.
+
+```bash
+snack list
+```
+
+Output:
+
+```
+auth/google_oauth_fastapi.py
+auth/google_oauth_flask.py
+auth/jwt_helpers.py
+forms/contact_form.py
+forms/newsletter_signup.py
+email/smtp_sender.py
+```
+
+#### Filter by category
+
+Pass a category name (subdirectory) to narrow the output:
+
+```bash
+snack list auth
+```
+
+Output:
+
+```
+auth/google_oauth_fastapi.py
+auth/google_oauth_flask.py
+auth/jwt_helpers.py
+```
+
+---
+
+### `snack search`
+
+Searches snippet filenames (not file contents) for a keyword. Case-insensitive.
+
+```bash
+snack search oauth
+```
+
+Output:
+
+```
+auth/google_oauth_fastapi.py
+auth/google_oauth_flask.py
+```
+
+---
+
+### `snack unpack`
+
+Copies a snippet **from the stash** into the **current working directory**.
+
+```bash
+snack unpack auth/google_oauth_fastapi.py
+```
+
+The path is relative to the stash root. Use `snack list` or `snack search` to find the correct path.
+
+#### Flags
+
+| Flag | Description |
+|---|---|
+| `--flat` | Copy the file directly into the current directory, discarding subdirectory structure |
+| `--force` | Overwrite an existing file without prompting |
+
+#### Default (preserves structure)
+
+```bash
+cd ~/projects/my-app
+snack unpack auth/google_oauth_fastapi.py
+# Creates: ./auth/google_oauth_fastapi.py
+```
+
+#### `--flat`
+
+```bash
+snack unpack auth/google_oauth_fastapi.py --flat
+# Creates: ./google_oauth_fastapi.py
+```
+
+#### Overwrite prompt
+
+If the destination file already exists:
+
+```
+'./auth/google_oauth_fastapi.py' already exists. Overwrite? [y/N]:
+```
+
+Pass `--force` to skip the prompt.
+
+---
+
+### `snack pack`
+
+Copies a file **from the current working directory** into the stash. Use this when you have improved a snippet during a project and want to update the canonical version.
+
+```bash
+snack pack auth/google_oauth_fastapi.py
+```
+
+The path is relative to the current working directory and is used as-is inside the stash.
+
+#### Flags
+
+| Flag | Description |
+|---|---|
+| `--force` | Overwrite an existing stash file without prompting |
+
+---
+
+## Stash management commands
+
+### `snack stash create`
+
+Registers a new named stash directory and creates it on disk if it doesn't already exist.
+
+```bash
+snack stash create default ~/snack-stash
+snack stash create work ~/work-stash
+snack stash create work ~/work-stash --no-activate
+```
+
+The first stash created is automatically set as active. For subsequent stashes, use `--activate` (the default) to switch, or `--no-activate` to add without switching.
+
+#### Flags
+
+| Flag | Default | Description |
+|---|---|---|
+| `--activate` / `--no-activate` | `--activate` | Whether to set this as the active stash |
+
+---
+
+### `snack stash list`
+
+Shows all configured stashes with their paths, marking the active one.
+
+```bash
+snack stash list
+```
+
+Output:
+
+```
+ default /Users/you/snack-stash ← active
+ work /Users/you/work-stash
+```
+
+If a stash path no longer exists on disk, it is flagged:
+
+```
+ default /Users/you/snack-stash ← active [path missing!]
+```
+
+If `SNACK_STASH` env var is set, a note is shown at the bottom indicating it is overriding the active stash.
+
+---
+
+### `snack stash move`
+
+Moves a stash directory to a new location on disk and updates the path in `~/.snackstashrc`.
+
+```bash
+snack stash move default ~/new-location/snack-stash
+```
+
+- The old directory and all its contents are moved to the new path
+- The config is updated automatically
+- If the old path no longer exists on disk, the new directory is created instead
+- Errors if the new path already exists (to prevent accidental overwrites)
+
+---
+
+### `snack stash add-remote`
+
+Downloads a public GitHub repository as a tarball and copies all `.py` files into the active stash, preserving directory structure.
+
+```bash
+snack stash add-remote owner/repo
+snack stash add-remote https://github.com/owner/repo
+```
+
+#### Filter by subdirectory
+
+Only copy files from a specific subdirectory of the repo:
+
+```bash
+snack stash add-remote owner/repo --subdir auth
+```
+
+This copies `auth/google_oauth.py` from the repo as `auth/google_oauth.py` in the stash (the full path is preserved).
+
+#### Flags
+
+| Flag | Description |
+|---|---|
+| `--subdir ` | Only copy files under this subdirectory of the repo |
+| `--force` | Overwrite existing stash files without prompting |
+
+#### Accepted repo formats
+
+- `owner/repo`
+- `https://github.com/owner/repo`
+- `https://github.com/owner/repo.git`
+
+Non-Python files (`.md`, `.txt`, etc.) are never copied.
diff --git a/docs/wiki/Configuration.md b/docs/wiki/Configuration.md
new file mode 100644
index 0000000..b173697
--- /dev/null
+++ b/docs/wiki/Configuration.md
@@ -0,0 +1,99 @@
+# Configuration
+
+Snack Stash supports multiple named stashes. The active stash is used by all snippet commands (`list`, `search`, `unpack`, `pack`).
+
+## Priority Order
+
+1. `SNACK_STASH` environment variable (overrides everything)
+2. Active stash in `~/.snackstashrc`
+3. Error — nothing is configured
+
+---
+
+## Method 1: Named stashes (recommended)
+
+Use `snack stash create` to register stashes. This is the standard workflow and requires no manual config editing.
+
+```bash
+# Create your first stash (auto-activated)
+snack stash create default ~/snack-stash
+
+# Add a second stash without switching to it
+snack stash create work ~/work-stash --no-activate
+
+# See what's configured
+snack stash list
+# default /Users/you/snack-stash ← active
+# work /Users/you/work-stash
+```
+
+This writes `~/.snackstashrc` in INI format:
+
+```ini
+[config]
+active = default
+
+[stash.default]
+path = /Users/you/snack-stash
+
+[stash.work]
+path = /Users/you/work-stash
+```
+
+You can edit this file by hand if needed.
+
+---
+
+## Method 2: Environment variable
+
+Set `SNACK_STASH` to override the config file entirely. Useful for scripts, CI, or quickly switching context.
+
+```bash
+export SNACK_STASH=~/snack-stash
+```
+
+Add to `~/.zshrc` or `~/.bashrc` to make it permanent:
+
+```bash
+echo 'export SNACK_STASH=~/snack-stash' >> ~/.zshrc
+```
+
+When `SNACK_STASH` is set, named stashes in the config file are ignored for all snippet commands. `snack stash list` will still display configured stashes but will note the override.
+
+---
+
+## Stash directory structure
+
+A stash is a plain directory of `.py` files, organized into subdirectories by category. No special files or metadata are required.
+
+```
+~/snack-stash/
+├── auth/
+│ ├── google_oauth_fastapi.py
+│ ├── google_oauth_flask.py
+│ └── jwt_helpers.py
+├── forms/
+│ ├── contact_form.py
+│ └── newsletter_signup.py
+└── email/
+ └── smtp_sender.py
+```
+
+The directory can be managed with Git, Dropbox, or any other sync mechanism independently of this tool. Syncing is outside the scope of `snack` — it only copies files in and out.
+
+---
+
+## Switching the active stash
+
+To change which named stash is active, create a new one with `--activate` or edit `~/.snackstashrc` directly and update the `active` key under `[config]`.
+
+---
+
+## Verifying your configuration
+
+```bash
+snack stash list # see all stashes and which is active
+snack list # confirm the active stash has snippets
+```
+
+See [[Error-Reference]] for help with configuration errors.
diff --git a/docs/wiki/Contributing.md b/docs/wiki/Contributing.md
new file mode 100644
index 0000000..71b1104
--- /dev/null
+++ b/docs/wiki/Contributing.md
@@ -0,0 +1,74 @@
+# Contributing
+
+## Dev Setup
+
+Clone the repo and install in editable mode with test dependencies:
+
+```bash
+git clone https://github.com/kickash/python-snacks.git
+cd python-snacks
+pip install -e ".[test]"
+```
+
+Verify the CLI works:
+
+```bash
+snack --help
+```
+
+## Running Tests
+
+```bash
+pytest tests/ -v
+```
+
+The test suite has 33 tests across two files:
+
+- `tests/test_commands.py` — snippet commands (`list`, `search`, `unpack`, `pack`), config resolution, error cases
+- `tests/test_stash_commands.py` — stash management commands (`create`, `list`, `move`, `add-remote`), including mocked HTTP for `add-remote`
+
+Tests never write to `~/.snackstashrc` — the config path is redirected to a temp file via `monkeypatch`.
+
+## CI
+
+Every push and pull request to `main` runs the test suite against Python 3.10, 3.11, and 3.12 via GitHub Actions (`.github/workflows/ci.yml`). Pull requests must pass CI before merging.
+
+## Release Process
+
+Releases are fully automated via `.github/workflows/publish.yml`.
+
+1. Update the version in `pyproject.toml`
+2. Commit and push to `main`
+3. Tag the commit with a `v`-prefixed version and push the tag:
+
+```bash
+git tag v0.2.0
+git push origin v0.2.0
+```
+
+The publish workflow will:
+- Run the test suite
+- Build the sdist and wheel
+- Publish to PyPI (via OIDC trusted publishing — no API token required)
+- Create a GitHub Release with the built artifacts attached
+
+## Project Structure
+
+```
+python-snacks/
+├── pyproject.toml # Package metadata and dependencies
+├── snacks/
+│ ├── main.py # Typer app and all command definitions
+│ ├── config.py # SnackConfig class, stash path resolution
+│ └── ops.py # File ops: pack, unpack, add_remote
+└── tests/
+ ├── test_commands.py # Snippet command tests
+ └── test_stash_commands.py # Stash management tests
+```
+
+## Key design notes
+
+- **Config format:** `~/.snackstashrc` uses INI format (`[stash.]` sections). The old `stash=` sectionless format is still read for backwards compatibility but never written.
+- **`SNACK_STASH` env var:** Always overrides the config file for all snippet commands. Useful for scripts and CI.
+- **`add-remote`:** Uses only stdlib (`urllib`, `tarfile`) — no additional dependencies beyond Typer.
+- **Test isolation:** `monkeypatch.setattr(config_module, "CONFIG_PATH", ...)` redirects the config file to a temp path so tests are hermetic.
diff --git a/docs/wiki/Error-Reference.md b/docs/wiki/Error-Reference.md
new file mode 100644
index 0000000..6b75f8f
--- /dev/null
+++ b/docs/wiki/Error-Reference.md
@@ -0,0 +1,166 @@
+# Error Reference
+
+## Stash not configured
+
+**Message:**
+```
+[error] Snack stash location is not configured.
+Create a stash with:
+ snack stash create default ~/snack-stash
+Or set the SNACK_STASH environment variable:
+ export SNACK_STASH=~/snack-stash
+```
+
+**Cause:** No stash has been created and `SNACK_STASH` is not set.
+
+**Fix:** Run `snack stash create default ~/snack-stash` to get started. See [[Configuration]] for full details.
+
+---
+
+## Stash path does not exist
+
+**Message:**
+```
+[error] SNACK_STASH is set to '/path/to/stash' but that path does not exist.
+```
+
+or
+
+```
+[error] Active stash 'default' path '/path/to/stash' does not exist.
+```
+
+**Cause:** The configured path is not present on disk. Common reasons:
+- The directory was moved or deleted manually (use `snack stash move` instead)
+- A typo in the path
+- The drive or volume it lives on is not mounted
+
+**Fix:** Either recreate the directory, correct the path in `~/.snackstashrc`, or run `snack stash move` to point the stash to its new location.
+
+---
+
+## Snippet not found in stash (`unpack`)
+
+**Message:**
+```
+[error] 'auth/nope.py' not found in stash (/path/to/stash).
+```
+
+**Cause:** The path passed to `snack unpack` does not exist in the stash.
+
+**Fix:** Use `snack list` or `snack search` to find the correct path:
+
+```bash
+snack list auth
+snack search oauth
+```
+
+---
+
+## Source file not found (`pack`)
+
+**Message:**
+```
+[error] 'auth/google_oauth.py' not found in current directory.
+```
+
+**Cause:** The file passed to `snack pack` does not exist relative to the current working directory.
+
+**Fix:** Check your working directory and the path you provided:
+
+```bash
+pwd
+ls auth/
+```
+
+---
+
+## Overwrite conflict
+
+**Message:**
+```
+'/path/to/file.py' already exists. Overwrite? [y/N]:
+```
+
+**Cause:** The destination file already exists. Applies to `snack unpack`, `snack pack`, and `snack stash add-remote`.
+
+**Fix:**
+- Answer `y` at the prompt to overwrite
+- Answer `n` (or press Enter) to abort
+- Pass `--force` to skip the prompt:
+
+```bash
+snack unpack auth/google_oauth.py --force
+snack pack auth/google_oauth.py --force
+snack stash add-remote owner/repo --force
+```
+
+---
+
+## Stash name already exists (`stash create`)
+
+**Message:**
+```
+[error] A stash named 'default' already exists.
+```
+
+**Cause:** You ran `snack stash create` with a name that is already registered in `~/.snackstashrc`.
+
+**Fix:** Choose a different name, or edit `~/.snackstashrc` directly to remove the existing entry first.
+
+---
+
+## Unknown stash name (`stash move`)
+
+**Message:**
+```
+[error] No stash named 'foo'. Run 'snack stash list' to see available stashes.
+```
+
+**Cause:** The name passed to `snack stash move` is not registered in `~/.snackstashrc`.
+
+**Fix:** Run `snack stash list` to see valid names.
+
+---
+
+## Move target already exists (`stash move`)
+
+**Message:**
+```
+[error] '/new/path' already exists.
+```
+
+**Cause:** The destination path for `snack stash move` is already present on disk.
+
+**Fix:** Choose a different target path, or remove the existing directory first if it is safe to do so.
+
+---
+
+## GitHub repo not found or inaccessible (`stash add-remote`)
+
+**Message:**
+```
+[error] HTTP 404: Not Found
+```
+
+**Cause:** The repository does not exist, is private, or the URL is incorrect.
+
+**Fix:** Check the repo name and ensure it is public. Private repos are not supported without a token (which is not currently a supported feature).
+
+---
+
+## Invalid repo format (`stash add-remote`)
+
+**Message:**
+```
+[error] Invalid repo 'not-a-repo'. Use 'owner/repo' or a full GitHub URL.
+```
+
+**Cause:** The argument passed to `snack stash add-remote` could not be parsed.
+
+**Fix:** Use one of the supported formats:
+
+```bash
+snack stash add-remote owner/repo
+snack stash add-remote https://github.com/owner/repo
+```
diff --git a/docs/wiki/Home.md b/docs/wiki/Home.md
new file mode 100644
index 0000000..4195df1
--- /dev/null
+++ b/docs/wiki/Home.md
@@ -0,0 +1,39 @@
+# python-snacks
+
+A personal CLI tool for managing a local stash of reusable Python code snippets. Copy snippets in and out of projects with a single command, and manage multiple named stashes.
+
+## Quick Start
+
+```bash
+# Install
+pipx install python-snacks
+
+# Create your first stash
+snack stash create default ~/snack-stash
+
+# Browse what you have
+snack list
+
+# Pull snippets from a GitHub repo into your stash
+snack stash add-remote owner/my-snippets
+
+# Copy a snippet into your project
+snack unpack auth/google_oauth.py
+
+# Copy an improved snippet back into the stash
+snack pack auth/google_oauth.py
+```
+
+## Pages
+
+- [[Installation]] — Install via pipx or pip
+- [[Configuration]] — Named stashes, env var, and config file
+- [[Commands-Reference]] — Full reference for all commands and flags
+- [[Writing-Good-Snippets]] — How to write snippets that stay reusable
+- [[Error-Reference]] — Diagnose and fix common errors
+- [[Contributing]] — Dev setup, tests, and release process
+
+## Links
+
+- [PyPI — python-snacks](https://pypi.org/project/python-snacks/)
+- [GitHub Repository](https://github.com/kickash/python-snacks)
diff --git a/docs/wiki/Installation.md b/docs/wiki/Installation.md
new file mode 100644
index 0000000..f07f075
--- /dev/null
+++ b/docs/wiki/Installation.md
@@ -0,0 +1,56 @@
+# Installation
+
+## Requirements
+
+- Python 3.10 or later
+
+## Recommended: pipx
+
+[pipx](https://pipx.pypa.io) installs CLI tools in isolated environments so they don't conflict with your project dependencies.
+
+```bash
+pipx install python-snacks
+```
+
+## Alternative: pip
+
+```bash
+pip install python-snacks
+```
+
+If you want it available globally, use `pip install --user python-snacks` or install inside a virtual environment you always activate.
+
+## Verify
+
+```bash
+snack --help
+```
+
+You should see:
+
+```
+Usage: snack [OPTIONS] COMMAND [ARGS]...
+
+ Manage your personal snack stash of reusable Python snippets.
+
+Commands:
+ unpack Copy a snippet FROM the stash INTO the current working directory.
+ pack Copy a snippet FROM the current working directory INTO the stash.
+ list List all snippets in the stash.
+ search Search snippet filenames for a keyword.
+ stash Manage stash directories.
+```
+
+## Upgrading
+
+```bash
+pipx upgrade python-snacks
+# or
+pip install --upgrade python-snacks
+```
+
+New versions are published to PyPI automatically when a `v*` tag is pushed to the repository.
+
+## Next Step
+
+[[Configuration]] — create your first stash and tell the tool where it lives.
diff --git a/docs/wiki/Writing-Good-Snippets.md b/docs/wiki/Writing-Good-Snippets.md
new file mode 100644
index 0000000..8e69e25
--- /dev/null
+++ b/docs/wiki/Writing-Good-Snippets.md
@@ -0,0 +1,120 @@
+# Writing Good Snippets
+
+A snippet is only as useful as it is reusable. These guidelines help you write snippets that are easy to drop into any project and immediately understand.
+
+---
+
+## The core principle: self-containment
+
+A snippet should work correctly after a single `cp` into a new project. That means:
+
+- All imports are explicit and at the top of the file
+- All configuration comes from parameters or environment variables — never hardcoded values
+- No assumptions about what else exists in the project
+- No side effects at import time (wrap executable code in functions or `if __name__ == "__main__"`)
+
+If unpacking a snippet requires you to also copy another file, refactor until it doesn't.
+
+---
+
+## Use a standard header
+
+The single most useful habit is a consistent docstring that captures three things: what the snippet does, what it depends on, and how to use it. Anyone (including future you) can read this without opening the file.
+
+```python
+"""Send transactional email via SMTP.
+
+Dependencies:
+ stdlib only
+
+Usage:
+ from email.smtp_sender import send_email
+ send_email(to="user@example.com", subject="Hello", body="
World
")
+
+Config (env vars):
+ SMTP_HOST — mail server hostname
+ SMTP_PORT — defaults to 587
+ SMTP_USER — sender login
+ SMTP_PASSWORD — sender password
+"""
+```
+
+Keep it short. The goal is a five-second orientation, not full API documentation.
+
+---
+
+## Name files to be searchable
+
+Filenames are the primary search surface — `snack search` matches against them. Choose names that are specific and predictable.
+
+**Good:**
+```
+auth/google_oauth_fastapi.py
+auth/google_oauth_flask.py
+forms/contact_form_wtf.py
+email/smtp_sender.py
+storage/s3_upload.py
+```
+
+**Avoid:**
+```
+auth/helpers.py # too vague
+auth/utils.py # tells you nothing
+auth/new_version.py # not a meaningful name
+```
+
+When a snippet has framework-specific variants, use a suffix: `_fastapi`, `_flask`, `_django`, `_sqlalchemy`. This makes `snack search fastapi` return only what's relevant.
+
+---
+
+## One file, one job
+
+Resist the urge to bundle related utilities into a single file. A snippet called `auth_helpers.py` that contains OAuth, JWT, and session logic will only ever be partially useful. Three focused snippets are more valuable than one large one.
+
+The right size for a snippet is: "I need exactly this, and I copy exactly this."
+
+---
+
+## Organise by what a project needs, not by technical category
+
+Think about how you reach for snippets when starting a project. Categories like `auth/`, `forms/`, `email/`, `storage/`, `payments/` map to features. Categories like `decorators/` or `metaclasses/` map to implementation details and are harder to browse purposefully.
+
+```
+~/snack-stash/
+├── auth/ # authentication and authorisation
+├── email/ # sending and templating emails
+├── forms/ # form handling and validation
+├── payments/ # Stripe, etc.
+├── storage/ # file uploads, S3, local disk
+└── tasks/ # background jobs, queues
+```
+
+---
+
+## Keep configuration out of the code
+
+Configuration that varies per-project (API keys, hostnames, feature flags) should be read from environment variables or passed as function arguments. Never commit a snippet with hardcoded credentials or URLs.
+
+```python
+# Good — caller provides credentials
+def create_oauth_client(client_id: str, client_secret: str) -> OAuth2Session:
+ ...
+
+# Good — reads from environment
+STRIPE_KEY = os.environ["STRIPE_SECRET_KEY"]
+
+# Bad — hardcoded
+STRIPE_KEY = "sk_live_abc123"
+```
+
+---
+
+## Update the stash when you improve a snippet
+
+The stash is most valuable when it reflects your current best practice, not the version from two years ago. When you improve a snippet during a project, pack it back:
+
+```bash
+snack pack auth/google_oauth_fastapi.py
+```
+
+If you manage your stash as a Git repo, commit the improvement there too. The stash stays useful only if it gets maintained like any other codebase.