Skip to main content

Invisible, auto-syncing personal storage for any git repo

Project description

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

swarf-0.4.0-py3-none-musllinux_1_2_x86_64.whl (6.1 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

swarf-0.4.0-py3-none-musllinux_1_2_aarch64.whl (5.8 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

swarf-0.4.0-py3-none-manylinux_2_17_x86_64.whl (6.1 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

swarf-0.4.0-py3-none-manylinux_2_17_aarch64.whl (5.8 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

swarf-0.4.0-py3-none-macosx_11_0_arm64.whl (5.9 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

swarf-0.4.0-py3-none-macosx_10_9_x86_64.whl (6.3 MB view details)

Uploaded Python 3macOS 10.9+ x86-64

File details

Details for the file swarf-0.4.0-py3-none-musllinux_1_2_x86_64.whl.

File metadata

  • Download URL: swarf-0.4.0-py3-none-musllinux_1_2_x86_64.whl
  • Upload date:
  • Size: 6.1 MB
  • Tags: Python 3, musllinux: musl 1.2+ x86-64
  • Uploaded using 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}

File hashes

Hashes for swarf-0.4.0-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 98969534126774320130174a0c73bce1b08f67aa06e6d74d543f052648d6dd48
MD5 54d3a645425ef7478ddc6412bfd9e1a9
BLAKE2b-256 8ed3204ee9c23a92a84d9ce1b0fb0aab39fbdacc3c3dad84620efc4391ba3fd8

See more details on using hashes here.

File details

Details for the file swarf-0.4.0-py3-none-musllinux_1_2_aarch64.whl.

File metadata

  • Download URL: swarf-0.4.0-py3-none-musllinux_1_2_aarch64.whl
  • Upload date:
  • Size: 5.8 MB
  • Tags: Python 3, musllinux: musl 1.2+ ARM64
  • Uploaded using 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}

File hashes

Hashes for swarf-0.4.0-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 eb5aa64614cb33fe842736a8a6de2dcec2af476ccbf9b88d5ac99264bba0bb8f
MD5 0cd33053558f9f92145859dbd9dd8921
BLAKE2b-256 92931b76f7781baca126264b02e15dd24e863d5940f0388d7003ea5bd7c4edd8

See more details on using hashes here.

File details

Details for the file swarf-0.4.0-py3-none-manylinux_2_17_x86_64.whl.

File metadata

  • Download URL: swarf-0.4.0-py3-none-manylinux_2_17_x86_64.whl
  • Upload date:
  • Size: 6.1 MB
  • Tags: Python 3, manylinux: glibc 2.17+ x86-64
  • Uploaded using 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}

File hashes

Hashes for swarf-0.4.0-py3-none-manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 a5d8d7baf3a2116fd9d62e4361c8926f581c5da274e624153ad85f5d8be743a9
MD5 6c8a69120be58d648b76ab6907fa557c
BLAKE2b-256 0457acbeebbca675379b7fabedb1ead7ec5b1afe0540526f77db553ec7bb2246

See more details on using hashes here.

File details

Details for the file swarf-0.4.0-py3-none-manylinux_2_17_aarch64.whl.

File metadata

  • Download URL: swarf-0.4.0-py3-none-manylinux_2_17_aarch64.whl
  • Upload date:
  • Size: 5.8 MB
  • Tags: Python 3, manylinux: glibc 2.17+ ARM64
  • Uploaded using 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}

File hashes

Hashes for swarf-0.4.0-py3-none-manylinux_2_17_aarch64.whl
Algorithm Hash digest
SHA256 9e5aa66ad0bed35463b3c40b92becf84187a8d8d929c7f4cf8e51c0672bfd14f
MD5 aefc3bd536580c2844b1cdaea391fa3d
BLAKE2b-256 60655d19cd9f503a957da0bcd698a15886cffd60777cccac4b0332c9ba863060

See more details on using hashes here.

File details

Details for the file swarf-0.4.0-py3-none-macosx_11_0_arm64.whl.

File metadata

  • Download URL: swarf-0.4.0-py3-none-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 5.9 MB
  • Tags: Python 3, macOS 11.0+ ARM64
  • Uploaded using 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}

File hashes

Hashes for swarf-0.4.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 9d28534bae2c21eee6969c5846173dd1c4bb25638b712e04ad273b9e61ac07a4
MD5 416b184a4f1bed0c2f206f6243af128b
BLAKE2b-256 58c841e11e859269062efab1c67eb885cc628b5366eda819d42b9f643665b602

See more details on using hashes here.

File details

Details for the file swarf-0.4.0-py3-none-macosx_10_9_x86_64.whl.

File metadata

  • Download URL: swarf-0.4.0-py3-none-macosx_10_9_x86_64.whl
  • Upload date:
  • Size: 6.3 MB
  • Tags: Python 3, macOS 10.9+ x86-64
  • Uploaded using 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}

File hashes

Hashes for swarf-0.4.0-py3-none-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 4f4d92461993683c503470ec0e2172a77ea3857935d9566d5d525b676ba81605
MD5 2b23a0ed09761efd8766329167a39f7b
BLAKE2b-256 3155ab627f3a52c1453f81cfa709bc5c971c9dd1aad10a3b9ae1400dfa40545e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page