Repository navigation
Releases: nimblemo/insta-boards
Release list
v0.1.3 — Standalone binaries, and four .env bugs fixed
v0.1.3 — Standalone binaries, and four .env bugs fixed
This release adds prebuilt, self-bootstrapping binaries for six platforms,
published straight to this GitHub Releases page — so insta-boards no longer
requires a Python toolchain to install. It also fixes four real bugs in
.env handling that silently ignored your configuration, including on
plain PyPI installs.
Prebuilt binaries — no Python required
Every release now ships six archives, built and smoke-tested in CI:
| Platform | Archive |
|---|---|
| Linux x86_64 | insta-boards-x86_64-unknown-linux-gnu.tar.gz |
| Linux aarch64 | insta-boards-aarch64-unknown-linux-gnu.tar.gz |
| macOS Intel | insta-boards-x86_64-apple-darwin.tar.gz |
| macOS Apple Silicon | insta-boards-aarch64-apple-darwin.tar.gz |
| Windows x86_64 | insta-boards-x86_64-pc-windows-msvc.zip |
| Windows ARM64 | insta-boards-aarch64-pc-windows-msvc.zip |
The binaries are built with uvbox,
which produces a small launcher rather than a frozen Python. On first run
the launcher bootstraps uv, fetches a Python interpreter and installs the
package; subsequent runs are fast and offline.
First run needs network access. This is not an offline bundle — the
interpreter is downloaded on demand. After that the tool runs as a normal
Python process and inherits your working directory, sodata/,secrets/
and.envresolve relative to where you invoke it.
Generated binaries also expose a small self-management CLI:
insta-boards self update # upgrade to the latest published version
insta-boards self remove # uninstall
insta-boards self path # print the install root
insta-boards self cache # print the cache dir
insta-boards self uv # print the bundled uv pathFour .env bugs fixed
These affected every install method, not just the new binaries — the
packaging audit is what surfaced them.
| Bug | Symptom | Fix |
|---|---|---|
| Eager constants | IG_DOWNLOAD_TIMEOUT, IG_DOWNLOAD_DELAY, IG_DOWNLOAD_RETRIES, IG_DOWNLOAD_BACKOFF were read at import time, before load_env() ran — values from .env were silently ignored. |
Replaced with lazy accessors, evaluated at call time. |
IG_STATE_PATH in sync |
The state path was computed before load_env(), so a custom path in .env had no effect. |
load_env() now runs first in main(), and --workdir is applied before dispatch. |
IG_DOWNLOAD_POOL_REUSE |
Parsed but never passed anywhere — a dead knob. | Now wired through to DownloadPool; exposed as DownloadPool.reuse_pool. |
| Empty value masking | An empty assignment (KEY=) in a higher-priority .env counted as set and shadowed a real value in a lower-priority .env. |
load_env() switched to dotenv_values() with manual application: an empty value means "not set". |
More deterministic data root
repo_root() no longer guesses. Resolution order is now:
IG_REPO_ROOT(absolute path or~-prefixed), if set;- otherwise the nearest ancestor that is a real checkout — it must contain
bothpyproject.tomlandsrc/paths.py; - otherwise the current working directory.
This stops an unrelated pyproject.toml higher up the tree from hijacking
where data/ is written — which matters now that the binary runs from
wherever you happen to be.
Docs and tests
README.md— new Prebuilt binaries section, a Where configuration is
read from subsection, and theIG_REPO_ROOTvariable.docs/uvbox-packaging-audit.md— the full.envaudit report.- 18 regression tests covering the lazy accessors,
.envprecedence and
repo_root()resolution.
Upgrading
# PyPI
uv tool upgrade insta-boards
# or a prebuilt binary
insta-boards self updateExisting installs need no migration — the .env fixes make previously
ignored settings take effect, so double-check IG_DOWNLOAD_* and
IG_STATE_PATH if you were setting them and seeing no change.
v0.1.2 —Public release
v0.1.2 — First public release
The first official release of insta-boards, a CLI for backing up every
Instagram Saved Collection into a plain, human-readable on-disk layout.
This release ships the unified entry point, a clean rename, MIT licensing,
and a fully automated PyPI release pipeline.
What is insta-boards?
insta-boards is a small, opinionated CLI that talks to Instagram's
private API (via instagrapi),
walks every Saved Collection on the account, and writes the result
to disk as one directory per collection: media files + per-item JSON
metadata + a top-level index. Re-runs are state-aware and incremental —
interrupt-safe, resumable, and friendly to rate limits.
Unified CLI — one entry point, four subcommands
The previous four entry points (sync-instagram, list-collections,
list-items, download-collection) are replaced by a single command
with subcommands. Pick the verb; everything else is a flag.
| Command | Purpose |
|---|---|
insta-boards sync |
Full sync of all collections (state-aware, resumable). |
insta-boards list boards |
JSONL of every collection on the account. |
insta-boards list items --collection <id> |
JSONL of items in a single collection. |
insta-boards download --collection <id> |
Download a single collection into data/raw/<slug>/. |
Migration:
# before
sync-instagram --dry-run
list-collections
list-items --collection 18427410172124759
download-collection --collection 18427410172124759
# after
insta-boards sync --dry-run
insta-boards list boards
insta-boards list items --collection 18427410172124759
insta-boards download --collection 18427410172124759The wheel name on PyPI also shortens: insta-sync-boards → insta-boards.
Highlights
- State-aware incremental sync — every item is persisted to a JSON
state file the moment it is downloaded, so a network drop or
Ctrl-Cnever loses progress. - Cursor-based pagination — every walk is resumable via
--max-id/--output-cursor. The next run picks up exactly where
the previous one stopped. - Human-like throttling — log-normal pause distribution with
micro- and session-breaks, optional User-Agent rotation. Toggle off
with--no-humanizefor deterministic CI runs. - Parallel carousel downloads — bounded thread pool that still
routes every byte through the pacer. Per-requestIG_DOWNLOAD_*
env vars tune timeouts, retries, and backoff. - Pure stdlib +
uv— single-binary install, no global Python
pollution, no transitive build deps.
Installation
# Recommended (one-shot, isolated)
uv tool install insta-boards
insta-boards --helpRequires uv.
Substitute pipx or pip if you prefer.
For development, run from a local checkout:
git clone https://github.com/nimblemo/insta-boards.git
cd insta-boards
uv sync
uv run insta-boards sync --dry-runRequirements
- Python ≥ 3.11 (CI matrix: 3.11 / 3.12 / 3.13)
- A working Instagram account (credentials,
sessionidcookie, or
a pre-savedinstagrapisettings file — see README → Configuration) - Outbound HTTPS to
i.instagram.comand thescontent-*.cdninstagram.com
CDN
CI / CD
Shipped on day one:
.github/workflows/ci.yml— runs on every push tomainand on
every pull request. Matrix-builds the sdist + wheel on Python
3.11 / 3.12 / 3.13 and smoke-tests every subcommand..github/workflows/release.yml— runs on every published GitHub
Release (or via the Run workflow button). Builds the wheel,
smoke-tests it, and pushes to PyPI via Trusted Publishing (OIDC).
No API tokens are stored in GitHub secrets.
Repository layout
The project lives across two GitHub repositories by design:
| Repo | Visibility | Purpose |
|---|---|---|
nimblemo/insta-boards |
public | Source of truth. Tagged, released, published to PyPI. |
nimblemo/my-insta-boards |
private | Personal working copy. The private branch keeps a relaxed .gitignore so secrets/, data/, and the local sync-collection-list.txt can be committed. |
The private branch is fast-forwarded from main after every release.
License
MIT. See the LICENSE file for the full text.
MIT License — Copyright (c) nimblemo
Changelog (0.1.2)
- CLI: collapsed four entry points into one (
insta-boards <sub>). - Packaging: renamed wheel and project from
insta-sync-boardsto
insta-boards. - Docs: leading
uv tool installblock at the top of the
Installation section. - CI: GitHub Actions matrix (Python 3.11–3.13) + PyPI trusted
publishing via OIDC. - Licensing: MIT.