Skip to main content

maia

The M.AI.A board from a terminal, for people and for the coding agents they run there.

It talks to the same public HTTP API the web app uses, so it inherits the server's rules rather than restating them: any active project member can move, edit, assign or reassign any ticket, and observers are read-only.

Install

uv tool install maiactl      # from PyPI (the package is maiactl; the command is maia)
maia login                   # opens your browser, then asks which workspace/project
maia                         # where am I, what next
maia status --full           # everything: version vs PyPI, accounts, workspaces, projects
maia doctor                  # if anything feels off
maia upgrade                 # newest release, via whatever installed you (uv / pipx / pip)
uv tool upgrade maiactl      # the standard path works too

Bare maia is a status card (offline): who you are, which workspace and project, and what to try. maia doctor checks version, server, token, workspace and project, and says how to fix each. The server check probes the API itself (an unauthenticated /api/v1/auth/me must answer JSON), not /health, which the web host answers on the backend's behalf.

Works on macOS (Apple Silicon and Intel), Linux and Windows — it's a pure-Python package. On Windows the config lives in %APPDATA%\maia\config.json, colour is enabled in the legacy console automatically, and output never fails on a character your code page can't show.

login runs the same brokered PKCE flow the desktop app uses: it opens Google in your real browser (always showing the account chooser, so a profile's current session is never reused silently) and polls until the backend releases a token, then finishes setting you up: if you're in several workspaces it asks which, and if that workspace has several projects it asks which of those. One of each is picked for you without a question. In a script or an agent shell (no TTY) there's no prompt; pass --tenant and then maia use <code>. The token is written to ~/.config/maia/config.json with mode 0600.

Several accounts at once

Like gh, you can be signed into more than one account and switch between them. An account is (email, server), so the same person on prod and on a local backend are two accounts — which is the point.

maia login                       # adds an account; never evicts an existing one
maia auth list                   # all of them, active one marked with *
maia auth switch priya           # by email, or any unique fragment
maia auth logout --account priya # sign out of just that one
maia auth logout --all

Each account remembers its own workspace and project, so switching restores where you were. For a single command, -a (--as) acts as another account without switching, and nothing that command does is saved:

maia -a priya@cydratech.com ls --mine
maia ls --mine -a priya          # flags may come before or after the command

-a can't be combined with login, logout or auth switch; those manage saved accounts, so name the account directly (logout --account priya).

Workspaces

maia workspaces              # the ones this account belongs to
maia workspace "Cydra Tech"  # switch

Switching workspace clears the selected project, because a project belongs to exactly one workspace — keeping it would point at something the account can no longer see. Pick a new one with maia projects and maia use.

It is a normal app session token, not a scoped API key, so it carries your full access and expires on the server's schedule. Treat the file as a credential. maia logout removes it.

For CI or a throwaway shell, skip the file entirely:

export MAIA_TOKEN=...        MAIA_TENANT_ID=...
export MAIA_PROJECT=MVP      MAIA_API_URL=https://maia.cydratech.com

Anything set this way applies to the current run only and is never written to disk: a CI job can't persist its credentials, and MAIA_PROJECT=X maia use Y won't change your saved project. Commands that would normally save say (not saved: …) on stderr. MAIA_ACCOUNT=priya selects a saved account for one run; a name that matches nothing is an error, not a silent fallback. With MAIA_TOKEN set, logout and auth switch refuse, since there is no saved session in play.

Reading

maia ls                       # active tickets, doing first (alias: maia tickets)
maia status                   # same as bare `maia`
maia ls --mine --status doing
maia ls --stage "In QA"
maia ls -s payment            # title/description search
maia show MVP-42              # detail + comments
maia show MVP-42 --history
maia history MVP-42           # the ticket's story (alias: maia log)
maia board                    # stages and card counts
maia members                  # who's on it, and their roles
maia stories
maia files MVP-42 --download ./tmp
maia media                    # the project's shared media (chat + tickets), by handle
maia media -s "invoice"       # search Maia's descriptions and filenames
maia media --download image-42 --to ./tmp

Every photo, video or PDF shared anywhere in the project has a handle like image-42, the same one you see in chat. maia media lists them with Maia's one-line description of each.

Tickets are addressed by key (MVP-42), bare number (42), or a title fragment. A fragment matching more than one ticket is an error, never a guess.

maia history shows who has had the ticket (the chain of custody, with how and when it changed hands) and a timeline of everything that happened — created, moved between stages, renamed, handed off, blocked/unblocked, filed under a story, commented — each with who did it and from which client. --json gives the same as {custody, timeline}.

Writing

maia new "Payment webhook retries" -d "Stripe retries land as duplicates." \
  --assign priya --stage "In Progress" --story "Billing"

git log -1 --format=%B | maia new "Ship the retry fix" -d -

maia mv MVP-42 doing          # a status…
maia mv MVP-42 "In QA"        # …or a stage by name
maia assign MVP-42 priya
maia story MVP-42 "Billing"   # file under an existing story
maia comment MVP-42 "Deployed to staging." --mention priya
maia comment MVP-42 - < notes.md
maia attach MVP-42 screenshot.png trace.pdf
maia attach MVP-42 --media image-42      # put EXISTING project media on the ticket
maia new "Webhook fix" -d "see the screenshot" --media image-42
maia drop MVP-42 --reason "superseded by MVP-51"   # project admins only

--media <handle> works on new, attach, comment and edit. A screenshot someone dropped in chat becomes the ticket's screenshot with no download and re-upload. Media that's already on another ticket isn't moved: the new ticket gets its own copy (its own bytes, a few seconds later), so the same image can be on any number of tickets and nothing done to the original later can reach into a ticket.

Every command takes --json for programmatic use, and -p CODE to act on a project other than the selected one for that command. Both may come before or after the subcommand. Progress notes ("uploaded x.png") go to stderr, so --json stdout is always a single parseable document.

What it deliberately doesn't do

  • No stage (column) create, rename or delete. Board structure is admin-curated in the app.
  • No story create, edit or delete. Same reason. You can file a ticket into an existing story with maia story.
  • No ticket delete. The API has none. maia drop sets the reversible dropped status, which is what "scrap that" means on this board; maia mv <key> next puts it back. Dropping is project-admin only from the CLI (the app lets any member), and maia mv <key> dropped is held to the same rule.

For agents

maia agent-guide                     # a cheat-sheet written for an LLM
maia agent-guide --write CLAUDE.md   # drop it into the repo (idempotent; re-run to refresh)

The guide tells the agent to use --json, never to run login itself, how tickets are addressed, the exit codes, and which rules the CLI enforces. With --json on, errors are JSON on stderr too ({"error", "hint", "exit_code"}), so failures parse as cleanly as successes.

An agent on your machine shares your saved login. For a CI job or a shell on another box, hand it your identity for one run:

eval "$(maia auth env)"        # exports MAIA_API_URL, MAIA_TOKEN, MAIA_TENANT_ID, MAIA_PROJECT
MAIA_TOKEN=$(maia auth token)  # or just the token
Invoke-Expression (maia auth env | Out-String)   # Windows; --shell cmd for cmd.exe

Exit codes

code meaning
0 fine
1 generic failure
2 not authenticated, or nothing selected
3 forbidden (e.g. you're an observer)
4 not found (a ticket, member, story, stage, project or workspace)
5 conflict; refetch and retry

maia doctor exits 1 when any check fails, so a script can gate on it; maia upgrade --check exits 1 when a newer release exists.

Metadata

Release files for maiactl 0.6.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for maiactl 0.6.2
File Size Uploaded
maiactl-0.6.2.tar.gz 94.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for maiactl 0.6.2
File Interpreter ABI Platform
maiactl-0.6.2-py3-none-any.whl Python 3 none any Details

Total release size: 147.8 kB

Release files / maiactl-0.6.2.tar.gz

Download URL maiactl-0.6.2.tar.gz
Size 94.3 kB
Tags Source
SHA-256 checksum
How to use checksums
8cdd8d51022836f206e48bd372494c3731e068cbe85e22d23cfc42b0512f381d
BLAKE2b-256 checksum
How to use checksums
9d21c2f6623c9101d25d09c58a4ab00aff123c96a2b6f44a69f7c527b1b60a1e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.5

Release files / maiactl-0.6.2-py3-none-any.whl

Download URL maiactl-0.6.2-py3-none-any.whl
Size 53.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
eec477d991e9d4d47837b038481cdba3e84d5bac1f393bb6a6503606a8d9baf0
BLAKE2b-256 checksum
How to use checksums
7111b7cbda2543e5f7d7627230434d9f198f73a26cc6ea26e45c1f05fbef7be1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.5

Release history Release notifications | RSS feed

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

This release

0.6.2 This release

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page