Command-line interface for PostgresAI monitoring and database management.
npm install -g postgresaiFor reproducible installs, pin the 0.15 release explicitly:
npm install -g postgresai@0.15.0Note: in this repository, cli/package.json uses a placeholder version (0.0.0-dev.0). The real published version is set by the git tag in CI when publishing to npm.
# Add the PostgresAI tap
brew tap postgres-ai/tap https://gitlab.com/postgres-ai/homebrew-tap.git
# Install postgresai
brew install postgresaiThe postgresai package provides two command aliases:
postgresai --help # Canonical, discoverable
pgai --help # Short and convenientYou can also run it without installing via npx:
npx postgresai --helpIf you want npx pgai ... as a shorthand for npx postgresai ..., install the separate pgai wrapper package:
npx pgai --helpThis command creates (or updates) the postgres_ai_mon user, creates the required view(s), and grants the permissions described in the root README.md (it is idempotent). Where supported, it also enables observability extensions described there.
Run without installing (positional connection string):
npx postgresai prepare-db postgresql://admin@host:5432/dbnameIt also accepts libpq "conninfo" syntax:
npx postgresai prepare-db "dbname=dbname host=host user=admin"And psql-like options:
npx postgresai prepare-db -h host -p 5432 -U admin -d dbnamePassword input options (in priority order):
--password <password>PGAI_MON_PASSWORDenvironment variable- if not provided: a strong password is generated automatically
By default, the generated password is printed only in interactive (TTY) mode. In non-interactive mode, you must either provide the password explicitly, or opt-in to printing it:
--print-password(dangerous in CI logs)
Optional permissions (RDS/self-managed extras from the root README.md) are enabled by default. To skip them:
npx postgresai prepare-db postgresql://admin@host:5432/dbname --skip-optional-permissionsTo see what SQL would be executed (passwords redacted by default):
npx postgresai prepare-db postgresql://admin@host:5432/dbname --print-sqlFor Supabase projects, you can use the Management API instead of direct PostgreSQL connections. This is useful when direct database access is restricted.
# Using environment variables
export SUPABASE_ACCESS_TOKEN='your_management_api_token'
export SUPABASE_PROJECT_REF='your_project_ref'
npx postgresai prepare-db --supabase
# Using command-line options
npx postgresai prepare-db --supabase \
--supabase-access-token 'your_token' \
--supabase-project-ref 'your_project_ref'
# Auto-detect project ref from a Supabase database URL
npx postgresai prepare-db postgresql://postgres:password@db.abc123.supabase.co:5432/postgres \
--supabase --supabase-access-token 'your_token'The Supabase access token can be created at https://supabase.com/dashboard/account/tokens.
Options:
--supabase- Enable Supabase Management API mode--supabase-access-token <token>- Supabase Management API access token (or useSUPABASE_ACCESS_TOKENenv var)--supabase-project-ref <ref>- Supabase project reference (or useSUPABASE_PROJECT_REFenv var)
Notes:
- The project reference can be auto-detected from Supabase database URLs
- All standard options work with Supabase mode (
--verify,--print-sql,--skip-optional-permissions, etc.) - When using
--verify, the tool checks if all required setup is in place
Verify that everything is configured as expected (no changes):
npx postgresai prepare-db postgresql://admin@host:5432/dbname --verifyReset monitoring user password only (no other changes):
npx postgresai prepare-db postgresql://admin@host:5432/dbname --reset-password --password 'new_password'Authenticate via browser to obtain API key:
postgresai authThis will:
- Open your browser for authentication
- Prompt you to select an organization
- Automatically save your API key to
~/.config/postgresai/config.json
Start monitoring with demo database:
postgresai mon local-install --demoStart monitoring with your own database:
postgresai mon local-install --db-url postgresql://user:pass@host:5432/dbComplete automated setup with API key and database:
postgresai mon local-install --api-key your_key --db-url postgresql://user:pass@host:5432/db -yThis will:
- Configure API key for automated report uploads (if provided)
- Add PostgreSQL instance to monitor (if provided)
- Generate secure Grafana and replication passwords
- Start all monitoring services
- Open Grafana at http://localhost:3000
# Complete setup with various options
postgresai mon local-install # Interactive setup for production
postgresai mon local-install --demo # Demo mode with sample database
postgresai mon local-install --api-key <key> # Setup with API key
postgresai mon local-install --db-url <url> # Setup with database URL
postgresai mon local-install --api-key <key> --db-url <url> # Complete automated setup
postgresai mon local-install -y # Auto-accept all defaults
# Service management
postgresai mon start # Start monitoring services
postgresai mon stop # Stop monitoring services
postgresai mon restart [service] # Restart all or specific monitoring service
postgresai mon status # Show monitoring services status
postgresai mon health [--wait <sec>] # Check monitoring services health--demo- Demo mode with sample database (testing only, cannot use with --api-key)--api-key <key>- Postgres AI API key for automated report uploads--db-url <url>- PostgreSQL connection URL to monitor (format:postgresql://user:pass@host:port/db)--instance-id <uuid>- Adopt a console-provisioned monitoring instance (also via thePGAI_INSTANCE_IDenv var)-y, --yes- Accept all defaults and skip interactive prompts
When --instance-id <uuid> (or PGAI_INSTANCE_ID) is set, local-install forwards the id to the platform, which adopts the already-provisioned monitoring instance instead of self-registering a duplicate under an auto-created postgres-ai-monitoring project. The CLI then persists the adopted instance's real project to .pgwatch-config, so checkup reports upload alongside the rest of that instance's health data. Adoption is awaited (with one automatic retry); if it fails, the CLI warns and reports fall back to the default project until you re-run local-install. Without the flag, the legacy self-registration path is byte-for-byte unchanged.
local-install writes .env in the monitoring directory. It preserves existing REPLICATOR_PASSWORD and VM_AUTH_* values or generates new random ones when missing; VM_AUTH_USERNAME defaults to vmauth when absent. The replication password is used by the demo PostgreSQL standby replication user, and the VM auth credentials are required before Docker Compose can provision Grafana datasources. If you run docker compose directly or maintain .env yourself, set both VM auth values before upgrading. For rotation, run VM_AUTH_PASSWORD="$(openssl rand -base64 18)" ./scripts/rotate-vm-auth.sh from the monitoring directory so .env, sink-prometheus, and grafana update together.
postgresai mon targets list # List databases to monitor
postgresai mon targets add <conn-string> <name> # Add database to monitor
postgresai mon targets remove <name> # Remove monitoring target
postgresai mon targets test <name> # Test target connectivitypostgresai mon config # Show monitoring configuration
postgresai mon update-config # Apply configuration changes
postgresai mon update # Update monitoring stack
postgresai mon reset [service] # Reset service data
postgresai mon clean # Cleanup artifacts
postgresai mon check # System readiness check
postgresai mon shell <service> # Open shell to monitoring servicepostgresai mcp start # Start MCP stdio server exposing toolsCursor configuration example (Settings → MCP):
{
"mcpServers": {
"PostgresAI": {
"command": "postgresai",
"args": ["mcp", "start"],
"env": {
"PGAI_API_BASE_URL": "https://postgres.ai/api/general/"
}
}
}
}Tools exposed:
list_issues: returns the same JSON aspostgresai issues list.view_issue: view a single issue with its comments (args:{ issue_id, debug? }).create_issue: create a new issue (args:{ title, description?, org_id, attachments?, debug? }).update_issue: update title/description/status/labels (args:{ issue_id, title?, description?, status?, labels?, attachments?, debug? }).post_issue_comment: post a comment (args:{ issue_id, content?, parent_comment_id?, attachments?, debug? }).update_issue_comment: update an existing comment (args:{ comment_id, content?, attachments?, debug? }).upload_file: upload a local file and return the storage URL plus a ready-to-paste markdown link (args:{ path, debug? }).download_file: download a file from storage (args:{ url, output_path?, debug? }).
create_issue, update_issue, post_issue_comment, and update_issue_comment accept an
optional attachments: string[] of local file paths. Each file is uploaded to PostgresAI
storage and the resulting markdown link is appended to the comment body or issue
description (image extensions — .png .jpg .jpeg .gif .webp .svg .bmp .ico — render
inline as ; everything else as [](url)).
For post_issue_comment and update_issue_comment, either content or attachments
must be non-empty (attachments alone are allowed). For update_issue with attachments
but no description, the existing description is fetched first and the new links are
appended to it.
The MCP server runs in your local user account with your PostgresAI API key. It treats the connected MCP client (the LLM agent) as trusted — the same way the CLI treats you when you type a command. In particular:
upload_fileand theattachments: string[]parameter on the issue/comment tools read any local file the CLI process can read, including secrets like~/.ssh/id_rsa,~/.aws/credentials, or~/.config/postgresai/config.json(which contains your own API key). The file's bytes are uploaded to PostgresAI storage and the resulting URL becomes visible to anyone with read access to the issue or comment it ends up in.download_filewrites to any path the CLI process can write to whenoutput_pathis supplied (~/.ssh/authorized_keys,~/.bashrc, etc. are all fair game). Whenoutput_pathis omitted, downloads are restricted to the current working directory.
This is fine when the agent and the upstream context the agent is reading are trusted. It is not safe to run this MCP server against an agent that is processing untrusted text (issue bodies, comments, web pages, third-party docs) without additional sandboxing — a prompt-injection in any input the agent reads could be used to exfiltrate local secrets or write arbitrary files. If you need to expose this MCP server to such an agent, run the agent (and this server) in a container or restricted user account that doesn't have access to anything sensitive.
postgresai issues list # List issues (shows: id, title, status, created_at)
postgresai issues view <issueId> # View issue details and comments
postgresai issues create --org-id <id> --title <t> # Create a new issue
postgresai issues update <issueId> [--title ... --status ...]# Update an existing issue
postgresai issues post-comment <issueId> <content> # Post a comment to an issue
postgresai issues update-comment <commentId> <content> # Update an existing comment
postgresai issues files upload <path> # Upload a file, print URL + markdown
postgresai issues files download <url> [-o <path>] # Download a file
# Common options:
# --parent <uuid> Parent comment ID (for replies on post-comment)
# --debug Enable debug output
# --json Output raw JSON (overrides default YAML)create, update, post-comment, and update-comment accept a repeatable
--attach <path> flag. Each file is uploaded to PostgresAI storage and a
markdown link is appended to the comment body (or issue description). Image
extensions — .png .jpg .jpeg .gif .webp .svg .bmp .ico — render inline as
; everything else as [](url). Multiple --attach flags preserve
order; each link goes on its own line.
# Attach a screenshot to a new comment
postgresai issues post-comment <issueId> "Saw this in prod" --attach screenshot.png
# Attach multiple files to a new issue
postgresai issues create --org-id 4 --title "Slow query" \
--description "Plan attached" --attach plan.txt --attach flame.svg
# Attach a file to an existing issue without changing the description.
# The current description is fetched and the link is appended to it.
postgresai issues update <issueId> --attach trace.logBy default, issues commands print human-friendly YAML when writing to a terminal. For scripting, you can:
- Use
--jsonto force JSON output:
postgresai issues list --json | jq '.[] | {id, title}'- Rely on auto-detection: when stdout is not a TTY (e.g., piped or redirected), output is JSON automatically:
postgresai issues view <issueId> > issue.jsonpostgresai mon generate-grafana-password # Generate new Grafana password
postgresai mon show-grafana-credentials # Show Grafana credentialspostgresai auth # Authenticate via browser (OAuth)
postgresai auth --set-key <key> # Store API key directly
postgresai show-key # Show stored key (masked)
postgresai remove-key # Remove stored keyThe CLI stores configuration in ~/.config/postgresai/config.json including:
- API key
- Base URL
- Organization ID
API key resolution order:
- Command line option (
--api-key) - Environment variable (
PGAI_API_KEY) - User config file (
~/.config/postgresai/config.json) - Legacy project config (
.pgwatch-config)
Base URL resolution order:
- API base URL (
apiBaseUrl):- Command line option (
--api-base-url) - Environment variable (
PGAI_API_BASE_URL) - User config file
baseUrl(~/.config/postgresai/config.json) - Default:
https://postgres.ai/api/general/
- Command line option (
- UI base URL (
uiBaseUrl):- Command line option (
--ui-base-url) - Environment variable (
PGAI_UI_BASE_URL) - Default:
https://console.postgres.ai
- Command line option (
Normalization:
- A single trailing
/is removed to ensure consistent path joining.
PGAI_API_KEY- API key for PostgresAI servicesPGAI_API_BASE_URL- API endpoint for backend RPC (default:https://postgres.ai/api/general/)PGAI_UI_BASE_URL- UI endpoint for browser routes (default:https://console.postgres.ai)
--api-base-url <url>- overridesPGAI_API_BASE_URL--ui-base-url <url>- overridesPGAI_UI_BASE_URL
For production (uses default URLs):
# Production auth - uses console.postgres.ai by default
postgresai auth --debugFor staging/development environments:
# Linux/macOS (bash/zsh)
export PGAI_API_BASE_URL=https://v2.postgres.ai/api/general/
export PGAI_UI_BASE_URL=https://console-dev.postgres.ai
postgresai auth --debug# Windows PowerShell
$env:PGAI_API_BASE_URL = "https://v2.postgres.ai/api/general/"
$env:PGAI_UI_BASE_URL = "https://console-dev.postgres.ai"
postgresai auth --debugVia CLI options (overrides env):
postgresai auth --debug \
--api-base-url https://v2.postgres.ai/api/general/ \
--ui-base-url https://console-dev.postgres.aiNotes:
- If
PGAI_UI_BASE_URLis not set, the default ishttps://console.postgres.ai.
The CLI uses Bun as the test runner with built-in coverage reporting.
# Run tests with coverage (default)
bun run test
# Run tests without coverage (faster iteration during development)
bun run test:fast
# Run tests with coverage and show report location
bun run test:coverageCoverage configuration is in bunfig.toml. Reports are generated in coverage/ directory:
coverage/lcov-report/index.html- HTML coverage reportcoverage/lcov.info- LCOV format for CI integration
- Node.js 18 or higher
- Docker and Docker Compose
- Documentation: https://postgres.ai/docs
- Issues: https://gitlab.com/postgres-ai/postgres_ai/-/issues