almirant
v1.5.4
Published
Almirant CLI — install, operate, and connect AI agents to your Almirant instance.
Maintainers
Readme
Almirant is an AI-native project management platform. Define your work in boards, sprints, and milestones — then let AI agents (Claude Code, Cursor, Windsurf, etc.) pick up tasks, implement them, and move them through your pipeline.
This CLI connects your repository to your Almirant project so your AI agent can access tasks, boards and sprints via MCP, and installs / operates self-hosted Almirant instances.
Install
npm i -g almirantThe npm package is a thin Node shim that spawns a single Go binary shipped
as the optional @almirant/cli-<os>-<arch> dependency for your platform.
Supported: macOS arm64/amd64, Linux arm64/amd64. For Windows or any
architecture not in that list, build from source:
go install github.com/fjpedrosa/almirant-cli@latestQuick start
# 1. Authenticate (opens browser)
almirant login
# 2. Set up your project (from your repo root)
almirant initThat's it. init generates local MCP config and syncs the bundled skill and specialist-agent templates so your AI agent can start working on tasks from your Almirant board.
If you use more than one Almirant instance, give each account a label and pick the active one explicitly:
almirant accounts list
almirant accounts rename 2 local-m1pro
almirant use local-m1pro
almirant currentCommands
Auth & project wiring
almirant login
Authenticate via browser OAuth. Credentials are stored in ~/.almirant/config.json (mode 0600). On first use you'll be prompted for the API URL — press Enter to accept the SaaS default https://api.almirant.ai, or type your self-hosted URL. You can also set ALMIRANT_API_URL or pass --api-url <url> to skip the prompt.
Supports multiple accounts — run login again to add another. Each account gets a stable ID and a human label so the same email can be used safely across several Almirant instances.
Credentials stay in ~/.almirant/config.json; generated project files should
not contain bearer tokens.
almirant init
Interactive setup wizard:
- Detects project type (Next.js, Bun, Node, React, Go, Python, Rust, etc.)
- Detects git remote (shown for GitHub integration setup)
- Select or create account — choose from stored accounts or add a new one
- Select or create project — pick an existing Almirant project or create one on the spot
- Generates agent MCP configs — Claude Code
.mcp.json, Codex.codex/config.toml, and OpenCode.opencode/opencode.json, all launchingalmirant mcp proxylocally without writing API keys into the repo - Ensures local config ignores — adds
.mcp.json,.codex/,.opencode/opencode.json,.opencode/opencode.jsonc, legacyopencode.json, legacyopencode.jsonc, and.claude/settings.local.jsonto.gitignorewhen missing - Syncs skill and agent templates — installs/updates Claude-specific skills in
.claude/skills/, the broader agent-compatible skills fromalmirant-communityin.agents/skills/and.opencode/skills/, plus bundled specialist agents in.claude/agents/,.agents/agents/, and.opencode/agents/. Existing bundled entries are overwritten so linked projects receive template updates when you re-runinitorlink.
almirant link
Quick variant of init that uses stored credentials (no OAuth prompt). Useful for linking additional repos to an existing account.
Config
The almirant config family of commands lets you inspect and manage stored credentials without touching ~/.almirant/config.json by hand. The CLI supports multiple accounts (e.g., SaaS workspace + self-hosted instance). The active account is tracked by a stable account ID, not just email, because the same email can exist in multiple instances. Use almirant use, almirant accounts rename, or almirant accounts add for the common account workflows.
almirant config
Launches an interactive bubbletea TUI in a terminal with a menu covering all config operations. On non-TTY (piped input, CI), prints command help instead.
almirant config show
Prints the active configuration: accounts, API URLs, and key state. API keys are never shown in plaintext — the display shows the key prefix followed by ***, or a re-login hint if no key is stored.
Example:
Default account: local-m1pro ([email protected])
[*] local-m1pro
ID: acc_abc123...
Email: [email protected]
API URL: https://macbook-m1-pro.tailnet.ts.net/api
API key: alm_***
[ ] prod-saas
ID: acc_def456...
Email: [email protected]
API URL: https://api.almirant.ai
API key: alm_***almirant accounts list|add|remove|rename|set-default
Manage the list of stored accounts. The same commands are also available under almirant config accounts ... for backwards compatibility.
list— print all accounts with marker, index, label, email, API URL, and key state.add— alias oflogin; adds a new account (same flags:--api-url,--app-url,--key-name).rename <ref> <label>— set a human label such aslocal-m1pro,prod-saas, orkroko-dev.remove <ref>— remove an account after a y/N prompt;--yesskips the prompt.set-default <ref>— set the default account used by commands that need authentication.
<ref> can be a label, stable ID, unique email, or 1-based list index.
Prefer:
- labels for humans:
almirant use local-m1pro - stable IDs for generated project config
- indexes for quick interactive cleanup
- emails only when they are unique across all configured instances
almirant use [label|id|email|index]
Select the active Almirant account. With no argument, opens an interactive selector. With an argument, accepts an account label, stable ID, unique email, or 1-based index.
almirant current
Prints the active account without exposing the plaintext API key.
Example:
Active account:
label: local-m1pro
id: acc_abc123...
email: [email protected]
api: https://macbook-m1-pro.tailnet.ts.net/api
key: alm_***almirant mcp proxy --project-id <id> [--account <ref>]
Runs a stdio MCP proxy for AI agents.
This is the key to the new secretless setup:
- the AI agent starts
almirant mcp proxy; - the CLI reads the selected account from
~/.almirant/config.json; - the CLI forwards MCP traffic to
<apiBaseUrl>/mcp?projectId=<id>; - the bearer token is attached in memory only.
No token is written to .mcp.json, .codex/config.toml, .opencode/opencode.json, shell rc files, or other project-local files.
When --account is present, that project is pinned to a specific account ID or
label. When --account is omitted, the proxy follows the current active account
selected by almirant use.
almirant config set api-url <url> [--account <ref>]
Overwrites the backend URL for an account. Only http/https URLs with a non-empty host are accepted; trailing slashes are stripped. Omit --account to target the default account.
When the account's frontend URL was derived from the previous backend URL, the CLI updates it to match the new backend URL as well. Explicit custom frontend URLs are preserved.
almirant config rotate api-key [--account <ref>]
Rotates the API key server-side atomically. On success, prints the new key prefix. If the key rotates successfully on the server but the local config cannot be saved (e.g., disk full), the new plaintext key is printed once to stderr with recovery instructions and the command exits with code 2 — do not lose this output.
almirant config reset [--yes]
Deletes ~/.almirant/config.json after a y/N confirmation. --yes skips the prompt. Use this to start fresh; you will need to run almirant login again afterward.
Self-hosted stack operations
Almirant is source-available and you can run your own instance. These commands wrap the shell scripts shipped in fjpedrosa/almirant-community.
almirant install
Clones the Almirant source repo into ~/.almirant/stack (override with --dir) and runs scripts/install.sh to build and start the Docker stack.
Run it without flags on a terminal to get a guided install wizard:
almirant installThe wizard asks where to install the stack, how users will reach the instance (public VPS, external proxy, LAN-only, localhost-only, or local Caddy), the domain/public URL, then detects RAM/CPU/disk and recommends a capacity profile before asking whether to enable the Discord bridge. The final summary shows the selected networking and capacity settings before starting.
Flags for automation or advanced installs:
--repo <owner/name|url>— source to clone (defaultfjpedrosa/almirant-community).owner/nameexpands tohttps://github.com/owner/name.git; full HTTPS or SSH URLs are accepted for private forks.--branch <name>— git branch/tag to check out (defaultmain).--domain <domain>— public domain for the instance; deriveshttps://<domain>and enables the built-in public Caddy proxy.--proxy <caddy|external|none|local>— choose how traffic reaches the stack.caddymanages 80/443 in Docker,externalexpects Traefik/Nginx/Caddy/Cloudflare outside the stack,noneis local-only, andlocalkeeps the legacy localhost Caddy profile.--bind-address <address>— direct host bind address for non-public-proxy modes. Keep127.0.0.1for host-only access; use0.0.0.0or a LAN IP for LAN-only installs.--public-url <url>— public URL where the instance will be served.--runner-ram-budget <true|false>— enable RAM-aware runner scheduling.--runner-ram-reserved-mb <mb>— RAM kept free for the OS, Docker, database, frontend/backend and upgrade builds.--max-concurrent <n>— runner slot cap; RAM budgeting adds a dynamic memory bound on top.--with-proxy,--with-discord— enable optional profiles.--with-proxyis kept for compatibility and maps to the legacy localhost Caddy profile; prefer--proxy caddyor--domain.--non-interactive— use defaults for every prompt ininstall.sh.--from-dir <path>— for air-gapped installs, skip git and use an existing clone.--resume— reuse the last saved wizard settings after cancelling or after a clone/install failure.
If the stack source repo is private and Git prompts for Password over HTTPS, enter a GitHub Personal Access Token, not your account password. GitHub no longer accepts account passwords for Git operations over HTTPS. Alternatively, use SSH:
almirant install --repo [email protected]:fjpedrosa/almirant-community.gitFor a normal public VPS install, use:
almirant install --domain almirant.example.comFor a 24 GB / 8 vCPU VPS where you want explicit upgrade/build headroom:
almirant install \
--domain almirant.example.com \
--runner-ram-budget true \
--runner-ram-reserved-mb 4096 \
--max-concurrent 3--runner-ram-reserved-mb is intentionally about more than steady-state agents: upgrades rebuild the frontend image, and the Next.js build can consume several GB while Docker, Postgres and Redis are also running.
This serves the app and API on the same origin: frontend at https://almirant.example.com, backend API at /api, MCP at /mcp, and WebSocket at /ws.
For a private LAN-only install:
almirant install \
--public-url http://192.168.1.50:8080 \
--bind-address 0.0.0.0 \
--proxy noneThat makes Almirant reachable from your private network, but it does not publish it to the Internet unless your router/firewall forwards the port.
almirant stack public-url set <url>
Updates an existing local stack's .env.production public URL, auth/CORS values, API path (/api), and proxy mode, then recreates frontend/backend because the public URL is baked into the frontend bundle. Pass --proxy caddy|external|none|local to choose the routing mode and --no-recreate to only edit .env.production.
almirant upgrade [service...]
Rebuilds + restarts the stack. Local by default (migrates known legacy Git origins to --repo, runs git pull, then reconciles .env.production against .env.production.example, aligns managed shim image variables with config/shim-images.json, builds missing shim tags through the shims Compose profile, then docker compose up -d --build --force-recreate on --dir). Pass --host <ssh> for the remote flow that delegates to scripts/update-remote.sh. Positional args are Docker Compose service names to scope the rebuild. Scoped upgrades include db-init automatically so database migrations and registered data backfills still run during the upgrade; when backend is recreated, Compose waits for db-init to finish successfully.
Env reconciliation. After the git pull, upgrade reads the schema in .env.production.example and adds any missing variables to .env.production using the recipes declared inline (auto-generate secrets, derive paths from the stack dir, copy from sibling vars, apply defaults). Existing values are never overwritten. A timestamped backup is written before any change. This means upgrades that introduce new required variables (e.g. UPDATER_INTERNAL_TOKEN) "just work" instead of failing on ${VAR:?…} interpolation.
Shim images. The runner shims are image-only Compose services. upgrade reads config/shim-images.json, updates previous local almirant-*-shim:* values in .env.production to the manifest tag, preserves custom image overrides, and builds only the shim tags missing from the local Docker cache.
Database maintenance. The production stack runs db-init on every upgrade. That service applies Drizzle migrations and then executes registered, ledgered data backfills exactly once per checksum. This is how historical data repairs ship safely with almirant upgrade and the in-app update banner.
--repo <owner/name>— stack source repo (defaultfjpedrosa/almirant-community). In local mode, legacy Almirant origins are migrated automatically; custom forks are kept unless you pass--repoexplicitly.--check-envreports what would be added without modifying anything (skips docker too).--no-env-syncskips the reconciliation entirely — only use this when you manage env via your own tooling.
almirant logs [service...], almirant ps, almirant down
Day-2 operations over the production compose file. logs -f tails; ps shows status; down stops the stack. down keeps volumes unless you pass --volumes (destructive — deletes your data).
Meta
almirant version
Print the installed version, commit SHA, build date, and Go runtime.
Multi-account support
The CLI supports multiple Almirant accounts (e.g., work SaaS + self-hosted). Each login adds an account with a stable ID and generated label. Rename labels to match how you think about the instance:
almirant accounts list
almirant accounts rename 2 local-m1pro
almirant use local-m1pro
almirant currentAccount references accept labels, stable IDs, unique emails, or 1-based indexes. Prefer labels for humans and IDs for generated project config.
Account labels
Labels are local aliases. They are for you, not for the backend. Good labels describe the instance or purpose:
almirant accounts rename 1 prod-saas
almirant accounts rename 2 local-m1pro
almirant accounts rename 3 kroko-devThe CLI normalizes labels to lowercase slug-style values (local m1pro becomes
local-m1pro). Labels must be unique.
Active account vs pinned project account
There are two valid modes:
- Pinned account — generated by
almirant init/almirant link. The project config includes--account <account-id>, so the repo always talks to the same Almirant instance even if you later runalmirant useelsewhere. - Active account — manual/advanced mode. Omit
--accountfrom the MCP proxy args and the repo follows whatever account is active in the shell viaalmirant use.
Default generated config uses the pinned account mode because it is safer: opening an old repo should not accidentally write memory, tasks, or comments to the wrong Almirant instance.
What gets generated
Claude Code .mcp.json
{
"mcpServers": {
"almirant": {
"type": "stdio",
"command": "almirant",
"args": ["mcp", "proxy", "--project-id", "<your-project-id>", "--account", "<account-id>"]
}
}
}The project config does not contain API keys. almirant mcp proxy reads the selected account from ~/.almirant/config.json and forwards MCP traffic to <apiBaseUrl>/mcp?projectId=... with the bearer token in memory. Existing entries in your .mcp.json (other MCP servers, top-level fields) are preserved on merge.
Codex .codex/config.toml
almirant init and almirant link create or update Codex project config with the same stdio proxy pattern. Existing tool approval sections are preserved:
[mcp_servers.almirant]
command = "almirant"
args = ["mcp", "proxy", "--project-id", "<your-project-id>", "--account", "<account-id-or-label>"]Do not put bearer tokens in .codex/config.toml. If you want to follow the
active account instead of pinning the repo, omit the --account pair:
[mcp_servers.almirant]
command = "almirant"
args = ["mcp", "proxy", "--project-id", "<your-project-id>"]OpenCode .opencode/opencode.json
almirant init and almirant link also create or update .opencode/opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"almirant": {
"type": "local",
"command": ["almirant", "mcp", "proxy", "--project-id", "<your-project-id>", "--account", "<account-id>"],
"enabled": true
}
},
"permission": "allow",
"agent": {
"build": {
"permission": {
"edit": "allow",
"bash": "allow"
}
}
}
}Existing OpenCode config and unrelated MCP servers are preserved. If an older root-level opencode.json exists and .opencode/opencode.json does not, it is used as the migration source. Old remote Almirant entries with headers.Authorization are replaced by the local proxy entry.
.gitignore
Because generated configs pin a local account ID and may replace older token-based files, init and link ensure these entries exist in .gitignore:
.mcp.json
.codex/
.opencode/opencode.json
.opencode/opencode.jsonc
opencode.json
opencode.jsonc
.claude/settings.local.jsonMigrating from old token-based MCP config
Older generated configs looked like this:
{
"mcpServers": {
"almirant": {
"type": "http",
"url": "https://api.almirant.ai/mcp?projectId=...",
"headers": {
"Authorization": "Bearer ..."
}
}
}
}Replace that entry by re-running:
almirant linkor manually change the server to the stdio proxy shown above. If a real bearer token was ever committed, rotate that API key from Almirant settings or with:
almirant config rotate api-key --account <ref>.claude/, .agents/, and .opencode/ templates
Skill and agent templates teach your AI tools how to work with tasks from your Almirant board. Claude receives the six Claude-specific skills from almirant-community: pr, ideate, fix, document, implement, refine. Agent-compatible targets receive the broader .agents/skills bundle from almirant-community, including create-tasks, review, validate, runner, feedback, Discord, and memory workflows.
almirant init and almirant link create and overwrite bundled entries in:
.claude/skills/and.claude/agents/for Claude Code..agents/skills/and.agents/agents/for Codex/OpenCode-compatible agent runners..opencode/skills/and.opencode/agents/for native OpenCode discovery.
Requirements
- npm install path: Node.js >= 18 for the shim. The binary itself has no runtime dependencies.
- install / upgrade / logs / ps / down: Docker + Docker Compose v2, git, bash.
- login: A browser for OAuth authentication.
Development
git clone https://github.com/fjpedrosa/almirant-cli
cd almirant-cli
go build ./... # builds the almirant-cli binary
go test ./... # runs the full test suite (nine packages)
go vet ./... # static analysisRelease is automated via .github/workflows/release.yml on v* tag pushes (GoReleaser + npm publishes).
Links
License
Business Source License 1.1 — see LICENSE.
