A small smart CLI toolkit for academic work on macOS in a single command: sci
Highlights:
- Wraps
brewanduvtool installs to reliably auto-sync with aBrewfile - TUIs for browsing: files, databases, hugging-face buckets, remote lab servers (ssh)
- Control Zotero from the command-line (write cloud, read local) with OpenAlex integration, pdf-to-markdown extraction, and LLM tools
- Control Canvas LMS from the command-line (experimental): manage assignments, modules, grades, files, etc
curl -fsSL https://raw.githubusercontent.com/sciminds/sci/main/install.sh | shWritten in Go because:
- Go is typed and compiled which makes it much faster than Python/JS and makes TDD with LLMs more reliable
- Easy to create single-file programs that work on any computer
- No complicated dev tooling: everything is pretty standardized in the ecosystem and distribution is just GitHub
- Eshin wanted to learn a new language and it's particularly nice for agentic engineering
| Command | What it does |
|---|---|
sci py |
Create ephemeral Python sessions and Marimo notebooks |
sci proj |
Scaffold MyST/Quarto-flavored Python and writing projects |
sci view |
Interactive viewer for markdown, csv, sqlite, and duckdb files |
sci db |
Work with sqlite, duckdb, csv, json, and parquet files |
sci vid |
Common video/audio editing operations (trim, resize, mute, …) |
sci tools |
Manage brew and uv packages and keep Brewfile up-to-date |
| Command | What it does |
|---|---|
sci doctor |
Check that your Mac is set up correctly |
sci update |
Update sci to the latest version |
sci help |
Interactive TUI with demos for any command |
sci learn |
Interactive TUI to learn common terminal commands |
| Command | What it does |
|---|---|
sci cloud |
Up/download files to the SciMinds Hugging Face buckets (requires hf auth) |
sci lab |
Up/download files to university HPC storage over SFTP (requires VPN) |
| Command | What it does |
|---|---|
sci cass |
Canvas LMS & GitHub Classroom management |
sci zot |
Interact with Zotero and let an Agent drive |
Setup your Mac for scientific work — installs Homebrew if missing, walks you through hf auth login / gh auth login, and reports anything that needs attention.
Details
Self-update the sci binary in place. Downloads the latest release asset for your OS/arch, verifies its SHA256 against the release notes, and replaces the running binary atomically.
Details
Interactive TUI for common terminal/git/Python commands — pick a topic, watch a rendered asciicast, repeat. Browses the casts under internal/learn/casts/.
Details
Browse data files & markdown interactively.
usage — click to expand
| Command | What it does |
|---|---|
sci view <file> |
Browse a tabular file (CSV, JSON, SQLite, DuckDB, Parquet) or render a markdown document |
sci db view <file> |
Same viewer, mounted under the sci db namespace for discoverability |
Tabular files open in dbtui (internal/tui/dbtui/). Markdown files (.md, .markdown) render via the uikit markdown viewer — press r to reload from disk after external edits.
Scaffold and manage Python data-analysis and writing projects.
sub-commands — click to expand
| Command | What it does |
|---|---|
sci proj new |
Create a new Python or writing project (--kind python|writing) |
sci proj add |
Add packages to the project |
sci proj remove |
Remove packages from the project |
sci proj config |
Refresh config files in your project |
sci proj preview |
Start a live preview server for documents |
sci proj render |
Build documents into HTML or PDF |
sci proj run |
Run a project task |
sci proj new supports --pkg-manager pixi|uv, --doc-system quarto|myst|none, and --template lab|default|<myst-template> for picking a Typst flavor up front.
Ephemeral Python REPLs/notebooks and document-format conversion.
sub-commands — click to expand
| Command | What it does |
|---|---|
sci py repl |
Open a Python scratchpad |
sci py notebook |
Open a marimo notebook |
sci py convert |
Convert between marimo (.py), MyST (.md), and Quarto (.qmd) |
Work with SQLite/DuckDB databases and tabular files (CSV, JSON, Parquet). Verbs dispatch on the file extension — pass a .duckdb and it routes through the bundled duckdb CLI; pass a .csv/.parquet and it goes through DuckDB's read_csv_auto / read_parquet.
sub-commands — click to expand
Database management
| Command | What it does |
|---|---|
sci db create |
Create an empty database (SQLite or DuckDB, picked by extension) |
sci db reset |
Delete and recreate an empty database |
sci db info |
Show database metadata and tables |
sci db rename |
Rename a table or view |
sci db delete |
Delete a table or view |
sci db view <file> |
Interactively browse a database or tabular file (same as sci view) |
Table / file inspection
| Command | What it does |
|---|---|
sci db head |
Show the first N rows of a tabular file |
sci db tail |
Show the last N rows of a tabular file |
sci db cols |
List column names and types |
sci db shape |
Report (rows, cols) |
sci db glimpse |
Transposed preview — one row per column with sample values |
sci db summarize |
Per-column statistics (min/max/avg/std/quartiles/null %) |
sci db query |
Run a read-only SELECT against a file (refer to it as src) |
Import / convert
| Command | What it does |
|---|---|
sci db add |
Import a CSV as a new table (errors if the table already exists) |
sci db append |
Append CSV rows to an existing table |
sci db convert |
Convert between csv/tsv/json/jsonl/parquet/sqlite/duckdb |
Upload/download files to the SciMinds Hugging Face buckets. Every verb defaults to the private bucket (sciminds/private); pass --public to operate against the world-readable bucket (sciminds/public). Files are keyed as <username>/<filename> so per-user listings stay scoped.
sub-commands — click to expand
| Command | What it does |
|---|---|
sci cloud setup |
Authenticate with Hugging Face (requires sciminds org membership) |
sci cloud ls |
List shared files (default: private; --public to list public) |
sci cloud get <name> [local] |
Download a shared file (no arg → interactive browser) |
sci cloud put <file> |
Upload a file (default: private; --public shares + returns an HTTPS URL) |
sci cloud remove <name> |
Remove a shared file |
Access university lab storage over SFTP (VPN required).
sub-commands — click to expand
| Command | What it does |
|---|---|
sci lab setup |
Configure SSH access to lab storage |
sci lab ls |
List remote directory contents |
sci lab get <remote> [local] |
Download a file or directory (no arg → interactive browser) |
sci lab put <local> [remote] |
Upload a file or directory (no arg → interactive picker) |
sci lab connect |
Open an SSH shell in lab storage |
Manage Homebrew & uv tools via your Brewfile.
sub-commands — click to expand
| Command | What it does |
|---|---|
sci tools list |
List packages in the Brewfile |
sci tools install |
Install packages from the Brewfile, or add and install a new package |
sci tools uninstall |
Remove a package from the Brewfile and uninstall it |
sci tools update |
Update the Homebrew registry and upgrade outdated packages |
sci tools outdated |
List outdated packages without upgrading |
sci tools reccs |
Pick optional tools to install |
Common video/audio editing operations. Wraps ffmpeg with sensible defaults.
sub-commands — click to expand
| Command | What it does |
|---|---|
sci vid info |
Show video info (resolution, duration, codec, fps, size) |
sci vid cut |
Trim a segment (e.g. 0:30 1:00) |
sci vid compress |
Shrink a video file (reduce file size) |
sci vid convert |
Convert to another format (mp4, webm, etc.) |
sci vid gif |
Convert to optimized GIF |
sci vid resize |
Scale video (720p, 1080p, 4k, 50%, W:H) |
sci vid speed |
Change playback speed (e.g. 2 = 2x faster) |
sci vid mute |
Remove audio from a video |
sci vid extract-audio |
Extract audio track to file |
sci vid strip-subs |
Remove subtitles from a video |
Canvas LMS & GitHub Classroom management.
sub-commands — click to expand
| Command | What it does |
|---|---|
sci cass setup |
Save your Canvas API token (one-time) |
sci cass init |
Create a cass.yaml config for a course directory |
sci cass pull |
Fetch students, assignments, and submissions from Canvas/GitHub |
sci cass status |
Show sync status, pending changes, and discrepancies |
sci cass diff |
Show pending grade changes (local or --remote 3-way) |
sci cass push |
Push grade changes to Canvas |
sci cass match |
Interactively match GitHub usernames to Canvas students |
sci cass revert |
Discard unpushed grade edits |
sci cass log |
Show operation history |
sci cass canvas modules |
List, create, publish, or delete course modules |
sci cass canvas assignments |
List, create, publish, or delete assignments |
sci cass canvas announce |
List, post, or delete announcements |
sci cass canvas files |
List course files |
Syncs course data to a local SQLite database (cass.db) with a git-like workflow: pull shows changelogs, diff shows pending grade changes, push sends grades to Canvas with conflict detection. GitHub Classroom is optional — works with Canvas-only courses.
Zotero library management — local reads from zotero.sqlite (immutable, no contention with the running desktop app); writes go through the Zotero Web API. sci zot guide prints an agent-friendly cheat sheet of common workflows.
sub-commands — click to expand
Library scope. Every zot command (except setup, info, import, guide, and view) requires --library personal or --library shared. Personal is your own Zotero user library; shared is a Zotero group library auto-detected at setup time. sci zot info without the flag summarizes both libraries side-by-side. Examples below include --library personal for the common case.
Setup & overview
| Command | What it does |
|---|---|
sci zot setup |
Save your Zotero API key + user ID + shared group (auto-detected) |
sci zot info |
Summarize both libraries (personal + shared) |
sci zot guide |
Agent-friendly cheat sheet of common workflows |
sci zot --library personal view |
Browse your library in an interactive table (read-only) |
Search & export
| Command | What it does |
|---|---|
sci zot --library personal search <query> |
Search the local library (@field: clauses for author/title/doi/pub/tag/type/year; --remote hits the Zotero Web API for fulltext + notes) |
sci zot --library personal search <q> --export -o hits.bib |
Route search results through the export pipeline |
sci zot --library personal export -o refs.bib |
Full-library BibTeX / CSL-JSON export (filters: --collection, --tag, --type) |
sci zot --library personal find works <query> |
Look up papers on OpenAlex (no library round-trip) |
sci zot --library personal find authors <query> |
Look up authors on OpenAlex |
sci zot --library personal graph refs <key> |
Show works this item cites — in-library vs outside |
sci zot --library personal graph cites <key> |
Show works that cite this item — in-library vs outside |
Items
| Command | What it does |
|---|---|
sci zot --library personal item read <key> |
Show full metadata for an item |
sci zot --library personal item list |
List items with optional filters |
sci zot --library personal item children <key> |
List child attachments + notes of an item |
sci zot --library personal item export <key> |
Export a single item to CSL-JSON or BibTeX |
sci zot --library personal item open <key> |
Open the item's PDF attachment |
sci zot --library personal item attach <key> <path> |
Upload a local file as a new child attachment |
sci zot --library shared item add / update / delete |
Create / patch / trash items via the Zotero Web API |
sci zot --library personal item note add|read|list|update |
Create and manage Zotero note items |
sci zot import <path> |
Drag-drop equivalent via Zotero desktop: upload + auto-recognize metadata (CrossRef/arXiv) |
PDF extraction (docling)
| Command | What it does |
|---|---|
sci zot --library personal extract <key> |
Convert the item's PDF into a Zotero child note (default is dry-run; --apply to post) |
sci zot --library personal extract <key> --out DIR --apply |
Full extraction: md + json + referenced PNGs + CSV tables to DIR |
sci zot --library personal extract-lib |
Bulk-extract every PDF in the library (default is cache-only; --apply to post notes; parallelizable with -j) |
sci zot --library personal notes list|read|add|update|delete |
Manage docling extraction notes |
sci zot --library personal llm catalog|query|read |
LLM-agent tools for querying docling notes |
Organize
| Command | What it does |
|---|---|
sci zot --library personal collection |
Manage collections (list, create, delete, add/remove items) |
sci zot --library personal tags |
Manage tags (list, add/remove per item, delete library-wide) |
sci zot --library personal saved-search |
Manage Zotero saved searches (list, show, create, update, delete) |
Hygiene
| Command | What it does |
|---|---|
sci zot --library personal doctor |
Run all hygiene checks (invalid → missing → orphans → duplicates → citekeys) |
sci zot --library personal doctor {invalid,missing,orphans,duplicates,citekeys,dois} |
Drill into individual hygiene reports |
sci zot --library personal doctor pdfs |
Find missing-PDF candidates via OpenAlex; --collection (local), --saved-search NAME|KEY (live API), or --keys-from FILE|- |
sci zot --library personal doctor dois --fix --apply |
Patch publisher-subobject DOIs (Frontiers /abstract, PLOS .tNNN, PNAS supplements) so OpenAlex resolves them |
sci zot doctor --deep enables fuzzy duplicate detection and noisier orphan kinds. --library shared routes the same surface to a Zotero group library (e.g. a shared lab collection) — setup picks the group automatically when the account belongs to exactly one, or accepts --shared-group-id when multiple groups exist.
PDF → child note extraction. sci zot extract <KEY> pipes the item's PDF attachment through docling and posts the markdown as a child note on the parent — tagged docling and stamped with a sentinel comment so re-runs dedupe by sha256. Default is dry-run; pass --apply to actually create the note (--html posts rendered HTML instead of raw markdown). --out DIR switches to full extraction (md + json + referenced PNGs + CSV tables per docling's always-on TableFormer) persisted for Obsidian-style vault exports; --no-note skips the Zotero post entirely. Identical re-runs skip; PDF updates PATCH-in-place so the note key stays stable. sci zot notes delete is the surgical undo — matches notes by their embedded sentinel (not tag). Requires docling on PATH (sci doctor installs it via uv).
For the bulk pipeline, sci zot extract-lib runs docling on every PDF in the library and caches results locally without posting by default — pass --apply to create the child notes. Cached output is reused on re-runs, so a failed run resumes where it left off; --reextract discards the cache.
Library export details. sci zot export honors user-pinned cite-keys (Zotero 7's native citationKey field, or legacy Better BibTeX Citation Key: lines in extra) and synthesizes semantic keys for everything else as lastname{year}{firstword}-ZOTKEY. The trailing 8-char Zotero key suffix guarantees uniqueness without collision arithmetic and keeps entries round-trippable back to the source item. Pinned entries also carry a zotero://select/library/items/<KEY> URI in the note field (appended to any existing user prose, never overwriting). A .zotero-citekeymap.json sidecar is written next to the output file; on the next run, any synthesized prefix that drifted (e.g. after a metadata typo fix) gets a biblatex ids = {oldkey} alias so manuscripts citing the old form still resolve.
Every push to main and every PR runs the Build & Release workflow:
- Check — fmt, vet, lint, test
- Build — cross-compiles
scifor darwin/linux × arm64/amd64 - Publish — uploads all binaries to a rolling
latestGitHub release (only when opted in via commit message, see Development below)
Binaries are named sci-{os}-{arch} (e.g. sci-darwin-arm64, sci-linux-amd64).
Updating: Users run sci update, which compares the compiled-in commit SHA against the latest release and atomically replaces the binary if a newer build is available.
Prerequisites: Go 1.26+ and just (brew install just).
You'll also need asciicinema to create new terminal "casts". Place sci command demos in internal/help/casts/ and general terminal/git/python tutorials in internal/learn/casts/.
This is also set up as a git pre-commit hook:
# Run the full check suite (fmt, vet, lint, test, build)
just okLaunch auto-documentation site:
just docsTo try commands during development:
just run doctor # same as: go run ./cmd/sci doctor
just run proj new # etc.Two opt-in actions are driven by strings in the commit message on main:
| Trigger | Effect |
|---|---|
[release] |
After the gate passes, publishes the build to the latest GitHub release. Without it, push/PR runs only fmt/vet/lint/test + cross-compile. |
[scenarios] |
Runs the Environment Scenarios matrix (no-brew / brew-no-file / brew-file / no-brew-accept) for this commit. Otherwise scenarios only runs weekly (Mondays 09:00 UTC) or via manual dispatch. |
Markers are matched as substrings (same convention as [skip ci]); the brackets keep them visually distinct from prose so describing them in the commit body doesn't fire them accidentally.
Combine both in one commit if a release touches brew/doctor/tools code and you want scenario coverage before it ships.
sci cloud shells out to the hf CLI for all bucket operations against the SciMinds Hugging Face org. Auth is delegated entirely to hf auth login — sci stores no tokens.
Components:
hfCLI — installed viauv tool install hf(wired through doctor's Brewfile). Auth state lives in~/.cache/huggingface/.git-xet— required for HF's Xet-protocol transfers. Installed viabrew install git-xetand registered globally withgit xet install. Both are gated bysci doctor.- Org buckets:
sciminds/public— world-readable; uploads return an HTTPS URL of the formhttps://huggingface.co/buckets/sciminds/<bucket>/resolve/<username>/<filename>.sciminds/private— org-members-only; default forsci cloud put.
Files are keyed as <username>/<filename> within each bucket so per-user listings stay scoped.
Onboarding a new sciminds member:
hf auth login # paste an HF token with read+write on sciminds
git xet install # one-time global LFS transfer agent setup
sci doctor # verify everything's greenA legacy Cloudflare R2 + worker auth flow was deprecated when this CLI moved to Hugging Face buckets. The old code (
internal/cloud/auth.go,device.go, andworker/) is preserved on thecloudflare-cloudgit branch; the deployed worker atsci-auth.sciminds.workers.devcan be decommissioned separately viabunx wrangler deletefrom a checkout of that branch.






















