Skip to main content

Swarf

CI PyPI Go License

Invisible, auto-syncing personal storage for any git repo.

You build software and generate byproduct — research docs, design specs, agent skills, scratch notes. Swarf gives this material a durable home alongside any project, without touching the project itself.

The problem

You have files that should live near your code but don't belong in the repo:

  • Agent instructions and skills (AGENTS.md, .copilot/skills/)
  • Research notes, design docs, open questions
  • Security audits, experiment logs, scratch work

Today these files are either untracked and local-only (one rm -rf from gone) or committed to the repo (polluting history, leaking on public repos). Neither is good.

How it works

Swarf creates a swarf/ directory inside your project. Everything in it is automatically excluded from git via .git/info/exclude. A background daemon watches for changes, mirrors them to a central store, and syncs to your configured remote (a git repo or any rclone backend).

my-project/
├── src/
├── swarf/                         ← private storage (invisible to git)
│   ├── docs/                      ← research, design, anything
│   ├── .links/                    ← files projected into the host tree
│   │   └── AGENTS.md
│   └── open-questions.md
├── AGENTS.md → swarf/.links/AGENTS.md   ← symlink (also gitignored)
└── .git/info/exclude              ← managed by swarf

The central store at ~/.local/share/swarf/ mirrors all projects into a single git repo. The daemon commits changes locally, then pushes to your remote. For rclone backends, the entire store is synced — both working files and .git/. This means you can browse your files directly in Google Drive (or whatever backend), and you get full commit history too.

Install

# macOS / Linux (recommended)
brew install swarf

# Via PyPI (persistent install to ~/.local/bin/)
pipx install swarf        # or: uv tool install swarf

# Via Go
go install github.com/mschulkind-oss/swarf@latest

# From source
git clone https://github.com/mschulkind-oss/swarf && cd swarf
just deploy   # builds and copies to ~/.local/bin/

Warning: Don't use pip install swarf inside a virtualenv or uvx swarf. The daemon records the binary's absolute path and breaks when the venv disappears. swarf doctor detects this and warns you.

Quick start

cd ~/projects/my-app
swarf init

On first run, init walks you through setup:

No global config found. Let's set one up.

  Backend [git/rclone] (git): git
  Remote URL (your private backup repo): git@github.com:you/my-swarf.git
✓ Wrote ~/.config/swarf/config.toml
✓ Created central store at ~/.local/share/swarf
✓ Initialized swarf/ for my-app
  Install systemd service for auto-sync? [Y/n] y
✓ Installed systemd service — daemon is running
✓ Daemon is running (PID 12345)

✓ All checks passed.

Next time you run swarf init in another project — no prompts, instant setup.

Rclone backend (Google Drive, Dropbox, S3, etc.)

Set up an rclone remote first:

brew install rclone
rclone config
#   → n (new remote), name: gdrive, type: drive
#   → scope: drive.file (option 2 — only files rclone creates)
#   → auto config: y (opens browser for OAuth)

Then run swarf init, pick rclone, and select your remote from the numbered menu. Swarf defaults to swarf-store as the directory path:

  Backend [git/rclone] (git): rclone

  Pick an rclone remote:

    1. gdrive:

  Enter a number (1-1), or q to quit: 1

  Directory path on gdrive: [swarf-store]:
✓ Remote: gdrive:swarf-store

The store is always a local git repo. Rclone syncs the whole store to the remote — your files are browseable directly in Google Drive (or wherever), and you get full git history via the .git/ directory.

Using swarf

Drop files in

echo "# Design Notes" > swarf/docs/design.md

That's it. The daemon commits and syncs after a 5-second quiet period.

Sweep files into the host tree

Some files need to appear at a specific path in the project (like AGENTS.md in the root). Use sweep to move them into swarf while leaving a symlink:

swarf sweep AGENTS.md
# AGENTS.md → swarf/.links/AGENTS.md

swarf sweep CLAUDE.md .copilot/skills/SKILL.md

Both the original path and swarf/ are automatically gitignored. Symlinks are relative, so they work across machines and inside containers.

To reverse a sweep:

swarf unlink AGENTS.md

Auto-sweep

Configure files to be swept automatically whenever they appear:

# ~/.config/swarf/config.toml
[auto_sweep]
paths = ["AGENTS.md", "CLAUDE.md", ".copilot/skills/"]

The daemon watches for these files and sweeps them on creation.

Check status

swarf status

Shows store state, pending files, remote verification, and daemon health:

Store
  Path           ~/.local/share/swarf
  Backend        git
  Remote         git@github.com:you/my-swarf.git
  Pending        all synced to remote
  Last commit    2 minutes ago — auto: sync 3 files
  Local save     2m ago
  Remote push    2m ago
  Remote sync    verified — local and remote match (a1b2c3d4)

Projects
╭──────────┬─────────────────────┬──────────╮
│ PROJECT  │ PATH                │ STATUS   │
├──────────┼─────────────────────┼──────────┤
│ my-app   │ ~/projects/my-app   │ ✓ ok     │
│ api      │ ~/work/api          │ ✓ ok     │
╰──────────┴─────────────────────┴──────────╯

Daemon: running (PID 12345)

Doctor

swarf doctor checks everything and fixes what it can:

swarf doctor

Doctor handles: missing config, missing store, broken symlinks, absolute symlinks, missing gitignore entries, service installation, and remote reachability. Errors include the exact fix command or config file to edit.

init and doctor share the same engine — the difference is that init creates swarf/ in a new directory, while doctor only checks and repairs.

Commands

Command Description
swarf init Set up swarf in the current project
swarf sweep <file>... Move files into swarf/.links/ and symlink back
swarf unlink <file>... Reverse a sweep — restore symlinks to regular files
swarf doctor Check health and fix problems (config, store, service, links)
swarf status Show projects, sync state, remote verification, daemon health
swarf clone Clone the store from your configured remote (new machine setup)
swarf pull Pull latest changes from the remote into the store
swarf daemon start Start the background sync daemon (--foreground for debugging)
swarf daemon stop Stop the daemon
swarf daemon status Check if the daemon is running
swarf daemon install Install as system service (systemd on Linux, launchd on macOS)
swarf docs [topic] Browse built-in documentation

Second machine setup

brew install swarf
swarf clone              # clones your store from the configured remote
cd ~/projects/my-app
swarf init               # re-links the project from the store

clone requires global config to exist (with the remote URL). After cloning, run swarf init in each project directory to recreate the local swarf/ directory and symlinks.

Containers and jails

The daemon runs on the host. Containers mount the project directory, so swarf/ comes along. Agents read and write to swarf/ directly — the host daemon picks up changes and syncs.

Inside a container, swarf doctor detects the environment (no global config), skips system checks, and validates project-local state only. sweep and unlink work without the daemon. Symlinks are relative, so they resolve correctly regardless of mount path.

Guides

  • Configuration Guide — all config options, file locations, environment variables, and examples
  • Roadmap — planned features and distribution channels
  • Built-in docs: swarf docs lists all topics (quickstart, architecture, config, sweep, daemon, backends)

License

Apache 2.0

Metadata

Release files for swarf 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for swarf 0.4.0
File
swarf-0.4.0-py3-none-musllinux_1_2_x86_64.whl Python 3 none Linux musl 1.2+ x86-64 Details
swarf-0.4.0-py3-none-musllinux_1_2_aarch64.whl Python 3 none Linux musl 1.2+ ARM64 Details
swarf-0.4.0-py3-none-manylinux_2_17_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details
swarf-0.4.0-py3-none-manylinux_2_17_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details
swarf-0.4.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
swarf-0.4.0-py3-none-macosx_10_9_x86_64.whl Python 3 none macOS 10.9+ x86-64 Details

Total release size: 36.1 MB

Release files / swarf-0.4.0-py3-none-musllinux_1_2_x86_64.whl

Download URL swarf-0.4.0-py3-none-musllinux_1_2_x86_64.whl
Size 6.1 MB
Tags Linux musl 1.2+ x86-64 Python 3
SHA-256 checksum
How to use checksums
98969534126774320130174a0c73bce1b08f67aa06e6d74d543f052648d6dd48
BLAKE2b-256 checksum
How to use checksums
8ed3204ee9c23a92a84d9ce1b0fb0aab39fbdacc3c3dad84620efc4391ba3fd8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / swarf-0.4.0-py3-none-musllinux_1_2_aarch64.whl

Download URL swarf-0.4.0-py3-none-musllinux_1_2_aarch64.whl
Size 5.8 MB
Tags Linux musl 1.2+ ARM64 Python 3
SHA-256 checksum
How to use checksums
eb5aa64614cb33fe842736a8a6de2dcec2af476ccbf9b88d5ac99264bba0bb8f
BLAKE2b-256 checksum
How to use checksums
92931b76f7781baca126264b02e15dd24e863d5940f0388d7003ea5bd7c4edd8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / swarf-0.4.0-py3-none-manylinux_2_17_x86_64.whl

Download URL swarf-0.4.0-py3-none-manylinux_2_17_x86_64.whl
Size 6.1 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
a5d8d7baf3a2116fd9d62e4361c8926f581c5da274e624153ad85f5d8be743a9
BLAKE2b-256 checksum
How to use checksums
0457acbeebbca675379b7fabedb1ead7ec5b1afe0540526f77db553ec7bb2246
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / swarf-0.4.0-py3-none-manylinux_2_17_aarch64.whl

Download URL swarf-0.4.0-py3-none-manylinux_2_17_aarch64.whl
Size 5.8 MB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
9e5aa66ad0bed35463b3c40b92becf84187a8d8d929c7f4cf8e51c0672bfd14f
BLAKE2b-256 checksum
How to use checksums
60655d19cd9f503a957da0bcd698a15886cffd60777cccac4b0332c9ba863060
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / swarf-0.4.0-py3-none-macosx_11_0_arm64.whl

Download URL swarf-0.4.0-py3-none-macosx_11_0_arm64.whl
Size 5.9 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
9d28534bae2c21eee6969c5846173dd1c4bb25638b712e04ad273b9e61ac07a4
BLAKE2b-256 checksum
How to use checksums
58c841e11e859269062efab1c67eb885cc628b5366eda819d42b9f643665b602
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / swarf-0.4.0-py3-none-macosx_10_9_x86_64.whl

Download URL swarf-0.4.0-py3-none-macosx_10_9_x86_64.whl
Size 6.3 MB
Tags Python 3 macOS 10.9+ x86-64
SHA-256 checksum
How to use checksums
4f4d92461993683c503470ec0e2172a77ea3857935d9566d5d525b676ba81605
BLAKE2b-256 checksum
How to use checksums
3155ab627f3a52c1453f81cfa709bc5c971c9dd1aad10a3b9ae1400dfa40545e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.4.0 This release

6 release files

0.3.0

6 release files

0.2.0

6 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page