Metadata-Version: 2.4
Name: plane-compose
Version: 0.4.4
Summary: Project as Code framework for Plane - Define and sync projects declaratively with YAML
Project-URL: Homepage, https://github.com/makeplane/compose
Project-URL: Documentation, https://github.com/makeplane/compose/tree/main/docs
Project-URL: Repository, https://github.com/makeplane/compose
Project-URL: Bug Tracker, https://github.com/makeplane/compose/issues
Project-URL: Source Code, https://github.com/makeplane/compose
Author-email: "Plane Software, Inc." <hello@plane.so>
Maintainer-email: "Plane Software, Inc." <hello@plane.so>
License: AGPL-3.0-or-later
License-File: LICENSE.txt
Keywords: cli,devops,infrastructure-as-code,issue-tracking,plane,project-management,workflow,yaml
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx>=0.25.0
Requires-Dist: plane-sdk<1.0.0,>=0.2.8
Requires-Dist: pydantic-settings>=2.0.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: rich>=13.0.0
Requires-Dist: typer[all]>=0.9.0
Provides-Extra: dev
Requires-Dist: hatch-vcs>=0.3.0; extra == 'dev'
Requires-Dist: mypy>=1.0.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Requires-Dist: types-pyyaml>=6.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# 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

```bash
pipx install plane-compose
```

### Upgrade

```bash
pipx upgrade plane-compose
```

### Verify

```bash
plane --version
```

---

## Quick Start

### Step 1 — Authenticate

```bash
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):

```bash
plane auth login \
  --server-url https://api.plane.so \
  --auth-type pat \
  --token YOUR_TOKEN \
  --workspace myteam
```

---

### Path A — Start from Scratch

```bash
# 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):

```bash
# 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

```bash
# 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](https://developers.plane.so/dev-tools/plane-compose).

### 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.

```bash
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:

```bash
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 upgrade [WORKSPACE] [--template TEMPLATE] [--dry-run] [--schema-only]`    | Apply a versioned workspace template — diff, plan, and push changes      |
| `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

```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

```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

```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

```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:

```bash
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:

```bash
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

```bash
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)**

```bash
plane auth logout <connection-id>
plane auth login
```

**Permission denied (403)**

```bash
plane auth list-connections   # Check available workspaces
plane auth whoami             # Verify current user
```

**Project not found (404)**

```bash
# Remove stale UUID from plane.yaml, then re-push
plane schema push
```

**Rate limit exceeded (429)**

```bash
plane rate stats
export PLANE_RATE_LIMIT_PER_MINUTE=30
plane push
```

**Duplicate work items**

```yaml
# Always use stable IDs in work/*.yaml
- id: "unique-identifier"
  title: My task
```

**State out of sync**

```bash
cp .plane/state.json .plane/state.json.backup
plane state reset MYPROJ
plane pull
```

**Debug logging**

```bash
plane --debug push
tail -f ~/.config/plane-compose/plane.log
```

---

## Development

Install plane-compose into your own Python environment:

```bash
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](https://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](https://plane.so) — Main website
- [Plane API Documentation](https://docs.plane.so/api) — API reference
- [Plane Python SDK](https://github.com/makeplane/plane-python-sdk) — Official SDK

---

## License

AGPLv3 — see [LICENSE.txt](LICENSE.txt) for details.
