CLI
EmbedHub has a CLI for managing files and todos in your projects from your laptop or CI environment (GitHub Actions, GitLab Runners, etc.).
Installation
Download a prebuilt binary
| Platform | Architecture | Download |
|---|---|---|
| macOS (Apple Silicon) | arm64 | embedhub-darwin-arm64 |
| macOS (Intel) | amd64 | embedhub-darwin-amd64 |
| Linux | amd64 | embedhub-linux-amd64 |
| Linux | arm64 | embedhub-linux-arm64 |
| Windows | amd64 | embedhub-windows-amd64.exe |
After downloading, chmod +x it (macOS/Linux) and move it onto your
PATH:
chmod +x embedhub-darwin-arm64
sudo mv embedhub-darwin-arm64 /usr/local/bin/embedhub
embedhub --version
Configure your API key
Before using the CLI you need to give it an API key. The key tells EmbedHub which user the CLI is acting as and which projects it has access to.
1. Create a key in the web UI
- Log in to embedhub.com and click your name in the top right → Settings.
- Open the API Keys tab.
- Click Create API Key, name it (e.g. "laptop", "ci"), and tick which organizations the key should have access to.
- Copy the full key — it's shown only once. Treat it like a password.
API keys look like ehk_<16-char-prefix>_<40-char-secret>.
2. Tell the CLI about it
embedhub config set api-key ehk_1234567890123456_abcdef1234567890abcdef1234567890abcdef12
This writes the key to ~/.embedhub/config.yaml (file mode 0600). Confirm
it stuck:
embedhub config list
The key will be shown masked.
Alternative: environment variables
If you'd rather not write the key to disk (CI runners, ephemeral containers), set it in the environment instead:
| Variable | Purpose |
|---|---|
EMBEDHUB_API_KEY | API key — overrides the config file. |
EMBEDHUB_VERBOSE | Set to true for verbose output. |
For GitHub Actions, see the GitHub Action integration — it
takes the key as a secret and runs embedhub push for you.
Rotating or revoking
To rotate: create a new key in the web UI, run embedhub config set api-key <new>, then revoke the old one from the API Keys tab.
To revoke a key without replacing it: open the API Keys tab and click Revoke on the row you want to disable. The key stops working immediately.
Command reference
embedhub [command]
Available Commands:
config Manage configuration settings
push Upload a file or folder to a project
pull Download a file from a project
list List files in a project
search Search files by extension or substring
todos Manage project todos
help Help about any command
All commands take the project as org/project-name.
embedhub push
Upload files (with glob support) to a project. The last argument is always the project; any number of files, folders, or glob patterns may precede it.
embedhub push app.bin myorg/myproject --path releases/v1.0.0/
embedhub push *.zip myorg/myproject --path releases/latest/
embedhub push app.bin app.map app.elf myorg/myproject --path releases/v1.0.0/
embedhub push build/ docs/ myorg/myproject
Project folders
A project has a small set of canonical folders. Each one is surfaced by a specific feature in the web UI; uploads to other folders are accepted but won't appear in any section.
| Folder | What goes here | How it gets there |
|---|---|---|
photos/ | .jpg, .jpeg, .png, .svg, .webp, .gif, .mp4, .mov, .webm | Default for image & video extensions, or --path photos/ |
documents/ | .pdf, .md, .mdx, design notes, specs | Default for .pdf; pass --path documents/ for others |
releases/ | .bin, .map, .elf | Default for release extensions, or --path releases/ |
state-machines/palette/ | palette.yaml — developer-owned state/event vocabulary | Push explicitly: --path state-machines/palette/ |
state-machines/diagrams/ | <slug>.yaml — diagrams referencing the palette | Push explicitly: --path state-machines/diagrams/. The paired .svg is rendered by the editor; direct .svg uploads here are rejected. |
todos/ | Individual todo items as markdown | Use embedhub todos ... (not push) |
.zip files containing PDFs are auto-processed. The folder you pass via
--path is preserved.
embedhub list
embedhub list myorg/myproject
embedhub list myorg/myproject --prefix releases/
embedhub list myorg/myproject --json
embedhub search
embedhub search myorg/myproject .bin # match by extension
embedhub search myorg/myproject firmware # substring match in path
embedhub search myorg/myproject .pdf --prefix documents/
embedhub pull
embedhub pull myorg/myproject releases/app.bin
embedhub pull myorg/myproject releases/app.bin --output ./local-app.bin
embedhub todos
Manage project todos. Each todo is a small markdown file in the project — see the Todos page for the file format.
embedhub todos list myorg/myproject [--status done|wip|cancel] [--json]
embedhub todos add myorg/myproject --title "..." [--notes "..."] [--assignee <user>]
embedhub todos show myorg/myproject <id-or-prefix> [--json]
embedhub todos status myorg/myproject <id-or-prefix> <new> # in_progress | complete | cancelled
embedhub todos assign myorg/myproject <id-or-prefix> <user> # or --unassign
embedhub todos rm myorg/myproject <id-or-prefix> [--yes]
embedhub todos members myorg/myproject [--json]
<id-or-prefix> accepts a full UUID or any unique prefix (8 chars is usually
enough — same as the IDs shown by embedhub todos list). Status accepts the
short aliases done, wip, and cancel.
Examples
# Daily flow
embedhub todos list anuj/firmware
embedhub todos add anuj/firmware --title "review LED driver PR" --assignee tanvi
embedhub todos status anuj/firmware 9f3e2c1d done
# CI pipeline — file a follow-up todo when a build fails
if ! make test; then
embedhub todos add anuj/firmware \
--title "Fix failing test on $(git rev-parse --short HEAD)" \
--notes "$(make test 2>&1 | tail -3)"
fi
# Agent flow — pick up the next in-progress todo and complete it
ID=$(embedhub todos list anuj/firmware --status wip --json | jq -r '.[0].id')
embedhub todos status anuj/firmware "$ID" done
CI/CD example
#!/bin/bash
go build -o app .
embedhub push app john/my-app --path "releases/$(git describe --tags)/"
embedhub push app john/my-app --path "releases/latest/"
echo "✓ Deployed to EmbedHub"
Security
- API keys are stored in
~/.embedhub/config.yamland masked when displayed. - All communication uses HTTPS.
- API keys only work with your personal organization's projects.
Troubleshooting
"API key not configured" — run embedhub config set api-key YOUR_KEY.
"Access denied" — ensure the key is valid and the project belongs to your personal organization.
"Not found" on todos commands — confirm your role on the project grants
read/write/delete on /todos/* (org owners always have full access).