A command-line interface for RSpace covering both the electronic lab notebook and the inventory system. Built on the rspace-client Python SDK.
Status: Alpha — not yet published to PyPI. Install locally using the instructions below.
- Verb-first command structure —
rspace list documents,rspace get SA123,rspace create sample - Full ELN coverage — documents, notebooks, folders, forms, files, groups, users, activity
- Full Inventory coverage — samples, subsamples, containers, sample templates, instruments, instrument templates, workbenches
- Smart
getcommand — infers resource type from GlobalID prefix (SD,SA,SS,IC,IN, …), and refuses an ID whose prefix doesn't match an explicit type - Tagging — set tags on any resource type with a single
rspace tagcommand - Inventory snapshots —
rspace migrate export/importto move whole inventories, individual containers (with full subtree), templates, samples, instruments, or instrument templates between RSpace instances. Preserves attachments, preview images, IMAGE-container backgrounds, and the container hierarchy. - Multiple output formats — rich tables (default), JSON, CSV, quiet (IDs only, for piping)
- Pagination — paginated list commands support
--page/--page-sizewith a result footer - Named profiles — manage multiple RSpace instances with
--profile - Keychain storage — store credentials in the OS keychain, never in a plain-text file
- Python 3.9 or later
- Poetry (for local installation)
The package is not yet published to PyPI. Install it directly from the repository using Poetry or pip.
To install a tagged release without cloning (see Releases):
pip install git+https://github.com/tilorspace/rspacectl.git@v0.1.0git clone https://github.com/tilorspace/rspacectl.git
cd rspacectl
poetry installThis installs the rspace command into a Poetry-managed virtual environment. Run commands via:
poetry run rspace --helpOr activate the environment first and use rspace directly:
poetry shell
rspace --helpgit clone https://github.com/tilorspace/rspacectl.git
cd rspacectl
pip install -e .
rspace --helpWith optional keychain support:
pip install -e ".[keychain]"rspace configureSaves credentials to ~/.rspacectl with permissions 600.
Manage multiple RSpace instances (e.g. production and staging) with named profiles:
rspace configure --profile staging # saves to ~/.rspacectl.staging
rspace --profile staging list samples # uses staging credentials
rspace configure --list # show all configured profilesThe default profile (~/.rspacectl) is used when --profile is omitted — fully backward compatible.
For better security, store credentials in the OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service) instead of a plain-text file. Requires the optional keyring dependency:
pip install -e ".[keychain]" # or: poetry install -E keychain
rspace configure --keychain # store default profile in keychain
rspace configure --profile prod --keychain # named profile in keychainCredentials stored in the keychain never appear in files, environment variables, or process arguments — recommended for agentic and CI use.
For every invocation, credentials are resolved in this order (first match wins):
--url/--api-keyCLI flagsRSPACE_URL/RSPACE_API_KEYenvironment variables- OS keychain
- Profile dotenv file (
~/.rspacectlor~/.rspacectl.<profile>)
Create ~/.rspacectl:
RSPACE_URL=https://your-rspace-instance.com
RSPACE_API_KEY=your-api-key-hererspace status-o / --output is a global option, so it goes before the command name (rspace -o json get SD123):
| Format | Flag | Description |
|---|---|---|
| Table | -o table |
Rich formatted table (default) |
| JSON | -o json |
Pretty-printed JSON |
| CSV | -o csv |
RFC 4180 CSV to stdout |
| Quiet | -o quiet |
IDs only, one per line — useful for piping |
# Pipe document IDs into another command
rspace -o quiet list documents | xargs -I{} rspace get {}rspace list documents
rspace list documents --query "CRISPR" --tag "methods" --page 1 --page-size 50
rspace list documents --order-by name --sort-order asc
rspace list notebooks
rspace list folders --parent FL123
rspace list samples
rspace list samples --query "buffer" --owned-by alice --page 0 --page-size 20
rspace list subsamples --query "aliquot"
rspace list containers --query "freezer"
rspace list templates
rspace list instruments --query "confocal" --owned-by alice
rspace list instrument-templates
rspace list files --type document
rspace list forms
rspace list groups
rspace list users # sysadmin only
rspace list activity --from 2024-01-01 --to 2024-03-31 --action CREATE
rspace list workbenchesA pagination footer is shown after every paginated result:
Showing 1–20 of 143 (page 0, use --page / --page-size to navigate)
The resource type is inferred automatically from the GlobalID prefix:
rspace get SD123 # document
rspace get NB456 # notebook
rspace get FL789 # folder
rspace get SA101 # sample
rspace get SS202 # subsample
rspace get IC303 # container
rspace get BE404 # workbench
rspace get IT505 # sample template
rspace get IN808 # instrument
rspace get NT909 # instrument template
rspace get FM606 # form
rspace get GL707 # gallery fileFor plain numeric IDs, provide the type explicitly:
rspace get document 123
rspace get sample 456
rspace get instrument 808When you give both a type and a GlobalID, the prefix must match the type. A mismatch such as rspace get subsample SA905 exits with an error instead of quietly fetching SS905. Containers and workbenches (IC / BE) are interchangeable, and so are folders and notebooks (FL / NB). The same check applies to update, delete, split, and move --target.
Additional flags for richer output:
rspace get SA101 --subsamples # sample detail + subsample list
rspace get IC303 --content # container detail + contents
rspace get BE404 --content # workbench detail + contents
rspace get NB456 --content # notebook detail + document list
rspace get FL789 --content # folder detail + document listrspace create document --name "My Experiment" --form FM123
rspace create notebook --name "Project Alpha"
rspace create folder --name "Data" --parent FL456
rspace create sample --name "Buffer A"
rspace create sample --name "Buffer A" --template IT101 # use a template
# populate template fields (use `rspace get template IT101` to see field names)
rspace create sample --name "Enzyme X" --template IT101 \
--field "pH=7.4" --field "Source=Commercial"
rspace create sample --name "Buffer B" --quantity 50 --unit 3 --expiry 2027-12-31
rspace create sample --from-csv samples.csv # bulk create from CSV
rspace create container --name "Freezer 1" --type list
rspace create container --name "Box A" --type grid --rows 9 --cols 9
# instruments (default instrument template if --template is omitted;
# stored on your workbench unless --target is given)
rspace create instrument --name "Confocal 1" --template NT12 \
--field "Manufacturer=Zeiss" --tag "microscopy" --target IC34 --row 1 --col 2
rspace create instrument-template --from-file confocal_template.json
rspace create template --from-file buffer_template.json # sample template
rspace create user --username jdoe --email j.doe@example.com \
--first-name Jane --last-name Doe # sysadmin only; prompts for password--expiry takes a date (YYYY-MM-DD). --unit is a numeric RSpace unit ID.
rspace update document SD123 --name "Revised Experiment"
rspace update document SD123 --tag "lab,2024,validated"
rspace update document SD123 --append "<p>Additional notes</p>"
# Target a specific form field
rspace update document SD123 --content "<p>New text</p>" --field-id 456
rspace update document SD123 --append "<p>Addendum</p>" --field-index 2
rspace update sample SA456 --name "Buffer A v2" --description "pH 7.4"
rspace update sample SA456 --tag "reagent,validated"
# Instruments: name, description, tags, template field values
rspace update instrument IN12 --field "Serial Number=SN-42" --tag "lab,confocal"
rspace update instrument IN12 --latest-template # move to the template's latest version
# Move all your instruments made from a template to its latest version
rspace update instrument-template NT3 --propagate--field-id targets a field by its numeric ID (use rspace -o json get SD123 to find IDs).
--field-index targets a field by 0-based position (for --append / --prepend).
rspace tag SD123 "lab,experiment,2024"
rspace tag NB456 "methods,protocols"
rspace tag SA789 "reagent,validated"
rspace tag SS101 "aliquot,stock"
rspace tag IC202 "freezer,-80C"
rspace tag IT303 "template,approved"
rspace tag IN404 "microscopy,shared"Accepts any GlobalID — the resource type is inferred from the prefix. Replaces all existing tags.
rspace delete document SD123 SD456 SD789 # batch delete
rspace delete sample SA101
rspace delete container IC303
rspace delete instrument IN404
rspace delete instrument-template NT5
rspace delete form FM606 # only forms in NEW state
rspace delete folder FL789 NB456 # folders or notebooksEvery ID in a batch is checked against the type first: if any one doesn't match (e.g. rspace delete sample SA1 IC2), nothing is deleted. A sample can't be deleted while any of its subsamples is stored in a container; move them to your workbench first. If the server refuses a delete, the command reports it and exits with status 1.
rspace search "CRISPR protocol"
rspace search "buffer" --type samples
rspace search "PCR" --type documents
rspace search "zeiss" --type instruments# List container
rspace move SS101 SS102 --target IC303
# Grid container — auto-fill by row or column
rspace move SS101 SS102 --target IC404 --strategy row
rspace move SS101 SS102 --target IC404 --strategy column
# Grid container — exact placement
rspace move SS101 --target IC404 --row 2 --col 3
# Instruments (fill free grid cells; move them separately from other items)
rspace move IN12 IN13 --target IC404 --strategy row# Upload a file to the gallery
rspace upload file ./data.csv
# Attach a file to an inventory item
rspace upload attachment ./spec.pdf SS101
# Download a gallery file
rspace download file GL606 --output-dir ./downloads
# Download an inventory attachment
rspace download attachment IF707 --output-dir ./downloadsrspace split SS202 --count 4 # 4 new subsamples; 5 equal parts in total
rspace split SS202 --count 3 --quantity 10.0 # 3 new subsamples of 10 each; SS202 keeps the rest--quantity is in the subsample's current unit (see rspace get SS202).
rspace share SD123 SD124 --group 5 --permission editrspace export --format xml --scope user
rspace export --format html --scope selection --id SD123 --id SD456
rspace export --format xml --scope user --no-wait # start job, don't waitrspace import word report.docx notes.docx --folder FL123
rspace import tree ./my-lab-data --folder FL123Take a snapshot of inventory on one server and recreate it on another. Useful for:
- Selective transfers — copy a freezer rack and its samples to a collaborator's instance, share a curated set of templates with a sister lab, or seed a test server with realistic data
- Full migrations — move everything when consolidating instances or upgrading
- Snapshots — keep a local file-system copy of an inventory subtree
Sample templates, instrument templates, containers (full hierarchy), samples, subsamples, instruments (with their container placements), attachments, preview images, template icons, and IMAGE-container backgrounds with marker locations are all preserved.
# Selective: a single container and everything inside it
rspace --profile source migrate export --container IC123 --output ./freezer_a
rspace --profile target migrate import ./freezer_a
# Selective: pick specific templates and samples (referenced templates auto-included)
rspace --profile source migrate export --template IT5 --sample SA42 --output ./partial
# Selective: instruments (their instrument templates are auto-included)
rspace --profile source migrate export --instrument IN12 --instrument-template NT3 --output ./lab_kit
# Multiple selectors compose
rspace --profile source migrate export \
--container IC100 --container IC200 --template IT5 \
--output ./teams_handoff
# Full inventory
rspace --profile source migrate export --all --output ./full_snapshot
rspace --profile target migrate import ./full_snapshot
# Preview an import without making any changes
rspace --profile target migrate import ./freezer_a --dry-runWhen you select a container, the entire subtree (sub-containers, subsamples, and the parent samples those subsamples belong to) is included automatically. When you select samples or instruments, the templates they depend on are pulled in too.
my_snapshot/
snapshot.json inventory data (templates, instrument templates, containers,
samples, instruments)
attachments/SA123/... per-item file attachments (also IN… for instruments)
images/SA123_preview.png preview images for samples / subsamples / containers /
templates / instruments
icons/IT12_icon template icons (NT… for instrument templates)
image_containers/ IMAGE-container backgrounds + marker positions
checkpoint.json created during import; auto-deleted on success
The importer runs in ordered phases, writing a checkpoint after each so an interrupted run can resume cleanly:
- Sample templates: created, with old→new IDs recorded
- Instrument templates: an identical template already on the target (same name, description and fields) is reused; otherwise one is created. Use
--no-reuse-templatesto always create - Containers (flat): all containers created at the top level. IMAGE containers get their background image and markers
- Container hierarchy: containers moved into their parents
- Samples: created from the mapped template; field values, tags, subsample names, quantities and notes restored
- Instruments: created from the mapped instrument template with field values, tags, extra fields and barcodes (identifiers such as PIDINST DOIs are not migrated)
- Subsample placements: subsamples moved to their original containers (grid coords for GRID, marker index for IMAGE)
- Instrument placements: instruments moved to their original container, grid cell or marker
- Attachments: files re-uploaded to their new owners
- Preview images: set for templates, samples, subsamples, containers and instruments (default thumbnails are deduplicated)
- Template icons: sample and instrument template icons (skipped for reused instrument templates)
# Resume an interrupted import
rspace migrate import ./freezer_a --checkpoint ./freezer_a/checkpoint.json
# Skip phases (e.g. data-only, no files)
rspace migrate import ./freezer_a --skip-files
rspace migrate import ./freezer_a --skip-templates --skip-containers
rspace migrate import ./freezer_a --skip-instruments
# Data-only export (no attachments / images / icons)
rspace migrate export --container IC123 --output ./data_only --no-files--outputsemantics differ from other commands: inmigrate export,--outputis the snapshot directory (not an output format). The-o/--outputtable/json/csv/quiet flag does not apply.- Workbench items (
BEprefix) cannot be migrated — workbenches are per-user. Subsamples and instruments that sat on a source workbench are reported; they are not placed in any container and stay on the importing user's workbench. - Selecting a container pulls its full subtree. Sub-containers, subsamples, and the parent samples those subsamples belong to are auto-included so the imported subtree is internally consistent.
- Backward compat: legacy plain-JSON snapshots produced before the directory format are still importable via
rspace migrate import old_snapshot.json(no attachments will be restored). - Default thumbnails are skipped: RSpace's content-addressed image storage reuses the same hash for every item without a custom preview, so the migrator deduplicates these to avoid re-uploading hundreds of identical placeholders.
| Prefix | Resource type |
|---|---|
SD |
Document |
NB |
Notebook |
FL |
Folder |
SA |
Sample |
SS |
Subsample |
IC |
Container |
IT |
Sample template |
IN |
Instrument |
NT |
Instrument template |
IF |
Inventory file (attachment) |
FM |
Form |
GL |
Gallery file |
BE |
Workbench |
# Install with dev dependencies
poetry install
# With optional keychain support
poetry install -E keychain
# Run tests
poetry run pytest
# Live end-to-end checks against a local RSpace (localhost only; each creates
# and deletes rspacectl-review-e2e-* items)
poetry run python scripts/e2e_review_fixes.py [--profile NAME]
poetry run python scripts/e2e_instruments.py [--profile NAME]
poetry run python scripts/e2e_migrate_instruments.py [--profile NAME]
# Format and lint
poetry run black rspacectl tests
poetry run ruff check rspacectl tests