CLI and Python client for the CUB REST API (cub.rip)
Project description
cubctl
CLI and Python library for the CUB REST API (cub.rip).
Quick start
pip install cubctl
cubctl --help
Development install from this repo:
pip install -e ".[dev]"
cubctl --help
# or: python -m cubctl --help
The package lives under src/cubctl/. From the repo root, cubctl is available after pip install -e . (or PYTHONPATH=src python -m cubctl).
Concepts (AWS-style)
| Term | CLI flag | Config | Description |
|---|---|---|---|
| Account slot | --account src|target |
account_src / account_target |
Saved API token + default profile ID (like AWS named profiles, fixed as src and target for migrations) |
| CUB profile | --profile ID |
per-slot profile field |
User profile within an account (Pavel, DEVOPS, …). Many commands need an explicit profile ID |
Credential chain (highest priority first):
--account src|target(+ optional--profileoverride)--token(+ optional--profile)CUB_TOKEN/CUB_PROFILEenvironment variables- Default slot:
CUB_ACCOUNTenv oraccount_src
Global flags (before or after the subcommand):
cubctl --account src --profile 311483 bookmarks all --type book
cubctl bookmarks all --account src --profile 311483 --type book
Install
pip install cubctl
pip install "cubctl[test]" # optional: pytest for running tests
From source:
pip install -e ".[dev]"
cubctl --help
Authentication (device/add)
CUB uses device-based login — the same flow as Lampa:
- Open cub.rip/add while logged in to your CUB account
- Copy the 6-digit code shown on the page
- Exchange it for a token via
POST device/add
cubctl device add 123456 --save # saves to src account slot in config
cubctl auth 123456 --save # alias; prefer accounts setup for src + target
For src + target account slots:
cubctl accounts setup # reads accounts.env in repo root
cubctl accounts show
Credentials live in ~/.cub/config.json — account tokens, default slot, and saved profile names. Manage with cubctl config:
cubctl config show # accounts + profiles (no tokens)
cubctl config path
cubctl config set default-account src
cubctl config profile sync --account src # fetch profile names from API → config
cubctl config profile list --account src
cubctl config profile set --account src --name Pavel --id 311483
cubctl config profile default --account src --name Pavel
cubctl bookmarks all --account src --profile Pavel # name resolved from config
Example ~/.cub/config.json:
{
"default_account": "src",
"account_src": {
"token": "...",
"profile": "311483",
"email": "user@example.com",
"profiles": {
"Pavel": "311483",
"Kids": "311484"
}
},
"account_target": {
"token": "...",
"profile": "796529",
"profiles": { "Main": "796529" }
}
}
The client sends these headers on every authenticated request:
| Header | Purpose |
|---|---|
token |
API access token (required) |
profile |
Profile ID (required for some) |
Environment variables
| Variable | Description | Default |
|---|---|---|
CUB_TOKEN |
API token | — |
CUB_PROFILE |
CUB profile ID | — |
CUB_ACCOUNT |
Default account slot: src or target |
src when configured |
CUB_CODE_SRC |
Device code for src slot (setup) | — |
CUB_CODE_TARGET |
Device code for target slot (setup) | — |
CUB_FROM_TOKEN |
Source token for migration | — |
CUB_TO_TOKEN |
Target token for migration | — |
CUB_BASE_URL |
API base URL | https://cub.rip/api/ |
CUB_CONFIG_DIR |
Config directory | ~/.cub |
accounts.env is auto-loaded at startup when present (see accounts.env.example).
Public vs authenticated commands
These work without a token:
cubctl collections top-collectors
cubctl collections list --category new
cubctl collections roll
cubctl collections view 123
cubctl reactions get movie_539972
cubctl reactions add movie_539972 think
cubctl users find --email user@example.com
All other subcommands require --account src|target, --token, or accounts setup.
Credential resolution
Every authenticated subcommand accepts:
| Flag | Env | Config |
|---|---|---|
--account src|target |
CUB_ACCOUNT |
account_src / account_target |
--token |
CUB_TOKEN |
— (explicit override only) |
--profile |
CUB_PROFILE |
slot profile or profiles map |
Order: --account → explicit --token → account_src → error with setup hint.
Profiles
List and resolve CUB profile IDs by name:
cubctl profiles all --account src
cubctl profiles pick --account src --name Pavel
cubctl profiles pick --account target --name DEVOPS
Use the returned id with --profile or --from-profile / --to-profile.
Bookmarks
The API has documented filter types (book, history, like, wath) and internal types returned with --full 1 (viewed, scheduled, look, thrown, …).
# Category counts (matches Lampa UI totals)
cubctl bookmarks counts --account src --profile 311483
# List by type
cubctl bookmarks all --account src --profile 311483 --type history
# All internal types (~400 items)
cubctl bookmarks all --account src --profile 311483 --full 1
Premium
Timeline endpoints require CUB Premium: timeline/all, changelog, dump, update.
Backup (JSON v2)
Full profile snapshot including all bookmark internal types, timeline, and optional notifications.
cubctl backup create --account src --profile 311483
cubctl backup restore --account target --profile 796529 -i backup.json --dry-run
cubctl backup restore --account target --profile 796529 -i backup.json
Equivalent: migrate export / migrate import (same JSON format).
Account slots (src / target)
cp accounts.env.example accounts.env
# edit CUB_CODE_SRC, CUB_CODE_TARGET, optional CUB_ACCOUNT=src
cubctl accounts setup
cubctl bookmarks all --account src --type book
cubctl migrate run \
--from src --from-profile 311483 \
--to target --to-profile 796529 \
--dry-run
Migration
Copy all bookmark types + timeline (+ optional notifications) between profiles or account slots.
Always specify profile IDs — saved slots store the main profile from login, not named profiles like Pavel.
# Preview
cubctl migrate run \
--from src --from-profile 311483 \
--to target --to-profile 796529 \
--dry-run
# Run with progress
cubctl migrate run \
--from src --from-profile 311483 \
--to target --to-profile 796529 \
--include bookmarks,timeline,notifications \
--progress
# Export / import (offline)
cubctl migrate export --from src --from-profile 311483 -o pavel.json
cubctl migrate import --to target --to-profile 796529 -i pavel.json --progress
| Flag | Description |
|---|---|
--from / --to |
Account slot: src or target |
--from-profile / --to-profile |
CUB profile ID within each slot |
--include bookmarks,timeline,notifications |
What to migrate |
--merge skip |
Skip existing items (default) |
--merge overwrite |
Overwrite timeline entries |
--dry-run |
Counts only, no writes |
--progress |
Print each import step to stderr |
--quiet |
Compact JSON (export: summary only) |
--delay SECS |
Pause between API writes (rate limiting) |
Same account slot, two CUB profiles (one token):
cubctl migrate run --from-profile 311484 --to-profile 311483 --dry-run
Security notes
- Tokens are stored in plain text in
~/.cub/config.json(local CLI tool). users give --passwordpasses the password on the command line (visible in shell history). Prefer env vars in scripts.
Tests
pip install -e ".[test]"
pytest tests/test_unit.py tests/test_migration.py tests/test_cli.py -m "not integration"
pytest tests -m integration # live API; needs CUB_TEST_DEVICE_CODE
Project layout
lampa-cub-cli/
├── README.md
├── pyproject.toml
├── requirements.txt
├── accounts.env.example
├── tests/
└── src/cubctl/
├── cli.py # command dispatch
├── cli_helpers.py # auth resolution, progress, public commands
├── client.py
├── migration.py
└── api_spec.json
pip install -e ".[dev]" && cubctl --help
Publish to PyPI
Recommended: Trusted Publisher (no long-lived token)
PyPI exchanges a short-lived token with GitHub via OIDC. You do not need PYPI_API_TOKEN in GitHub Secrets when this is configured.
1. PyPI — Account → Publishing (or project → Publishing after the first release)
Add a GitHub trusted publisher:
| Field | Value |
|---|---|
| Owner | pavelpikta |
| Repository | lampa-cub-cli |
| Workflow name | publish.yml |
| Environment | pypi (optional but matches this repo’s workflow) |
For the first upload, you can add a pending publisher before the cubctl project exists on PyPI.
2. GitHub — repo Settings → Environments
Create environment pypi (optional protections: required reviewers, branch rules).
No repository secret is required for trusted publishing.
3. Release
git tag v1.0.0
git push origin v1.0.0
# GitHub → Releases → Draft new release from tag v1.0.0 → Publish
Or run Actions → publish → Run workflow manually.
The workflow uses pypa/gh-action-pypi-publish with id-token: write (see .github/workflows/publish.yml).
Alternative: API token + secret
If you prefer a classic token instead of trusted publishing:
- PyPI → Account settings → API tokens → create token (scope: entire account or project
cubctl) - GitHub → Settings → Secrets and variables → Actions →
PYPI_API_TOKEN - Replace the publish step in
publish.ymlwith:
- name: Publish to PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
run: twine upload dist/*
Remove id-token: write if you use only the token method.
Manual upload (local)
pip install build twine
python -m build
twine check dist/*
twine upload dist/*
# Username: __token__ Password: pypi-Ag... (API token)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cubctl-1.0.0.tar.gz.
File metadata
- Download URL: cubctl-1.0.0.tar.gz
- Upload date:
- Size: 42.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7aef3cdcce1c62077dc029d53d74500f88f1f97c3d5e08173622a6727ae8f7bc
|
|
| MD5 |
28ccbe9f863d0d304e142e12126f2b09
|
|
| BLAKE2b-256 |
11b2eb0ae98a8230b307e5a69cfb4ecb7cf7576fcecde19f5a5ec9ceb5edad9a
|
Provenance
The following attestation bundles were made for cubctl-1.0.0.tar.gz:
Publisher:
publish.yml on pavelpikta/cubctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cubctl-1.0.0.tar.gz -
Subject digest:
7aef3cdcce1c62077dc029d53d74500f88f1f97c3d5e08173622a6727ae8f7bc - Sigstore transparency entry: 1736236987
- Sigstore integration time:
-
Permalink:
pavelpikta/cubctl@f0667f46d003401c8f9d3f6cf4a94edc367aae7a -
Branch / Tag:
refs/tags/1.0.0 - Owner: https://github.com/pavelpikta
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f0667f46d003401c8f9d3f6cf4a94edc367aae7a -
Trigger Event:
release
-
Statement type:
File details
Details for the file cubctl-1.0.0-py3-none-any.whl.
File metadata
- Download URL: cubctl-1.0.0-py3-none-any.whl
- Upload date:
- Size: 36.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
55280fb9e86773422153cbe6c9e55069a02c91d5e0b848cb54207fb98dac3dfa
|
|
| MD5 |
7289260edf970778f1700d4c8bce0b51
|
|
| BLAKE2b-256 |
cf7c985b245a5c7d0da91d1ecd20ffbeb167c4177cb3a83f8a6718a1dd5bad3a
|
Provenance
The following attestation bundles were made for cubctl-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on pavelpikta/cubctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cubctl-1.0.0-py3-none-any.whl -
Subject digest:
55280fb9e86773422153cbe6c9e55069a02c91d5e0b848cb54207fb98dac3dfa - Sigstore transparency entry: 1736237037
- Sigstore integration time:
-
Permalink:
pavelpikta/cubctl@f0667f46d003401c8f9d3f6cf4a94edc367aae7a -
Branch / Tag:
refs/tags/1.0.0 - Owner: https://github.com/pavelpikta
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f0667f46d003401c8f9d3f6cf4a94edc367aae7a -
Trigger Event:
release
-
Statement type: