thesa
thesa is a Rust CLI to archive GitHub and Bitbucket repositories, ML models, datasets, websites, and free 3D assets.
Repository refresh helpers live in repoforge, model target parsing lives in
modelforge, dataset scraping is powered by baseforge, website archiving is
powered by siteforge, and license-aware 3D bundles use assetforge.
Made by Trevor Knott for Knott Dynamics. The terminal experience is built with Scrin and Aisling for the TUI, dashboards, loaders, and visual effects.
thesa is the operator-facing binary for the Knott Dynamics archive stack. It
keeps reusable parsing and repository refresh logic in focused crates, then adds
CLI/TUI orchestration, archive manifests, integrity sidecars, and terminal
workflows.
What It Archives
- GitHub repositories by owner/organization and Bitbucket Cloud repositories by workspace.
- Existing Git repository archives via safe refresh/pull workflows.
- Hugging Face, Ollama, and CivitAI model targets.
- Hugging Face Datasets and Zenodo dataset records through BaseForge.
- Websites and documentation through Siteforge.
- Poly Haven CC0 3D assets through AssetForge.
What It Produces
- Local archive directories under
./archivesby default. .thesa/manifest.jsonand.thesa/checksums.blake3integrity sidecars.- Scrin/Aisling TUI dashboards for interactive archive flows.
- Siteforge AI-readable website bundles with
AGENTS.md, indexes, compact page artifacts, and raw crawl evidence. - Dependency-complete, checksum-verified 3D bundles with AssetForge license manifests.
Install
cargo install --path .
From crates.io after publishing:
cargo install thesa
On Windows, install with the Windows Rust toolchain from Git Bash, PowerShell, or Command Prompt:
Git Bash can run the installed Windows thesa.exe, but a binary installed inside
WSL is a Linux binary and will not run from Windows Git Bash. If Git Bash reports
a missing DLL, check the DLL name: VCRUNTIME*.dll means the Microsoft Visual C++
Redistributable or Build Tools runtime is missing; libgcc_s_seh-1.dll or
libwinpthread-1.dll usually means an MSYS2/MinGW Rust toolchain is being used,
so switch to the rustup MSVC toolchain above or ensure MSYS2's mingw64/bin is on
PATH. thesa uses Rustls for its direct HTTPS client and Siteforge uses bundled
SQLite, so default installs do not require external OpenSSL or SQLite DLLs.
Then run:
thesa
Or force the interactive TUI explicitly:
thesa --tui
Short form:
thesa -T
Usage
thesa [TARGET] [options]
New command form:
thesa archive site <URL>thesa archive url <URL>thesa archive dataset <TARGET>thesa archive asset <TARGET>thesa archive refresh [OWNER]thesa archive listthesa archive inspect <ARCHIVE_ID>thesa archive search <QUERY>thesa archive export <ARCHIVE_ID> --format <FORMAT>thesa archive pack <ARCHIVE_ID>thesa archive verify <ARCHIVE_ID>thesa archive resume <ARCHIVE_ID>thesa archive diagnostics [ARCHIVE_ID]thesa verify <ARCHIVE_DIR>
Run with no arguments for interactive mode.
Use --tui or -T to force interactive mode. If TARGET is also passed, the
TUI flag takes precedence and opens the TUI prompt instead.
The TUI landing screen offers five archive routes: GitHub/Bitbucket repositories,
ML models, BaseForge datasets, Siteforge website archives, and AssetForge free
3D assets. Selecting BaseForge
prompts for a dataset target and archives into ./archives/datasets by default.
Selecting Siteforge prompts for a URL and then shows a preflight options screen
for full-site vs single-page archives, max depth, max pages, archive output
profile, and JavaScript rendering mode. TUI Siteforge runs archive into
./archives/sites by default.
Selecting AssetForge offers Poly Haven, ambientCG, or Sketchfab CC0, then prompts
for an id, search, category, top, or latest target. Results default to the top 20,
are ranked before selection, and archive into ./archives/assets.
Repository TARGET can be an owner/workspace, owner/repo, GitHub URL, or
Bitbucket URL. Bare targets use --repo-provider github|bitbucket; provider URLs
and SSH remotes are detected automatically.
Examples:
thesa torvalds/linux --repo-provider github --dry-runthesa workspace/repo --repo-provider bitbucket --dry-runthesa https://bitbucket.org/workspace/repo --dry-run
For model mode, TARGET can also be presets:
top(most downloaded)latest(most recently updated)
For model mode, set --mode models and choose one provider:
--provider hf(Hugging Face, default)--provider ollama(local Ollama instance)--provider civitai(CivitAI)
In interactive/TUI model mode, provider selection appears before the model target prompt.
For dataset mode, TARGET can be:
ownerfor a Hugging Face dataset namespace.owner/datasetordataset:<id>for one Hugging Face dataset.search:<query>for a Hugging Face dataset search.- a Hugging Face dataset URL such as
https://huggingface.co/datasets/squad. - a Zenodo record id or
https://zenodo.org/records/<id>when using--dataset-provider zenodo. toporlatestpresets.
For dataset mode, set --mode datasets and choose one provider:
--dataset-provider hf(Hugging Face Datasets, default)--dataset-provider zenodo(Zenodo records)
The command form is also available:
thesa archive dataset dataset:squad --provider hf --dry-runthesa archive dataset "climate data" --provider zenodo --dry-run
For free 3D asset mode, provider targets include:
- a provider id or canonical provider URL
search:<query>orcategory:<name>toporlatest
Bundle controls:
--asset-format auto|gltf|fbx|blend|usd|archiveand--asset-resolution auto|original|1k|2k|4k|8kin top-level mode--formatand--resolutionunderthesa archive asset--asset-limit <1-100>or--limit <1-100>controls ranked discovery (default20)--asset-max-download-bytesor--max-download-bytesto bound each selected bundle--skip-existingverifies every local size and BLAKE3 digest, plus provider MD5 when supplied
Poly Haven assets are CC0, but access to api.polyhaven.com is governed by
separate terms and is free only for reasonable non-commercial use unless Poly
Haven grants a commercial API license. Thesa displays required Poly Haven
attribution and the API terms URL next to API-derived content.
ambientCG assets are CC0 and use its official API. Sketchfab searches are limited
to downloadable CC0 models; downloads require --asset-token or
SKETCHFAB_API_TOKEN and preserve creator plus Sketchfab attribution.
Common options:
--depth <DEPTH>: clone with commit depth-c, --concurrency <N>: number of repos cloned in parallel (default4)--filter <PATTERN>: filter repository names by substring--skip-existing: skip repos that are already present--token <TOKEN>: GitHub API token (or useGITHUB_TOKENenv)--bitbucket-token <TOKEN>: Bitbucket access token (or useBITBUCKET_TOKENenv)--repo-provider <PROVIDER>: provider for bare repository targets (github,bitbucket)--hf-token <TOKEN>: Hugging Face API token (or useHF_TOKENenv)--civitai-token <TOKEN>: CivitAI API token (or useCIVITAI_TOKENenv)--hf-mirror: usehf-mirror.comfor Hugging Face API calls--provider <PROVIDER>: model provider for model mode (hf,ollama,civitai)--dataset-provider <PROVIDER>: dataset provider for dataset mode (hf,zenodo)--asset-provider polyhaven|ambientcg|sketchfab: free 3D asset provider--asset-token <TOKEN>: user Sketchfab API token (orSKETCHFAB_API_TOKEN)--asset-format <FORMAT>/--asset-resolution <RESOLUTION>: AssetForge bundle selection-T, --tui: force the interactive Scrin interface
Git archive refresh options:
thesa archive refresh: scan./archives/**for GitHub/Bitbucket worktrees and rungit pull --ff-onlythesa archive refresh <NAMESPACE>: refresh only archives whose slug owner/workspace matches<NAMESPACE>thesa archive updateandthesa archive pull: aliases forrefresh--archive-root <DIR>: root to scan recursively (default./archives)--owner <NAMESPACE>/--workspace <NAMESPACE>: provider namespace filter-c, --concurrency <N>: number of repositories refreshed at once (default4)--filter <TEXT>: refresh only matching owner/repo slugs or paths--dry-run: print discovered archives without pulling
Refresh only touches actual Git worktrees. It derives owner/repo from recognized
GitHub or Bitbucket origin URLs and falls back to the archive path layout,
such as archives/<owner>/<repo>. Dirty worktrees are skipped with an error so
local edits are not overwritten silently. The discovery, slugging, clean-check,
and git pull --ff-only execution are provided by the repoforge crate; thesa
adds archive manifests and terminal reporting around that core.
Namespace-scoped refresh is the fastest way to update one provider archive:
thesa archive refresh tknott95 --dry-runthesa archive refresh tknott95 --concurrency 8thesa archive pull --owner tknott95 --filter agent
Archive output directories are ignored by git and excluded from Cargo packages.
Website archive options:
-o, --output <DIR>: output root for website archives (default./archives/sites)--input <FILE>: seed URLs from a file, one per line (#comments allowed); may be used with or without a positional URL--full-site: follow in-scope site links instead of archiving one page--allow-cross-domain: permit cross-domain links--max-depth <N>: limit crawl depth--max-pages <N>: limit page count-c, -j, --concurrency <N>: number of concurrent fetch workers--delay-ms <N>: politeness delay between requests per worker--archive-id <ID>: stable archive directory id--include <GLOB>: include URL glob pattern, repeatable--exclude <GLOB>: exclude URL glob pattern, repeatable--archive-profile <full|agent|lean>: choose Siteforge artifact volume--max-page-size-bytes <N>: maximum bytes fetched per HTML page--max-asset-size-bytes <N>: maximum bytes fetched per asset--max-total-archive-size-bytes <N>: maximum bytes written by the archive--render-js: use Siteforge browser rendering for JavaScript pages--render-js-auto: render only thin JavaScript app shells--browser-command <COMMAND>: browser command template for JavaScript rendering--browser-profile <DIR>: browser profile directory for JavaScript rendering--render-wait-ms <N>: milliseconds to wait before extracting rendered DOM--header 'Name: Value': extra request header, repeatable--cookie <COOKIE_HEADER>: cookie header value for authenticated/public crawls--user-agent <VALUE>: Siteforge fetch/render User-Agent--timeout-secs <N>: HTTP timeout per request--retry-count <N>: retry attempts for failed frontier items--ocr: enable Siteforge OCR for code-like downloaded assets--dry-run: print the Siteforge crawl plan without fetching pages
Avoid storing secrets in docs or shell history when using --header or
--cookie; prefer a short-lived shell variable or a local wrapper script outside
the repository.
Siteforge archives write an AI-readable bundle under the archive id directory.
The default agent profile avoids duplicate YAML Markdown and plain-text copies:
AGENTS.md: first file to open for agent-readable instructions/contextagent-index.json: machine-readable index for agents/toolsreadable/basic_markdown,readable/json: default extracted page contentreadable/markdown,readable/text: additional representations in explicitfullmodechunks/chunks.jsonl: chunk stream for downstream indexingmanifest.json,checksums.json,crawl.db: Siteforge crawl metadata.thesa/manifest.json,.thesa/checksums.blake3: thesa integrity sidecars
Siteforge management commands default to ./archives/sites. Use
--archive-root <DIR> when archives live elsewhere.
Siteforge export formats include markdown, basic-markdown, jsonl, json,
html, warc, zip, tar, agent-tar, and all.
Forge Crates
thesa keeps reusable archive logic in small crates so it can stay focused on
CLI/TUI orchestration:
repoforge: discovers Git worktrees under archive roots, derives GitHubowner/reposlugs, rejects dirty worktrees, and refreshes clean clones withgit pull --ff-only.modelforge: normalizes Hugging Face, Ollama, and CivitAI target strings into provider-neutral target enums before thesa calls provider APIs.baseforge: discovers Hugging Face/Zenodo datasets, inspects downloadable files, and archives them with bounded concurrent downloads.siteforge: captures websites into AI-readable local archives and provides website archive management commands.assetforge: discovers ranked CC0 models through official Poly Haven, ambientCG, and Sketchfab APIs and writes bounded, BLAKE3-verified archives.
The thesa binary combines those crates with Scrin and Aisling to provide the interactive command deck, repo/model/dataset pickers, clone dashboards, Siteforge option screens, AssetForge discovery, and archive progress displays.
Package Safety
The Cargo package is explicitly whitelisted. Releases include only the manifest, lockfile, README, license, changelog, source, and helper scripts. Archive output, sessions, notes, logs, build directories, and local scratch files are not shipped.
Included package files:
Cargo.tomlCargo.lockREADME.mdLICENSECHANGELOG.mdsrc/**git.shscripts/**
Repo picker controls (TTY only):
Space: check or uncheck a repo- Mouse: hover a visible row to focus it, left-click to check or uncheck it
a: check all visible reposc: clear filter and checksb: open batch-size overlay (1,2,3,6,8)PageUp/PageDown: move cursor by one viewport pageHome/End: jump to first/last visible resultEnter: clone checked repos only, or visible repos when nothing is checked
Clone dashboard controls (TTY only):
t: toggle repository detail lines in the live batch displayq: request stop after current batch completesm: motion effectb: Burn effectw: Wipe effect
TTY clone runs use a Scrin dashboard. Aisling renders the top Matrix deck, effect pane, and TQDM-style loader rows for concurrent repository pulls. The TUI is built against newer Scrin interaction support and remains keyboard-first for SSH reliability.
Mode, provider, repository, and model picker screens also accept mouse hover and left-click actions when the terminal supports mouse reporting. Dataset selection uses a compact numbered prompt after BaseForge discovery.
Examples:
- Start TUI and pick target/repo interactively:
thesathesa --tuithesa -T
- Clone one repo:
thesa torvalds/linux --output ./repos
- Clone all public repos for a user/org with shallow history:
thesa octocat --output ./repos --depth 1
- Clone with explicit concurrency:
thesa octocat --concurrency 8 --output ./repos
- Refresh existing GitHub archives:
thesa archive refresh --dry-runthesa archive refresh tknott95 --dry-runthesa archive refresh --archive-root ./archives --concurrency 8thesa archive pull --filter octocatthesa archive pull --owner tknott95 --concurrency 8
- Archive a website:
thesa archive site https://example.com --full-site --max-pages 100thesa archive url https://example.com/docs --max-depth 2thesa archive site https://docs.example.com --archive-profile agent --render-js-autothesa archive --dry-run url https://example.com/docs --full-sitethesa archive url https://example.com/docs --dry-run --include '**/docs/**' --delay-ms 500thesa archive url https://example.com/docs --input seeds.txt --archive-id docsthesa archive url --input seeds.txt --full-site --archive-id docs
- Manage Siteforge archives:
thesa archive listthesa archive inspect docsthesa archive search "install" --archive-id docs --limit 5thesa archive export docs --format agent-tar --output ./exports/docs-agentthesa archive pack docs --max-tokens 80000thesa archive verify docsthesa archive resume docsthesa archive diagnostics docs
- Verify a thesa archive directory:
thesa verify ./archives/examplethesa verify ./archives/example --json
- Preview actions before cloning:
thesa org-name --dry-run
- Models and providers:
thesa --mode models --provider hf meta-llama --dry-runthesa --mode models --provider hf meta-llama/Llama-3.1-8B-Instruct --dry-runthesa --mode models --provider ollama llama3 --dry-runthesa --mode models --provider hf top --dry-runthesa --mode models --provider hf latest --dry-runthesa --mode models --provider ollama top --dry-runthesa --mode models --provider ollama latest --dry-runthesa --mode models --provider civitai top --dry-runthesa --mode models --provider civitai latest --dry-runthesa --mode models --provider civitai 827184 --dry-run
- Datasets and providers:
thesa --mode datasets --dataset-provider hf dataset:squad --dry-runthesa --mode datasets --dataset-provider hf search:"code data" --filter python --dry-runthesa --mode datasets --dataset-provider hf openai --concurrency 8 --skip-existingthesa archive dataset dataset:squad --provider hf --archive-root ./archives/datasetsthesa archive dataset "climate data" --provider zenodo --dry-run
- Free 3D assets:
thesa --mode assets --asset-provider polyhaven --asset-resolution 1k Shelf_01 --dry-runthesa --mode assets --asset-format gltf --asset-resolution 2k search:"wooden chair"thesa archive asset category:furniture --format fbx --resolution 1k --dry-runthesa archive asset Shelf_01 --format gltf --resolution 1k --skip-existing
Scripts
You can compile and run with helper scripts:
-
Run from repo root (interactive target prompt):
./run.sh
-
Pass a target directly:
./run.sh <target> [output-root] [concurrency] [extra thesa flags]
-
Compile only:
./scripts/compile.sh
-
Compile and run (default concurrency
4):./scripts/run.sh <target> [output-root] [concurrency] [extra thesa flags excluding --output]
-
Publish release to crates.io:
./scripts/publish.sh --allow-dirty./scripts/publish.sh --dry-run(safe checks only)
run.sh creates an output folder from the target name (for example owner or,
for owner/repo, just repo) and runs clones inside that folder.
Notes
--concurrencysets the concurrent clone batch size.- private repositories are intentionally skipped/blocked.
- Cargo packages exclude archive output, session files, logs, target directories, and temporary test archives. Do not put secrets in project files.