albus-cli 0.1.0__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. albus_cli-0.2.0/.github/ISSUE_TEMPLATE/bug.yml +61 -0
  2. albus_cli-0.2.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
  3. albus_cli-0.2.0/.github/pull_request_template.md +10 -0
  4. albus_cli-0.2.0/.github/workflows/close-pull-requests.yml +51 -0
  5. {albus_cli-0.1.0 → albus_cli-0.2.0}/.gitignore +0 -1
  6. albus_cli-0.2.0/AGENTS.md +85 -0
  7. albus_cli-0.2.0/CONTRIBUTING.md +32 -0
  8. {albus_cli-0.1.0 → albus_cli-0.2.0}/Makefile +2 -0
  9. albus_cli-0.2.0/PKG-INFO +180 -0
  10. albus_cli-0.2.0/README.md +165 -0
  11. albus_cli-0.2.0/RELEASING.md +101 -0
  12. albus_cli-0.2.0/SECURITY.md +21 -0
  13. {albus_cli-0.1.0 → albus_cli-0.2.0}/install.ps1 +15 -5
  14. {albus_cli-0.1.0 → albus_cli-0.2.0}/install.sh +17 -7
  15. {albus_cli-0.1.0 → albus_cli-0.2.0}/pyproject.toml +4 -2
  16. albus_cli-0.2.0/pyrightconfig.json +17 -0
  17. albus_cli-0.2.0/setup.sh +22 -0
  18. albus_cli-0.2.0/src/albus_cli/client.py +288 -0
  19. albus_cli-0.2.0/src/albus_cli/commands/auth.py +98 -0
  20. albus_cli-0.2.0/src/albus_cli/commands/invites.py +33 -0
  21. {albus_cli-0.1.0 → albus_cli-0.2.0}/src/albus_cli/commands/sessions.py +37 -7
  22. albus_cli-0.2.0/src/albus_cli/commands/status.py +101 -0
  23. albus_cli-0.2.0/src/albus_cli/commands/tokens.py +43 -0
  24. albus_cli-0.2.0/src/albus_cli/context.py +41 -0
  25. albus_cli-0.2.0/src/albus_cli/credentials.py +245 -0
  26. albus_cli-0.2.0/src/albus_cli/docs.py +21 -0
  27. albus_cli-0.2.0/src/albus_cli/main.py +177 -0
  28. albus_cli-0.2.0/src/albus_cli/oauth.py +373 -0
  29. albus_cli-0.2.0/src/albus_cli/output.py +92 -0
  30. albus_cli-0.2.0/tests/conftest.py +164 -0
  31. albus_cli-0.2.0/tests/test_auth.py +657 -0
  32. albus_cli-0.2.0/tests/test_cli.py +362 -0
  33. albus_cli-0.2.0/tests/test_credentials.py +391 -0
  34. albus_cli-0.2.0/tests/test_health.py +45 -0
  35. albus_cli-0.2.0/tests/test_invites.py +63 -0
  36. albus_cli-0.2.0/tests/test_oauth.py +379 -0
  37. albus_cli-0.2.0/tests/test_status.py +162 -0
  38. albus_cli-0.2.0/tests/test_tokens.py +108 -0
  39. albus_cli-0.2.0/tools/mirror-release +215 -0
  40. {albus_cli-0.1.0 → albus_cli-0.2.0}/tools/publish +12 -51
  41. albus_cli-0.2.0/tools/release_state.sh +60 -0
  42. {albus_cli-0.1.0 → albus_cli-0.2.0}/uv.lock +5 -5
  43. albus_cli-0.1.0/.github/workflows/check.yml +0 -32
  44. albus_cli-0.1.0/PKG-INFO +0 -98
  45. albus_cli-0.1.0/README.md +0 -83
  46. albus_cli-0.1.0/RELEASING.md +0 -59
  47. albus_cli-0.1.0/src/albus_cli/client.py +0 -30
  48. albus_cli-0.1.0/src/albus_cli/context.py +0 -24
  49. albus_cli-0.1.0/src/albus_cli/main.py +0 -63
  50. albus_cli-0.1.0/src/albus_cli/output.py +0 -16
  51. albus_cli-0.1.0/tests/conftest.py +0 -78
  52. albus_cli-0.1.0/tests/test_cli.py +0 -186
  53. {albus_cli-0.1.0 → albus_cli-0.2.0}/LICENSE +0 -0
  54. {albus_cli-0.1.0 → albus_cli-0.2.0}/src/albus_cli/__init__.py +0 -0
  55. {albus_cli-0.1.0 → albus_cli-0.2.0}/src/albus_cli/__main__.py +0 -0
  56. {albus_cli-0.1.0 → albus_cli-0.2.0}/src/albus_cli/commands/__init__.py +0 -0
  57. {albus_cli-0.1.0 → albus_cli-0.2.0}/src/albus_cli/commands/agents.py +0 -0
  58. {albus_cli-0.1.0 → albus_cli-0.2.0}/src/albus_cli/commands/secrets.py +0 -0
  59. {albus_cli-0.1.0 → albus_cli-0.2.0}/tests/__init__.py +0 -0
  60. {albus_cli-0.1.0 → albus_cli-0.2.0}/tools/check +0 -0
