GitOps CLI for Port.io -- manage your developer portal configuration as versioned YAML in git.
portctl works like kubectl or terraform for your Port.io portal: pull live config to local YAML files, review changes with a diff, push updates back, and detect drift -- all from your terminal or CI pipeline.
- Pull / Push workflow -- export portal config (blueprints, scorecards, actions, pages) to YAML, edit locally, push back
- Dry-run diffs -- see exactly what will change before applying
- Drift detection -- audit live portal state against your last-applied snapshot
- Validation pipeline -- local schema checks plus optional remote API validation
- Rollback -- restore any previous configuration state
- Multi-org support -- manage multiple Port.io organizations from one config
- Secure credentials -- OS keychain first, env vars for CI, encrypted file fallback
- Rich terminal UI -- tables, trees, progress bars, syntax-highlighted YAML
# Install
pip install portctl
# or
uv tool install portctl
# Initialize a new project
portctl init
# Authenticate
portctl auth login
# Pull portal config to local YAML files
portctl pull
# Edit YAML files in your editor, then preview changes
portctl diff
# Push changes to Port.io
portctl push| Command | Description |
|---|---|
portctl init |
Initialize a new portctl project (interactive wizard) |
portctl auth login |
Authenticate with Port.io credentials |
portctl auth status |
Check authentication status |
portctl auth logout |
Clear stored credentials |
portctl org list |
List configured organizations |
portctl org add |
Add a new organization |
portctl org remove |
Remove an organization |
| Command | Description |
|---|---|
portctl pull |
Pull portal config from Port.io to local YAML |
portctl diff |
Show what would change (local vs remote) |
portctl diff <org1> <org2> |
Compare config between two orgs |
portctl push |
Push local YAML config to Port.io |
portctl validate |
Validate YAML syntax and schema |
portctl validate --remote |
Validate against the Port.io API |
portctl audit |
Detect configuration drift |
portctl rollback --to <event-id> |
Restore to a previous state |
| Command | Description |
|---|---|
portctl whoami |
Show current auth and org info |
portctl blueprint show <name> |
Interactive blueprint inspector |
portctl history |
View apply/export event log |
portctl seed |
Seed demo data for testing |
-V, --version Show version and exit
-v, --verbose Enable debug logging
--help Show help for any command
portctl manages four resource types as YAML files:
blueprints/ # Entity types (service, team, environment, ...)
scorecards/ # Quality rules and scoring levels
actions/ # Self-service actions and automations
pages/ # Portal UI pages and dashboards
Internal/system resources (prefixed with _ or $) are automatically excluded.
portctl stores its configuration in ~/.portctl/:
~/.portctl/
config.yaml # Organizations, default org, preferences
state.yaml # Last-applied snapshots per org per resource
credentials # Encrypted credentials (fallback)
# ~/.portctl/config.yaml
default_org: my-org
orgs:
my-org:
client_id: your-port-client-id
# client_secret resolved via keyring, env var, or credentials fileCredentials are resolved in this order:
- OS keychain (via
keyring) -- set byportctl auth login - Environment variables --
PORT_CLIENT_ID+PORT_CLIENT_SECRET(for CI/CD) - Encrypted file --
~/.portctl/credentials(headless Linux fallback) - Config file --
~/.portctl/config.yamlinline (not recommended)
Create a .portctlignore file in your project root to exclude resources from pull/push operations, using gitignore-style patterns.
The typical workflow for managing portal configuration with portctl:
1. portctl pull # Export live config to YAML files
2. git checkout -b feat # Branch for changes
3. (edit YAML files) # Make changes in your editor
4. portctl validate # Check syntax and schema locally
5. portctl diff # Review what will change
6. git commit & push # Version control your changes
7. portctl push # Apply changes to Port.io (via CI or locally)
In CI, use environment variables for authentication:
export PORT_CLIENT_ID="..."
export PORT_CLIENT_SECRET="..."
portctl validate --remote && portctl pushRequires Python 3.11+.
# Clone and install
git clone https://github.com/vaknir/portctl.git
cd portctl
uv sync
# Run the CLI
uv run portctl --help
# Run tests
uv run pytest tests/unit/ -x --tb=short
# Lint and format
uv run ruff check src/ tests/
uv run ruff format src/ tests/
# Type check
uv run mypy src/portctl/
# Full quality check (same as CI)
uv run ruff check src/ tests/ && uv run ruff format --check src/ tests/ && uv run mypy src/portctl/ && uv run pytest tests/unit/ -x --tb=shortsrc/portctl/
cli/ # Typer commands and Rich formatters
services/ # Business logic (planner, applier, auditor, ...)
client/ # Port API wrapper (httpx async)
models/ # Pydantic schemas for YAML and API
validation/ # Layer 1 (local) + Layer 2 (remote) checks
tests/
unit/ # 434 unit tests
integration/ # Tests against live Port API (VCR cassettes)
See docs/contributing.md for development guidelines, code standards, and pull request process.
Apache License 2.0 -- see LICENSE for details.