monolynx-cli
Command-line client for the Monolynx platform: manage projects, tickets, sprints and wiki pages from your terminal.
Installation
Requirements: Python 3.10 or newer.
With pipx (recommended, installs the CLI in its own isolated environment):
pipx install monolynx-cli
With uv:
uv tool install monolynx-cli
With pip:
pip install monolynx-cli
With Homebrew (macOS and Linux), from the monolynx/tap tap. Either install in one step, which adds the tap for you:
brew install monolynx/tap/monolynx
or add the tap first and then install by the short name:
brew tap monolynx/tap
brew install monolynx
The formula is not in homebrew-core, so the short brew install monolynx works only after brew tap monolynx/tap.
Check the installation:
monolynx --version
Quickstart
-
Sign in. The default flow opens your browser and signs you in with OAuth:
monolynx auth login
On a CI runner or a headless machine, use an API token generated in the Monolynx dashboard (
/dashboard/profile/tokens) instead:monolynx auth login --token osk_your_token
-
List the projects you have access to:
monolynx project list
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━┓ ┃ id ┃ name ┃ slug ┃ code ┃ role ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━┩ │ 6f1c2a9e-3b4d-4c8e-9a1f-2d7b5e8c0a31 │ My Project │ my-project │ MP │ admin │ └──────────────────────────────────────┴────────────┴────────────┴──────┴────────┘
Columns trimmed for brevity: the CLI prints every field the API returns, so the real table also has
descriptionandcreated_at. -
List the tickets of a project. Ticket commands need a project, passed as a global option before the command group:
monolynx --project my-project ticket list
┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━┓ ┃ key ┃ title ┃ status ┃ priority ┃ story_points ┃ ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━┩ │ MP-12 │ Export the monthly report │ in_progress │ high │ 3 │ │ MP-11 │ Fix login redirect │ todo │ medium │ 2 │ └────────┴──────────────────────────────┴─────────────┴──────────┴──────────────┘ Strona 1/1, razem: 2
Columns trimmed for brevity: the real table has 14 columns (
id,key,title,description,status,priority,story_points,sprint_id,assignee_email,due_date,label_ids,created_via_ai,created_at,updated_at). The last line is the page footer, printed on stderr.To avoid typing
--projectevery time, store the project in your profile (replacedefaultwith your profile name if you use another one):monolynx config set profile.default.project my-project monolynx ticket list
How signing in works
monolynx auth login without options uses OAuth 2.1 (Authorization Code with PKCE):
- The CLI reads the server metadata from
<endpoint>/.well-known/oauth-authorization-server. - It starts a short-lived local server on
127.0.0.1(random port, path/callback) and registers itself with Dynamic Client Registration. Registration runs on every login, because the server matches the redirect address including the port. - It opens your browser on the Monolynx consent page. You have 300 seconds to approve.
- It exchanges the code for tokens and checks them with
GET /api/v2/me. Only then does it store them in the profile (auth_type = "oauth",access_token,refresh_token,expires_at,client_id).
A timeout, a denied consent or a mismatched state parameter ends the login with exit code 3 and leaves the configuration unchanged.
Login options:
monolynx auth login --no-browser
monolynx auth login --token osk_your_token
monolynx auth login --endpoint https://monolynx.example.com --profile work
--no-browserprints the authorization URL on stderr instead of opening a browser (the CLI does the same when opening the browser fails). The browser must still run on the same machine as the CLI, because the redirect goes to127.0.0.1. Over SSH without port forwarding, use--token.--tokenstores an API token without a browser (auth_type = "token").--endpointand--profilework with both flows.
The OAuth access token is valid for 30 days. Every command that calls the API keeps the session alive. project, member, ticket, sprint and wiki commands do it in two ways, auth whoami only reactively:
- Proactively (not in
auth whoami): when the profile'sexpires_atis less than 24 hours away (or already past), the CLI refreshes the tokens once before the first request of the command and sends the request with the new access token. The server rotates the refresh token and both new tokens are saved in the profile, so regular use extends the session. If this refresh fails, the command goes on with the current token. - Reactively: when the server answers 401, the CLI refreshes the tokens once and repeats the request. A failed refresh ends with a message asking you to run
monolynx auth loginand exit code 3.
Neither applies to --token profiles or to MONOLYNX_TOKEN.
monolynx auth whoami shows the signed-in user; for an OAuth profile it also shows expires_at. Tokens are always masked, never printed in full. monolynx auth logout removes the stored tokens from the profile.
Command reference
Help texts, prompts and messages of the CLI are in Polish. Run monolynx --help, monolynx <group> --help or monolynx <group> <command> --help for the built-in help.
Arguments in angle brackets are positional; [...] marks an optional one. Options are given after the command name, global options before the command group.
Global options
| Option | Default | Description |
|---|---|---|
-o, --output |
table in a terminal, json otherwise |
Output format: table, json, yaml or csv. |
--no-color |
off | Disable table colors. The NO_COLOR environment variable (any non-empty value) does the same. |
-q, --quiet |
off | Silence progress messages on stderr. Data on stdout and error messages are unaffected. |
--profile |
active profile | Configuration profile to use. |
--project |
none | Project slug. |
--debug |
off | Log HTTP requests and responses on stderr (token always masked, body cut to 500 characters). |
--timeout |
30.0 |
HTTP request timeout in seconds, must be greater than zero. |
--version |
Print the version and exit. |
monolynx -o json auth whoami
monolynx --quiet -o csv config list
monolynx --profile work --project my-project ticket list
monolynx --timeout 10 --debug auth whoami
auth
| Command | Arguments and options | Description |
|---|---|---|
auth login |
--endpoint, --token, --profile, --no-browser |
Sign in with OAuth in the browser, or with an API token, and save the session in the profile. |
auth logout |
--profile |
Remove the stored secrets (token, access_token, refresh_token, expires_at) of the profile. |
auth whoami |
--profile |
Show the signed-in user. |
The local --profile of an auth command takes precedence over the global --profile.
config
| Command | Arguments and options | Description |
|---|---|---|
config get |
<key> |
Print the value under a dotted key (secrets masked). |
config set |
<key> <value> |
Set the value under a dotted key. |
config list |
Print the whole configuration as key/value rows (secrets masked). |
Valid keys are general.active_profile and profile.<name>.<field>, see Configuration and profiles. These commands edit the file directly and ignore --profile and --project.
project
| Command | Arguments and options | Description |
|---|---|---|
project list |
List the projects you have access to (all pages). | |
project get |
<slug> |
Show project details: your role, member and ticket counts, active sprint. |
project create |
--name (required), --slug, --description, --code |
Create a project. Without --slug and --code the server derives them from the name. |
project update |
<slug>, --name, --description, --new-slug |
Change a project; only the given options are sent. |
project delete |
<slug>, -y/--yes |
Delete a project (asks for confirmation unless --yes). |
project summary |
<slug> |
Show the project summary: unresolved errors, monitors, uptime, active sprint, backlog. |
member
| Command | Arguments and options | Description |
|---|---|---|
member list |
--project |
List project members (all pages). |
member invite |
<email>, --project, --role (member or admin, default member) |
Invite a person to the project. |
member remove |
<email>, --project, -y/--yes |
Remove a member (asks for confirmation unless --yes). |
The local --project of a member command takes precedence over the global --project, MONOLYNX_PROJECT and the profile.
ticket
All ticket commands work on the project resolved from --project, MONOLYNX_PROJECT or the profile. <ticket> is a ticket UUID or key, for example MON-42.
| Command | Arguments and options | Description |
|---|---|---|
ticket list |
--status, --priority, --search, --sprint, --due-before, --due-after, --overdue, --label, --page |
List project tickets with filters (one page). --search matches the title only; use ticket search to match the description too. |
ticket search |
[query], --status, --priority, --assignee, --sprint, --due-before, --due-after, --page |
Search tickets by phrase (title or description) and filters (one page). |
ticket get |
<ticket> |
Show ticket details. |
ticket create |
--title (required), --description, --description-file, --priority, --sp/--story-points, --sprint, --assignee, --due, --label, --ac, --spec-page, --blocked-by |
Create a ticket. --label, --ac and --blocked-by can be repeated; --blocked-by takes the UUID of the blocking ticket (not the key). |
ticket update |
<ticket>, --title, --description, --description-file, --status, --priority, --sp/--story-points, --sprint, --assignee, --due, --label, --blocked-by, --no-blockers |
Update a ticket; only the given fields are sent. --label and --blocked-by replace the current values; --blocked-by takes the UUID of the blocking ticket (not the key). |
ticket delete |
<ticket>, -y/--yes |
Delete a ticket (asks for confirmation unless --yes). |
ticket bulk-update |
<tickets>..., --status, --priority, --assignee, --sprint, --due |
Update many tickets in one request. |
ticket comment list |
<ticket> |
List ticket comments (all pages, flat list). |
ticket comment add |
<ticket>, --body (required) |
Add a comment (markdown). |
ticket label list |
List project labels (all pages, flat list). | |
ticket label create |
--name (required), --color |
Create a project label, for example --color "#ff0000". |
ticket ac list |
<ticket> |
List acceptance criteria (all pages, flat list). |
ticket ac add |
<ticket> <description> |
Add an acceptance criterion. |
ticket ac update |
<ticket> <criterion_id>, --description, --done/--not-done |
Change the description or mark a criterion as done or not done. |
ticket ac delete |
<ticket> <criterion_id> |
Delete an acceptance criterion. |
Notes:
- Dates use the
YYYY-MM-DDformat. Ticket statuses arebacklog,todo,in_progress,in_review,done. The server rejects an unknown status or priority inticket create,ticket updateandticket bulk-update(exit code 1), but silently ignores it in the--statusand--priorityfilters ofticket listandticket search: the filter is not applied and the command succeeds, so check the spelling. - Identifiers in the URL path (ticket, sprint, page, criterion, project slug) are URL-encoded. A bare
.or..(or an empty value) is refused with exit code 2 before any request is sent. --description -and--body -read the text from stdin.- In
ticket updateandticket bulk-update, an empty string for--sprint,--assigneeor--dueclears the value.
monolynx --project my-project ticket create --title "Fix login redirect" --priority high --sp 2 --ac "Redirect keeps the next parameter"
monolynx --project my-project ticket update MP-11 --status in_progress
git log -1 --format=%B | monolynx --project my-project ticket comment add MP-11 --body -
sprint
| Command | Arguments and options | Description |
|---|---|---|
sprint list |
--status |
List all project sprints (all pages, flat list), optionally filtered by status (for example planning, active, completed). |
sprint get |
<sprint_id> |
Show sprint details. |
sprint create |
--name (required), --start (required), --end, --goal |
Create a sprint. Dates use YYYY-MM-DD. |
sprint update |
<sprint_id>, --name, --goal, --start, --end |
Change the name, goal or dates of a sprint. |
sprint start |
<sprint_id> |
Start a sprint (only one sprint can be active at a time). |
sprint complete |
<sprint_id> |
Complete a sprint; unfinished tickets go back to the backlog. |
sprint board |
Show the Kanban board of the active sprint. | |
sprint burndown |
[sprint_id] |
Show the burndown of a sprint (the active one by default). |
wiki
| Command | Arguments and options | Description |
|---|---|---|
wiki list |
--tree |
List all wiki pages of the project; --tree indents titles by depth. |
wiki get |
<page_id>, --raw |
Show a page with its content; --raw prints only the markdown. |
wiki create |
--title (required), --content, --file, --parent, --position, --public/--no-public |
Create a page. Content comes from --content, --file or stdin (--content -). |
wiki update |
<page_id>, --title, --content, --file, --position, --public/--no-public |
Update a page; only the given fields are sent. |
wiki edit |
<page_id> |
Edit the page content in $EDITOR (vi by default); saves only when the content changed. |
wiki delete |
<page_id>, --yes |
Delete a page together with all its subpages. This cannot be undone. |
wiki search |
<query>, --limit (default 10) |
Semantic search over wiki pages. |
wiki config get |
Show the LLM Wiki method configuration of the project. | |
wiki config set |
--enabled/--disabled |
Turn the LLM Wiki method on or off (requires the settings:write permission). |
--public publishes the page at /blog/{slug}, visible to anyone without signing in. wiki delete has no -y short form. --content - with an empty standard input, an unreadable or non-UTF-8 --file, and a missing project are usage errors (exit code 2, no request sent).
Reserved groups
monitoring, issues, time, plan, rozliczenia, graph, pipeline, heartbeat and role appear in monolynx --help but are reserved: they have no commands yet (not yet available).
Confirmations
project delete, member remove, ticket delete and wiki delete ask for confirmation in a terminal. Outside a terminal they refuse to run without --yes (exit code 2). Declining the prompt ends with exit code 1.
Configuration and profiles
The CLI keeps its settings in config.toml inside the per-user config directory reported by platformdirs for the application name monolynx:
| System | Path |
|---|---|
| Linux | ~/.config/monolynx/config.toml |
| macOS | ~/Library/Application Support/monolynx/config.toml |
| Windows | the per-user config directory reported by platformdirs |
The file is written atomically with permissions 0600 (the directory gets 0700; not applied on Windows). auth login creates it for you. Example with two profiles:
[general]
active_profile = "prod"
[profile.prod]
endpoint = "https://monolynx.com"
project = "my-project"
auth_type = "oauth"
access_token = "..."
refresh_token = "..."
expires_at = "2026-10-29T12:00:00+00:00"
client_id = "..."
[profile.staging]
endpoint = "https://staging.monolynx.example.com"
project = "my-project"
auth_type = "token"
token = "osk_..."
Profile fields: endpoint, project, auth_type (token or oauth), token, access_token, refresh_token, expires_at, client_id. config get and config list always mask token, access_token and refresh_token.
Switch profiles:
monolynx --profile staging ticket list
MONOLYNX_PROFILE=staging monolynx ticket list
monolynx config set general.active_profile staging
The profile is chosen in this order: --profile, then MONOLYNX_PROFILE, then general.active_profile, then default.
Only auth login has an --endpoint option. For other commands, set the endpoint in the profile or through MONOLYNX_ENDPOINT:
monolynx config set profile.staging.endpoint https://staging.monolynx.example.com
Environment variables
| Name | Meaning | Default |
|---|---|---|
MONOLYNX_ENDPOINT |
API address of the Monolynx server. | https://monolynx.com |
MONOLYNX_TOKEN |
API token used instead of the tokens stored in the profile. | none |
MONOLYNX_PROJECT |
Project slug. | none |
MONOLYNX_PROFILE |
Configuration profile. | general.active_profile, otherwise default |
NO_COLOR |
Any non-empty value disables table colors, like --no-color. |
unset |
Resolution order for every setting: command-line option, then environment variable, then config file, then default. The options are --profile and --project (global), and --endpoint and --token (only in auth login).
MONOLYNX_TOKEN takes precedence over the tokens stored in the profile and is never refreshed. Use it in CI together with MONOLYNX_ENDPOINT and MONOLYNX_PROJECT, without a config file.
Exit codes
| Code | Meaning | Example causes |
|---|---|---|
0 |
Success | |
1 |
API or local error | 4xx other than 401/403 (for example 404 or 422), 429 or 5xx after all retries; corrupted config file; declined confirmation; config get for a key without a value |
2 |
Usage error | Unknown option or bad argument; no project resolved; destructive command without --yes outside a terminal; --timeout not greater than zero; invalid config key; update without any field to change; empty stdin for --content -; a bare . or .. as an identifier in a URL path |
3 |
Authentication error | 401 or 403; failed token refresh; no token stored; OAuth login timeout, denied consent or mismatched state |
4 |
Network error | Timeout, connection refused, DNS failure |
Errors are printed on stderr as Błąd: <status> <title>: <detail>. --quiet does not silence them.
Retries and timeouts:
GETandDELETEare retried on 429 and 5xx;POSTandPATCHonly on 429, because retrying a 5xx could create a duplicate.- At most 4 attempts, with backoff of 0.5 s, 1 s and 2 s. On 429 a
Retry-Aftervalue in seconds takes precedence, capped at 60 s. - Network errors are not retried.
--timeoutsets the timeout of a single request (30 s by default).--debugprints each request (method, URL, headers) and response (status, body cut to 500 characters) on stderr, with the token masked.
Piping and scripting
Without -o, the output format is table when stdout is a terminal and json otherwise, so piping into jq works without -o json. Global options such as -o go before the command group.
ticket list and ticket search return one page as a pagination envelope (use --page for the next pages):
{
"items": [{"key": "MP-12", "title": "Export the monthly report"}],
"page": 1,
"per_page": 20,
"total": 1,
"total_pages": 1
}
Read the rows through .items[] (the example above is shortened; each item has all ticket fields):
monolynx -o json --project my-project ticket list | jq -r '.items[] | .key'
monolynx -o json --project my-project ticket list --page 2 | jq '.total_pages'
project list, member list, wiki list, sprint list, ticket comment list, ticket label list and ticket ac list fetch all pages themselves and return a flat list, so there is no .items:
monolynx -o json project list | jq -r '.[].slug'
monolynx -o json --project my-project sprint list --status active | jq -r '.[].name'
monolynx -o json --project my-project ticket comment list MP-11 | jq -r '.[].content'
Status messages such as Zalogowano jako ..., Wylogowano z profilu ... and Ustawiono ... (auth login, auth logout, config set) go to stderr and --quiet silences them, so stdout stays empty for these commands.
In table and csv formats the page footer (Strona X/Y, razem: Z) goes to stderr, so stdout holds data only.
A script that reacts to exit codes. It captures the CLI output first and pipes it to jq only afterwards, because $? after a pipeline holds the exit code of the last command (jq), not of monolynx:
#!/usr/bin/env bash
set -u
json=$(monolynx -o json --project my-project ticket list --status todo)
status=$?
case $status in
0) printf '%s\n' "$json" | jq -r '.items[] | .key' ;;
3) echo "Not signed in or token expired: run 'monolynx auth login'." >&2; exit 3 ;;
4) echo "Monolynx is unreachable, try again later." >&2; exit 4 ;;
*) echo "monolynx failed with exit code $status." >&2; exit "$status" ;;
esac
The mnx alias
The package installs two equivalent commands, monolynx and mnx. Every command works with either:
mnx ticket list
mnx -o json project list
Shell completion
monolynx completion <shell> prints a completion script for bash, zsh or fish on stdout. It needs no sign-in and no configuration. An unknown shell ends with exit code 2.
The script is bound to the name the program was invoked as, so generate it separately for each command you want completed. monolynx completion zsh prints a script for monolynx, mnx completion zsh a script for mnx. Any other invocation name (for example python -m monolynx_cli) gets the script for monolynx.
Load the script into the current session (add the line to your shell startup file to make it permanent):
source <(monolynx completion bash)
autoload -Uz compinit && compinit
source <(monolynx completion zsh)
monolynx completion fish | source
Or save it to the place your shell reads completions from. The zsh script starts with #compdef, so it works as a file in a directory on $fpath (the file must be named _monolynx):
# bash
mkdir -p ~/.local/share/bash-completion/completions
monolynx completion bash > ~/.local/share/bash-completion/completions/monolynx
# zsh: add "fpath+=~/.zfunc; autoload -Uz compinit; compinit" to ~/.zshrc, before compinit runs
mkdir -p ~/.zfunc
monolynx completion zsh > ~/.zfunc/_monolynx
# fish
mkdir -p ~/.config/fish/completions
monolynx completion fish > ~/.config/fish/completions/monolynx.fish
For the mnx alias, do the same with mnx completion <shell> and save the result under the name mnx (_mnx for zsh, mnx.fish for fish):
mnx completion fish > ~/.config/fish/completions/mnx.fish
Alternatively, let the CLI install completion for your current shell with monolynx --install-completion, or print the script with monolynx --show-completion (to copy it or customize the installation). Both detect the shell automatically; --install-completion writes the script for monolynx only, so run mnx --install-completion for the alias. Open a new shell session afterwards.
Documentation and issues
- Documentation: https://gitlab.com/piotrkrych/monolynx/-/blob/main/cli/README.md
- Issues: https://gitlab.com/piotrkrych/monolynx/-/issues
- Source and homepage: https://gitlab.com/piotrkrych/monolynx
License
MIT. See the LICENSE file distributed with the package.
For command authors
Commands never print result data with print(), typer.echo() or rich.print(). A command builds a structure (list[dict] for records, dict for a single record or a pagination envelope with an items key) and hands it over as its last step:
from monolynx_cli.output import emit
emit(ctx, data)
emit(ctx, data) reads the global options (monolynx_cli.options.GlobalOptions) and calls render(data, fmt, *, no_color, quiet), the only function that writes result data to stdout, in table, json, yaml or csv. Progress messages (not data, not errors) go through echo_stderr(msg, *, quiet=False, no_color=False), which respects --quiet. Error messages go to stderr with typer.echo(..., err=True) and are never silenced.
HTTP calls go through monolynx_cli.client.MonolynxClient, never through httpx directly. The client adds the Authorization: Bearer, User-Agent: monolynx-cli/<version> and Accept: application/json headers, applies the retry policy and returns parsed JSON (None for 204). Commands do not catch client exceptions: a MonolynxError goes up to the global handler in monolynx_cli.main, which prints it and exits with the code from Exit codes.
opts = get_options(ctx)
with MonolynxClient(settings.endpoint, settings.bearer, timeout=opts.timeout, debug=opts.debug) as client:
emit(ctx, client.get("/api/v2/projects"))
Development install and tests, from the repository root:
pip install -e "cli/[test]"
pytest cli/tests
Metadata
Release files for monolynx-cli 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| monolynx_cli-0.1.0.tar.gz | 119.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| monolynx_cli-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 171.4 kB
Release files / monolynx_cli-0.1.0.tar.gz
| Download URL | monolynx_cli-0.1.0.tar.gz |
|---|---|
| Size | 119.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
27053bb368489db608e4846843570cff60cb3af3dfa2a7c952a301532f118455
|
|
BLAKE2b-256 checksum How to use checksums |
c09e59fa94b7342738441229b5422948de352951916d6a3a031a27b1916df309
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|
Release files / monolynx_cli-0.1.0-py3-none-any.whl
| Download URL | monolynx_cli-0.1.0-py3-none-any.whl |
|---|---|
| Size | 51.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
526178d5d12d7b21c95dce44c390d2b2c2cee3f1d5220597c00f353f6db05020
|
|
BLAKE2b-256 checksum How to use checksums |
4c6a5cf7c2c8ce50760dc7de1c2a22c94d1df7dcb01b46773b277872509570f4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|