@@ -0,0 +1,61 @@
1
+ name: Bug report
2
+ description: Report incorrect or unexpected behavior in the albus command
3
+ body:
4
+ - type: markdown
5
+ attributes:
6
+ value: |
7
+ The CLI is maintained upstream, and this repository is a mirror of each
8
+ release. Fixes land upstream and arrive in the next published version,
9
+ which closes the issue.
10
+
11
+ **Never paste access tokens, API keys, secret values, or customer data
12
+ into this issue.** Redact them from commands, logs, and tracebacks.
13
+ Report suspected vulnerabilities privately through
14
+ [SECURITY.md](https://github.com/albusgroup/albus-cli/blob/master/SECURITY.md)
15
+ instead of opening an issue.
16
+
17
+ - type: input
18
+ id: cli-version
19
+ attributes:
20
+ label: albus-cli version
21
+ description: Output of `pip show albus-cli` or `uv tool list`.
22
+ placeholder: "0.2.0"
23
+ validations:
24
+ required: true
25
+
26
+ - type: input
27
+ id: python-version
28
+ attributes:
29
+ label: Python version
30
+ description: Output of `python --version`.
31
+ placeholder: "3.12.4"
32
+ validations:
33
+ required: true
34
+
35
+ - type: textarea
36
+ id: reproduction
37
+ attributes:
38
+ label: Command and output
39
+ description: >
40
+ The command you ran and what it printed, with credentials and customer
41
+ data removed.
42
+ render: shell
43
+ validations:
44
+ required: true
45
+
46
+ - type: textarea
47
+ id: expected
48
+ attributes:
49
+ label: Expected behavior
50
+ validations:
51
+ required: true
52
+
53
+ - type: textarea
54
+ id: actual
55
+ attributes:
56
+ label: Actual behavior
57
+ description: >
58
+ What happened instead, including the exit status, the HTTP status, and
59
+ redacted output when relevant.
60
+ validations:
61
+ required: true
@@ -0,0 +1,8 @@
1
+ blank_issues_enabled: true
2
+ contact_links:
3
+ - name: Report a security vulnerability
4
+ url: https://github.com/albusgroup/albus-cli/blob/master/SECURITY.md
5
+ about: Report privately. Do not open a public issue for a vulnerability.
6
+ - name: How this repository is maintained
7
+ url: https://github.com/albusgroup/albus-cli/blob/master/CONTRIBUTING.md
8
+ about: This is a release mirror. It accepts issues, not pull requests.
@@ -0,0 +1,10 @@
1
+ **This repository does not accept pull requests, and this one will be closed
2
+ automatically.**
3
+
4
+ It is a mirror of the Albus CLI: every release overwrites the whole tree, so a
5
+ merge here is deleted by the next published version.
6
+
7
+ Open an [issue](https://github.com/albusgroup/albus-cli/issues/new/choose)
8
+ instead and include your patch in the body. Maintainers apply the fix upstream,
9
+ and it ships in the next release, which closes the issue. See
10
+ [CONTRIBUTING.md](https://github.com/albusgroup/albus-cli/blob/master/CONTRIBUTING.md).
@@ -0,0 +1,51 @@
1
+ name: Close pull requests
2
+
3
+ # This repository is a mirror: every release overwrites its tree, so a merged
4
+ # pull request is deleted by the next release. GitHub cannot disable pull
5
+ # requests, so opened ones are closed here with a pointer to issues.
6
+ #
7
+ # pull_request_target runs this file from the default branch with a read/write
8
+ # token, so it also works for pull requests opened from forks.
9
+ on:
10
+ pull_request_target:
11
+ types: [opened, reopened]
12
+
13
+ permissions:
14
+ pull-requests: write
15
+
16
+ jobs:
17
+ close:
18
+ runs-on: ubuntu-latest
19
+
20
+ steps:
21
+ - env:
22
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
23
+ GH_REPO: ${{ github.repository }}
24
+ PULL_REQUEST: ${{ github.event.number }}
25
+ AUTHOR: ${{ github.event.pull_request.user.login }}
26
+ run: |
27
+ cat > comment.md <<EOF
28
+ Thanks for taking the time to write this, @${AUTHOR} — but this
29
+ repository is a read-only mirror of the Albus CLI, and every release
30
+ overwrites its entire tree. A pull request merged here would be
31
+ deleted by the next published version, so this one is being closed
32
+ unmerged.
33
+
34
+ Please open an issue instead:
35
+ https://github.com/${GH_REPO}/issues/new/choose
36
+
37
+ Describe the behavior you expected, and include the diff or patch
38
+ from this pull request in the issue body. Maintainers apply the fix
39
+ in the private upstream repository, and it reaches you in the next
40
+ release, which closes the issue.
41
+
42
+ Report suspected vulnerabilities privately through
43
+ [SECURITY.md](https://github.com/${GH_REPO}/blob/master/SECURITY.md),
44
+ not as a public issue.
45
+
46
+ See [CONTRIBUTING.md](https://github.com/${GH_REPO}/blob/master/CONTRIBUTING.md)
47
+ for how this repository is maintained.
48
+ EOF
49
+
50
+ gh pr comment "$PULL_REQUEST" --body-file comment.md
51
+ gh pr close "$PULL_REQUEST"
@@ -6,4 +6,3 @@ __pycache__/
6
6
  .ruff_cache/
7
7
  dist/
8
8
  build/
9
- .tmp/
@@ -0,0 +1,85 @@
1
+ # albus-cli
2
+
3
+ Source of truth for the public `albus-cli` Python package: the `albus`
4
+ command-line client for the Albus REST API, built on `albus-sdk`. Releases are
5
+ published to PyPI and copied out to the public `albusgroup/albus-cli`
6
+ repository, which is a mirror. See
7
+ [`.agents/plans/sdk-publishing-from-monorepo.md`](../../.agents/plans/sdk-publishing-from-monorepo.md)
8
+ and the repository-wide
9
+ [engineering style guide](../../.agents/style-guide.md).
10
+
11
+ ## Commands
12
+
13
+ Run everything from `clients/albus-cli/`. `uv` owns the virtualenv and
14
+ `uv.lock`.
15
+
16
+ | Command | Purpose |
17
+ |---|---|
18
+ | `./setup.sh` | Install `uv`, Python 3.11, and the development environment |
19
+ | `make install` | `uv sync` |
20
+ | `make lint` | `ruff check` + `ruff format --check` |
21
+ | `make typecheck` | `mypy --strict` |
22
+ | `make test` | `pytest` |
23
+ | `make check` | all of the above |
24
+ | `./tools/check` | `make check`, and what a release runs |
25
+ | `./tools/publish --dry-run <version>` | Validate a release without uploading |
26
+ | `./tools/publish [--testpypi] <version>` | Upload, after explicit authorization |
27
+ | `./tools/mirror-release [--dry-run] <version> <checkout>` | Copy the released tree to the public mirror |
28
+
29
+ See [`RELEASING.md`](RELEASING.md). Publishing is never implied by a merge: a
30
+ version reaches PyPI only when it was explicitly authorized, and published
31
+ versions are immutable.
32
+
33
+ ## Conventions
34
+
35
+ - The CLI owns argument parsing, output, and error reporting only. Request
36
+ building, retries, and response types belong to `albus-sdk`; never hand-roll
37
+ HTTP calls or redefine SDK models.
38
+ - Every command maps to exactly one SDK operation and prints its response as
39
+ JSON via `output.emit`. Do not add per-command formatting or extra
40
+ round trips.
41
+ - `login` and `logout` are the one exception: they sign in to Auth0 rather
42
+ than call Albus, so they drive `oauth.py` and the credential store, and
43
+ print prose. `login` also reads back `/whoami` to name the account it
44
+ signed in as. Any further exception needs the same kind of reason.
45
+ - `output.py` owns every colour the CLI emits, prose included: a command
46
+ composes its report from `progress`, `done`, `field`, `link`, and `note`
47
+ rather than calling `typer.secho` itself. Styling must survive being
48
+ piped, which means letting Typer drop the escapes and never writing them
49
+ by hand.
50
+ - `client.py` is the single owner of credential and transport configuration.
51
+ It resolves `ALBUS_API_KEY` first, then the stored browser session for the
52
+ base URL — renewing it when it has expired — and otherwise fails with a
53
+ message naming both ways to get a credential.
54
+ - A command wrapping an operation whose `security` in `api/openapi.yaml`
55
+ lists `bearerAuth` only (`whoami`, `tokens`, `invites`) builds its client
56
+ with `signed_in_client`, which uses the browser session and never an API
57
+ key: the key would be a 401 the caller cannot act on.
58
+ - Never print or log a token. Every sentence about a credential — not signed
59
+ in, expired, rejected, shadowed by an API key — is written in `client.py`,
60
+ which is the only place that knows which credential was sent. An
61
+ instruction for the credential the command did not use is worse than none.
62
+ - Renewing a stored session goes through `credentials.renew`, which holds the
63
+ store's lock across the Auth0 call. Two processes spending one refresh
64
+ token is a rotation reuse, and Auth0 revokes the family.
65
+ - Nothing from the credential store or `oauth.py` reaches the terminal as a
66
+ traceback; `main.py` turns it into an instruction naming the file.
67
+ - Tests drive commands through `typer.testing.CliRunner` with a fake SDK; they
68
+ never reach the network.
69
+ - Keep lines at 81 characters or fewer (`ruff` enforces it).
70
+ - The `albus-sdk` dependency is pinned to one version. The published CLI has
71
+ to name an SDK version that exists on PyPI, so the pin is bumped
72
+ deliberately in the pull request that needs the newer SDK — never floated to
73
+ whatever is latest at install time.
74
+ - The public repository accepts issues, not pull requests. A user-reported bug
75
+ is fixed here and reaches them in the next release, which closes the issue
76
+ via a `Mirror-Issue: albusgroup/albus-cli#<n>` trailer on the fix's commit.
77
+ - `.github/` is the mirror's, not this repository's: GitHub only runs workflows
78
+ and reads templates from a repository root, so these files are inert here and
79
+ active once the release copies the tree out. Anything the mirror needs
80
+ belongs here, since the release overwrites its entire tree. This repository's
81
+ own CI for the CLI is `.github/workflows/cli-test.yml` at the root.
82
+ - `install.sh` and `install.ps1` are what the public install instructions pipe
83
+ into a shell. They install the published package from PyPI and must keep
84
+ working against the mirror's `master`, which is where the documented URLs
85
+ point.
@@ -0,0 +1,32 @@
1
+ # Contributing to albus-cli
2
+
3
+ Thanks for helping improve the Albus CLI.
4
+
5
+ ## Report a problem
6
+
7
+ Open a [GitHub issue](https://github.com/albusgroup/albus-cli/issues) with:
8
+
9
+ - The installed `albus-cli` and Python versions.
10
+ - The command you ran and the exact output.
11
+ - The expected and actual behavior.
12
+
13
+ Do not include access tokens, organization keys, secret values, or other
14
+ sensitive data. `albus` never prints a credential; if you have pasted one into
15
+ a log, redact it and rotate the credential.
16
+
17
+ Report suspected vulnerabilities privately by following
18
+ [SECURITY.md](SECURITY.md), not by opening a public issue.
19
+
20
+ ## This repository is a mirror
21
+
22
+ The CLI is developed in the private Albus repository, alongside the
23
+ `api/openapi.yaml` contract and the SDK it is built on, and each release is
24
+ copied here. This repository does not accept pull requests: a change merged
25
+ here is removed by the next release, so one opened here is commented on and
26
+ closed automatically.
27
+
28
+ Issues are the right channel, and they are read. Maintainers fix the problem
29
+ upstream, and the fix arrives in the next published version, which closes the
30
+ issue.
31
+
32
+ See [RELEASING.md](RELEASING.md) for how a version is produced and published.
@@ -1,5 +1,7 @@
1
1
  .PHONY: install lint fmt typecheck test check
2
2
 
3
+ # uv owns the virtualenv. The albus-sdk version is pinned in pyproject.toml,
4
+ # so a sync installs what a release would publish against.
3
5
  install:
4
6
  uv sync
5
7
 
@@ -0,0 +1,180 @@
1
+ Metadata-Version: 2.5
2
+ Name: albus-cli
3
+ Version: 0.2.0
4
+ Summary: Command-line client for the Albus REST API
5
+ Project-URL: Homepage, https://github.com/albusgroup/albus-cli
6
+ Project-URL: Repository, https://github.com/albusgroup/albus-cli
7
+ Project-URL: Issues, https://github.com/albusgroup/albus-cli/issues
8
+ Author: Albus
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Requires-Python: >=3.11
12
+ Requires-Dist: albus-sdk==0.6.0
13
+ Requires-Dist: typer<0.28,>=0.26.8
14
+ Description-Content-Type: text/markdown
15
+
16
+ # albus CLI
17
+
18
+ Command-line client for the Albus REST API, built on the public
19
+ [`albus-sdk`](https://pypi.org/project/albus-sdk/) Python SDK. It is a thin
20
+ shell over the SDK: every command that calls Albus maps to one API operation
21
+ and prints the JSON response, so output pipes into `jq`.
22
+
23
+ ## Install
24
+
25
+ macOS / Linux:
26
+
27
+ ```bash
28
+ curl -fsSL https://raw.githubusercontent.com/albusgroup/albus-cli/master/install.sh | sh
29
+ ```
30
+
31
+ Windows (PowerShell):
32
+
33
+ ```powershell
34
+ irm https://raw.githubusercontent.com/albusgroup/albus-cli/master/install.ps1 | iex
35
+ ```
36
+
37
+ Pin a version:
38
+
39
+ ```bash
40
+ curl -fsSL https://raw.githubusercontent.com/albusgroup/albus-cli/master/install.sh | ALBUS_CLI_VERSION=0.2.0 sh
41
+ ```
42
+
43
+ The installer uses, in order: `uv tool install`, `pip install --user`, or
44
+ `pip` inside a conda environment. It does not download OS-specific binaries.
45
+ To install directly instead:
46
+
47
+ ```bash
48
+ uv tool install albus-cli
49
+ # or
50
+ pip install --user albus-cli
51
+ ```
52
+
53
+ ## Authentication
54
+
55
+ Sign in with a browser, which stores a session per base URL and renews it as
56
+ it expires:
57
+
58
+ ```bash
59
+ albus login
60
+ albus whoami
61
+ albus logout
62
+ ```
63
+
64
+ `albus health` is the one command that needs no credential, matching its empty
65
+ `security` in `api/openapi.yaml`: run it first to tell an unreachable API from
66
+ an unauthenticated one. `albus status` reports which credential is in effect
67
+ and whether Albus accepts it, as JSON, exiting 0 either way — it is the one
68
+ command to run to find out where you stand. `albus login --no-browser` prints
69
+ the authorization URL instead of opening it, for a coding agent signing in the
70
+ user in front of it.
71
+
72
+ Or export an organization API key, which wins over a stored session so CI and
73
+ agent harnesses need not touch disk:
74
+
75
+ ```bash
76
+ export ALBUS_API_KEY=... # organization API key
77
+ export ALBUS_BASE_URL=http://localhost:8080/api # optional; defaults to prod
78
+ ```
79
+
80
+ `--base-url` overrides `ALBUS_BASE_URL`, and `--timeout` bounds each request
81
+ (a waiting `sessions run` long-polls and is exempt).
82
+
83
+ `albus login` opens a browser on this machine and listens on
84
+ `127.0.0.1:8484-8487`; on a headless host, forward those ports or export
85
+ `ALBUS_API_KEY` instead. The
86
+ session is written to `$ALBUS_CONFIG_DIR/credentials.json`, else
87
+ `$XDG_CONFIG_HOME/albus/credentials.json`, else `~/.config/albus/`.
88
+
89
+ Operations whose `security` in `api/openapi.yaml` lists `bearerAuth` only,
90
+ such as `/whoami`, `/tokens`, and `/invites`, need the browser session.
91
+ `albus whoami`, `albus tokens`, and `albus invites` use it even when
92
+ `ALBUS_API_KEY` is exported, and say to run `albus login` when there is none.
93
+ Sign in first, then `albus tokens create` to mint the key that
94
+ `ALBUS_API_KEY` carries.
95
+
96
+ ## Commands
97
+
98
+ ```bash
99
+ albus health
100
+ albus --version
101
+ albus login
102
+ albus login --no-browser
103
+ albus whoami
104
+ albus logout
105
+ albus status
106
+
107
+ albus sessions run my-session -p "summarize the incident" \
108
+ --agent-name support-triage --model gemini-3.6-flash \
109
+ --provider gemini --credential albus.sh/secrets/gemini-key
110
+ albus sessions run my-session -p "and the follow-up?" \
111
+ --agent-name support-triage --agent-file agent.json --no-wait
112
+ albus sessions list
113
+ albus sessions get my-session --limit 20
114
+ albus sessions audit my-session --after "$cursor"
115
+ albus sessions delete my-session
116
+
117
+ albus secrets list
118
+ albus secrets create gemini-key --value ... # or pipe the value on stdin
119
+ albus secrets get gemini-key
120
+ albus secrets update gemini-key < value.txt
121
+ albus secrets delete gemini-key
122
+
123
+ albus agents list
124
+ albus agents get support-triage
125
+ albus agents revision support-triage "$revision"
126
+
127
+ albus tokens list
128
+ albus tokens create ci
129
+ albus tokens get "$id"
130
+ albus tokens delete "$id"
131
+
132
+ albus invites create teammate@example.com
133
+ ```
134
+
135
+ `tokens create` prints the only copy of the key value the API ever returns;
136
+ `list` and `get` return metadata alone.
137
+
138
+ `invites create` invites a person by email, and they get their own
139
+ organization on first sign-in. `CreateInviteRequest`'s `role` and
140
+ `organization_id` have no flags: one user is one organization for the beta.
141
+
142
+ `sessions run` waits for the assistant response by default; pass `--no-wait`
143
+ to return as soon as the invocation is accepted, or `--wait-timeout` to bound
144
+ the wait server-side. Pass `--idempotency-key` to make a run retry-safe. The
145
+ JSON output carries the effective `idempotency_key`, whether supplied by the
146
+ caller or generated by the server — absent only if something between the CLI
147
+ and Albus strips the response header on a run that supplied no key.
148
+
149
+ `--agent-file` takes a JSON object shaped like the API's `AgentConfig` and
150
+ covers what the flags do not (MCP servers, provider URL overrides):
151
+
152
+ ```json
153
+ {
154
+ "model": { "name": "gemini-3.6-flash" },
155
+ "mcp_servers": [
156
+ { "name": "github", "url": "https://mcp.example.com/mcp" }
157
+ ]
158
+ }
159
+ ```
160
+
161
+ ## Documentation
162
+
163
+ | Reader | URL |
164
+ |---|---|
165
+ | A person | <https://docs.albus.sh> |
166
+ | A coding agent | <https://docs.albus.sh/agents/docs.md> |
167
+
168
+ The CLI prints both, so whoever is reading its output has the URL that is
169
+ theirs.
170
+
171
+ ## Development
172
+
173
+ The CLI is developed in the private Albus repository, next to the
174
+ `api/openapi.yaml` contract and the SDK it is built on, and each release is
175
+ copied to the public `albusgroup/albus-cli` repository. That repository accepts
176
+ issues, not pull requests — see [CONTRIBUTING.md](CONTRIBUTING.md).
177
+
178
+ ```bash
179
+ make check # ruff, mypy --strict, pytest
180
+ ```
@@ -0,0 +1,165 @@
1
+ # albus CLI
2
+
3
+ Command-line client for the Albus REST API, built on the public
4
+ [`albus-sdk`](https://pypi.org/project/albus-sdk/) Python SDK. It is a thin
5
+ shell over the SDK: every command that calls Albus maps to one API operation
6
+ and prints the JSON response, so output pipes into `jq`.
7
+
8
+ ## Install
9
+
10
+ macOS / Linux:
11
+
12
+ ```bash
13
+ curl -fsSL https://raw.githubusercontent.com/albusgroup/albus-cli/master/install.sh | sh
14
+ ```
15
+
16
+ Windows (PowerShell):
17
+
18
+ ```powershell
19
+ irm https://raw.githubusercontent.com/albusgroup/albus-cli/master/install.ps1 | iex
20
+ ```
21
+
22
+ Pin a version:
23
+
24
+ ```bash
25
+ curl -fsSL https://raw.githubusercontent.com/albusgroup/albus-cli/master/install.sh | ALBUS_CLI_VERSION=0.2.0 sh
26
+ ```
27
+
28
+ The installer uses, in order: `uv tool install`, `pip install --user`, or
29
+ `pip` inside a conda environment. It does not download OS-specific binaries.
30
+ To install directly instead:
31
+
32
+ ```bash
33
+ uv tool install albus-cli
34
+ # or
35
+ pip install --user albus-cli
36
+ ```
37
+
38
+ ## Authentication
39
+
40
+ Sign in with a browser, which stores a session per base URL and renews it as
41
+ it expires:
42
+
43
+ ```bash
44
+ albus login
45
+ albus whoami
46
+ albus logout
47
+ ```
48
+
49
+ `albus health` is the one command that needs no credential, matching its empty
50
+ `security` in `api/openapi.yaml`: run it first to tell an unreachable API from
51
+ an unauthenticated one. `albus status` reports which credential is in effect
52
+ and whether Albus accepts it, as JSON, exiting 0 either way — it is the one
53
+ command to run to find out where you stand. `albus login --no-browser` prints
54
+ the authorization URL instead of opening it, for a coding agent signing in the
55
+ user in front of it.
56
+
57
+ Or export an organization API key, which wins over a stored session so CI and
58
+ agent harnesses need not touch disk:
59
+
60
+ ```bash
61
+ export ALBUS_API_KEY=... # organization API key
62
+ export ALBUS_BASE_URL=http://localhost:8080/api # optional; defaults to prod
63
+ ```
64
+
65
+ `--base-url` overrides `ALBUS_BASE_URL`, and `--timeout` bounds each request
66
+ (a waiting `sessions run` long-polls and is exempt).
67
+
68
+ `albus login` opens a browser on this machine and listens on
69
+ `127.0.0.1:8484-8487`; on a headless host, forward those ports or export
70
+ `ALBUS_API_KEY` instead. The
71
+ session is written to `$ALBUS_CONFIG_DIR/credentials.json`, else
72
+ `$XDG_CONFIG_HOME/albus/credentials.json`, else `~/.config/albus/`.
73
+
74
+ Operations whose `security` in `api/openapi.yaml` lists `bearerAuth` only,
75
+ such as `/whoami`, `/tokens`, and `/invites`, need the browser session.
76
+ `albus whoami`, `albus tokens`, and `albus invites` use it even when
77
+ `ALBUS_API_KEY` is exported, and say to run `albus login` when there is none.
78
+ Sign in first, then `albus tokens create` to mint the key that
79
+ `ALBUS_API_KEY` carries.
80
+
81
+ ## Commands
82
+
83
+ ```bash
84
+ albus health
85
+ albus --version
86
+ albus login
87
+ albus login --no-browser
88
+ albus whoami
89
+ albus logout
90
+ albus status
91
+
92
+ albus sessions run my-session -p "summarize the incident" \
93
+ --agent-name support-triage --model gemini-3.6-flash \
94
+ --provider gemini --credential albus.sh/secrets/gemini-key
95
+ albus sessions run my-session -p "and the follow-up?" \
96
+ --agent-name support-triage --agent-file agent.json --no-wait
97
+ albus sessions list
98
+ albus sessions get my-session --limit 20
99
+ albus sessions audit my-session --after "$cursor"
100
+ albus sessions delete my-session
101
+
102
+ albus secrets list
103
+ albus secrets create gemini-key --value ... # or pipe the value on stdin
104
+ albus secrets get gemini-key
105
+ albus secrets update gemini-key < value.txt
106
+ albus secrets delete gemini-key
107
+
108
+ albus agents list
109
+ albus agents get support-triage
110
+ albus agents revision support-triage "$revision"
111
+
112
+ albus tokens list
113
+ albus tokens create ci
114
+ albus tokens get "$id"
115
+ albus tokens delete "$id"
116
+
117
+ albus invites create teammate@example.com
118
+ ```
119
+
120
+ `tokens create` prints the only copy of the key value the API ever returns;
121
+ `list` and `get` return metadata alone.
122
+
123
+ `invites create` invites a person by email, and they get their own
124
+ organization on first sign-in. `CreateInviteRequest`'s `role` and
125
+ `organization_id` have no flags: one user is one organization for the beta.
126
+
127
+ `sessions run` waits for the assistant response by default; pass `--no-wait`
128
+ to return as soon as the invocation is accepted, or `--wait-timeout` to bound
129
+ the wait server-side. Pass `--idempotency-key` to make a run retry-safe. The
130
+ JSON output carries the effective `idempotency_key`, whether supplied by the
131
+ caller or generated by the server — absent only if something between the CLI
132
+ and Albus strips the response header on a run that supplied no key.
133
+
134
+ `--agent-file` takes a JSON object shaped like the API's `AgentConfig` and
135
+ covers what the flags do not (MCP servers, provider URL overrides):
136
+
137
+ ```json
138
+ {
139
+ "model": { "name": "gemini-3.6-flash" },
140
+ "mcp_servers": [
141
+ { "name": "github", "url": "https://mcp.example.com/mcp" }
142
+ ]
143
+ }
144
+ ```
145
+
146
+ ## Documentation
147
+
148
+ | Reader | URL |
149
+ |---|---|
150
+ | A person | <https://docs.albus.sh> |
151
+ | A coding agent | <https://docs.albus.sh/agents/docs.md> |
152
+
153
+ The CLI prints both, so whoever is reading its output has the URL that is
154
+ theirs.
155
+
156
+ ## Development
157
+
158
+ The CLI is developed in the private Albus repository, next to the
159
+ `api/openapi.yaml` contract and the SDK it is built on, and each release is
160
+ copied to the public `albusgroup/albus-cli` repository. That repository accepts
161
+ issues, not pull requests — see [CONTRIBUTING.md](CONTRIBUTING.md).
162
+
163
+ ```bash
164
+ make check # ruff, mypy --strict, pytest
165
+ ```