Project as Code framework for Plane - Define and sync projects declaratively with YAML
Project description
Plane Compose
Project as Code framework for Plane — Define projects, schemas, and work items in YAML. Sync bidirectionally. Version control everything.
Plane Compose brings infrastructure-as-code workflows to project management. Declare your Plane projects in YAML, push them to Plane, pull changes back, and version-control everything in Git.
Features
- Bidirectional sync — push local YAML to Plane, pull remote state back
- Schema management — work item types, states, labels, workflows, and custom properties
- Workspace management — members, releases, initiative labels, relation definitions, project states
- Template-based init & upgrade — bootstrap or upgrade projects from local or remote (Git) templates
- Project cloning — clone any existing Plane project to local YAML
- Intelligent diff — see exactly what would change before pushing
- Collaborative mode — additive-only push, safe for shared teams
- CI/CD ready —
--dry-run,--exit-code,--json, and non-interactive flags throughout - Self-hosted support — works with any Plane instance, not just Plane Cloud
- Rate limiting — built-in throttling with live stats
Installation
pipx install plane-compose
Upgrade
pipx upgrade plane-compose
Verify
plane --version
Quick Start
Step 1 — Authenticate
plane auth login
# Interactive: enter your API key and workspace slug
# API keys: https://app.plane.so/<workspace>/settings/account/api-tokens/
For CI/CD (non-interactive):
plane auth login \
--server-url https://api.plane.so \
--auth-type pat \
--token YOUR_TOKEN \
--workspace myteam
Path A — Start from Scratch
# Initialize a new project (default built-in template)
plane init MYPROJ -w myteam
cd myproj
# Edit schema to match your workflow
vim schema/types.yaml
vim schema/workflows.yaml
# Push schema (creates the project in Plane)
plane schema push
# Add work items
vim work/workitems.yaml
# Push work items
plane push
Or bootstrap from a template (local path or Git URL):
# From a local template
plane init MYPROJ -w myteam -t ./templates/engineering
# From a remote Git template (with optional version pin)
plane init MYPROJ -w myteam -t https://github.com/org/repo/templates/standard@v1.2.0
cd myproj
# Push everything (schema + any template work items)
plane push
Path B — Clone an Existing Project
# Clone by UUID, project key, or workspace/KEY
plane clone myteam/MYPROJ
cd myproj
# See what was pulled
cat .plane/remote/items.yaml
# Make changes and push
vim work/inbox.yaml
plane push
Commands
For the full flag reference, see the Command Reference.
Auth
| Command | Purpose |
|---|---|
plane auth login |
Authenticate with Plane (interactive or CI flags) |
plane auth logout CONNECTION_ID |
Remove a connection |
plane auth list-connections |
List all saved connections and workspaces |
plane auth connect-workspace CONNECTION_ID WORKSPACE |
Link a workspace to a connection |
plane auth disconnect-workspace WORKSPACE |
Unlink a workspace |
Project
| Command | Purpose |
|---|---|
plane init [PROJECT] -w WORKSPACE [-t TEMPLATE] |
Initialize a new project (optionally from a template) |
plane clone PROJECT [--workspace WS] |
Clone an existing Plane project to local YAML |
plane upgrade [PROJECT] -t TEMPLATE [--include-data] [--skip-pull] [--dry-run] |
Upgrade schema (and optionally data) from a template |
plane schema validate [PROJECT] |
Validate local schema files without connecting to Plane |
plane schema push [PROJECT] [--dry-run] [--force] |
Push schema to Plane (creates project if needed) |
plane schema import [PROJECT] [--merge] [--force] |
Import remote schema into local state |
plane schema sync [PROJECT] [--dry-run] |
Declarative schema sync — make remote match local exactly |
plane schema diff [PROJECT] [--exit-code] |
Compare local schema with remote |
plane push [PROJECT] [--dry-run] [--schema-only] [--skip SECTION] [--resume] |
Push schema and/or work items to Plane |
plane pull [PROJECT] [--schema-only] [--skip SECTION] |
Pull schema and/or work items from Plane |
plane diff [PROJECT] [--exit-code] |
Show bidirectional diff between local and remote work items |
plane status [--all] |
Show project sync status |
plane validate [--offline] |
Validate work items against schema |
plane upgrade — Template-based upgrades
Pulls the latest state from Plane, diffs it against a template, shows a plan, and applies changes. Non-destructive — local-only items are always preserved.
plane upgrade -t ./my-template # Schema only, current dir
plane upgrade MYPROJ -t https://github.com/org/repo/tmpl # Remote template
plane upgrade MYPROJ -t ./my-template --include-data # Schema + cycles, modules, work items
plane upgrade MYPROJ -t ./my-template --dry-run # Preview only
Pin a specific template version:
plane upgrade MYPROJ -t https://github.com/org/repo@v1.2.0
Workspace (plane ws)
Manage workspace-level configuration: work item types, members, releases, initiative labels, relation definitions, and project states.
| Command | Purpose |
|---|---|
plane ws clone [WORKSPACE] |
Clone workspace configuration to local YAML |
plane ws pull [--merge] [--force] |
Pull latest workspace config from Plane |
plane ws push [--dry-run] [--prune] [--skip SECTION] |
Push local workspace changes to Plane |
plane ws diff |
Show differences between local and remote workspace config |
plane ws state show |
Display workspace sync state |
plane ws state reset [--force] |
Reset workspace sync state |
plane ws state remove PATH_TO_ITEM |
Remove a specific item from state tracking |
Sync State (plane state)
| Command | Purpose |
|---|---|
plane state show PROJECT_KEY |
Show project sync state |
plane state reset PROJECT_KEY [--force] |
Reset sync state (next push treats all items as new) |
plane state clear-items PROJECT_KEY |
Clear work item tracking, keep schema mappings |
plane state remove PROJECT_KEY TRACKING_KEY |
Remove a specific item from tracking |
Rate Limiting (plane rate)
| Command | Purpose |
|---|---|
plane rate stats |
Show current rate limit statistics |
plane rate reset |
Reset rate limit statistics |
Project Structure
Created by plane init or plane clone:
myproj/
├── plane.yaml # Project config — workspace, connection, template source
├── workspace.yaml # Workspace-level config (features, work item types) — auto-managed
├── schema/
│ ├── features.yaml # Project feature flags
│ ├── labels.yaml # Label definitions
│ ├── members.yaml # Project members
│ ├── states.yaml # Workflow states
│ ├── types.yaml # Work item types and custom properties
│ └── workflows.yaml # State transitions
├── work/
│ ├── cycles.yaml # Cycles
│ ├── modules.yaml # Modules
│ └── workitems.yaml # Work items (any *.yaml except cycles/modules is treated as work items)
└── .plane/
└── state.json # Sync state (auto-managed)
plane.yaml
workspace: myteam
connection: default # Connection to use (defaults to "default")
template: default # Template source — set by init/upgrade, used by next upgrade
project:
key: MYPROJ
name: My Project
uuid: abc-123-def # Auto-populated after first schema push
defaults:
type: task
workflow: standard
work/workitems.yaml
workitems:
- id: "auth-oauth" # Stable ID — prevents duplicates across pushes
title: Implement OAuth2 authentication
type: task
priority: high
labels: [backend, feature]
state: todo
description: Add OAuth2 authentication flow
- id: "bug-login-css"
title: Fix login button alignment
type: bug
priority: medium
state: backlog
work/cycles.yaml
cycles:
- name: Sprint 1
description: First sprint — core setup and scaffolding
start_date: '2024-01-01'
end_date: '2024-01-14'
- name: Sprint 2
description: Second sprint — feature development
start_date: '2024-01-15'
end_date: '2024-01-28'
work/modules.yaml
modules:
- name: Authentication
description: User login, OAuth, and session management
status: backlog
- name: API Integration
description: Third-party API integrations
status: backlog
Workspace Structure
Created by plane ws clone:
myteam/
├── plane.yaml # Workspace config (slug, connection)
├── schema/
│ ├── features.yaml # Workspace feature flags
│ ├── members.yaml # Members with roles
│ ├── workitemtypes.yaml # Work item types, properties, hierarchy
│ ├── project.yaml # Project-level states and labels
│ ├── initiatives.yaml # Initiative labels
│ ├── releases.yaml # Release tags and labels
│ ├── relations.yaml # Custom relation type definitions
│ └── webhooks.yaml # Webhook configurations (read-only stub)
└── work/
└── releases.yaml # Release items (operational data)
Configuration
Self-Hosted Plane
Point to your instance when authenticating:
plane auth login --server-url https://plane.yourcompany.com
The server URL is stored in the connection and used automatically for all subsequent commands. No changes to plane.yaml needed.
Alternatively, override via environment variable:
export PLANE_API_URL="https://plane.yourcompany.com"
API Key
- Plane Cloud:
https://app.plane.so/<workspace>/settings/account/api-tokens/ - Self-hosted:
https://your-plane-url/<workspace>/settings/account/api-tokens/
Credentials are stored at ~/.config/plane-compose/credentials.
Environment Variables
PLANE_API_URL=https://api.plane.so # API base URL
PLANE_API_TIMEOUT=30 # Request timeout (seconds)
PLANE_RATE_LIMIT_PER_MINUTE=50 # API rate limit
PLANE_DEBUG=true # Enable debug logging
PLANE_LOG_TO_FILE=true # Log to ~/.config/plane-compose/plane.log
Troubleshooting
Authentication failed (401)
plane auth logout <connection-id>
plane auth login
Permission denied (403)
plane auth list-connections # Check available workspaces
plane auth whoami # Verify current user
Project not found (404)
# Remove stale UUID from plane.yaml, then re-push
plane schema push
Rate limit exceeded (429)
plane rate stats
export PLANE_RATE_LIMIT_PER_MINUTE=30
plane push
Duplicate work items
# Always use stable IDs in work/*.yaml
- id: "unique-identifier"
title: My task
State out of sync
cp .plane/state.json .plane/state.json.backup
plane state reset MYPROJ
plane pull
Debug logging
plane --debug push
tail -f ~/.config/plane-compose/plane.log
Development
Install plane-compose into your own Python environment:
pip install plane-compose
# Or pin to a specific version
pip install plane-compose==0.4.0
Architecture
src/planecompose/
├── cli/ # CLI commands (thin layer — delegates to sync/backend)
├── backend/ # Backend abstraction (PlaneApiClient, rate limiting)
├── core/ # Domain models (Pydantic)
├── sync/ # Sync orchestration (planner + executor)
├── diff/ # Change detection
├── parser/ # YAML parsing
├── templates/ # Template loader (local + Git, @tag pinning)
├── utils/ # Rate limiting, logging
├── config/ # Configuration management
└── exceptions.py # Custom exception hierarchy
Documentation
Full documentation is available at developers.plane.so/dev-tools/plane-compose, covering:
- Getting started — authentication, init, schema push, work items
- Cloning an existing project
- Project structure reference
- Understanding sync modes (collaborative vs declarative)
- Working with schemas — types, workflows, labels
- Working with work items
- Self-hosting configuration
Links
- Plane — Main website
- Plane API Documentation — API reference
- Plane Python SDK — Official SDK
License
AGPLv3 — see LICENSE.txt for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file plane_compose-0.4.3.tar.gz.
File metadata
- Download URL: plane_compose-0.4.3.tar.gz
- Upload date:
- Size: 423.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f355f63142563f9ff47202fd4377b74866b73031df383082c6468372eb6278d
|
|
| MD5 |
6b740c9505ce845efa282e5589064a9f
|
|
| BLAKE2b-256 |
08eacaf8affced716faf671149a61e19dce858a0d4f94f7efa805c75048785c1
|
File details
Details for the file plane_compose-0.4.3-py3-none-any.whl.
File metadata
- Download URL: plane_compose-0.4.3-py3-none-any.whl
- Upload date:
- Size: 314.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
468a184151003123e2151b659801b4f1e617b657d7a2e237651a5683b5461dcc
|
|
| MD5 |
2de3eee1ec5e1f01cfa94f741041897f
|
|
| BLAKE2b-256 |
b79dd3ebcb95059a028439529c1b9988111072fc57ccad33e3bc2858b3b4424d
|