Reference
state
Destructive. Inspect and repair a project's .plane/state.json. Every command takes an optional [project] folder and --path; remove uses -p / --project instead of a positional folder.
| Command | What it does |
|---|---|
state show [--json] | List types, states, labels, cycles, modules and work items as dotted.path = value lines you can copy. --json prints the whole file, including pages, workflows and properties. |
state remove <path> | Drop one entry, for example types.Task, states.In Progress, labels.Frontend, cycles.Sprint 1, modules.Auth or work_items.id:MYPROJ-1. Quote paths that contain spaces. |
state clear-items [-f] | Forget work item tracking but keep the schema mappings, so work items can be re-synced without recreating the schema. |
state reset [-f] | Delete the state file. The next push treats everything as new and can create duplicates if Plane already has the data. |
plane state show
plane state remove "states.In Progress"
plane state clear-itemsImport instead of resetting
After plane state reset, or if .plane/ is lost, run plane schema import and then plane pull to rebuild the mappings before you push again.
rate
Safe. Plane Compose throttles its own API requests and keeps counters for each connection.
| Command | What it does |
|---|---|
rate stats [-c <connection>] | Total requests, requests per minute, total wait time, tracking period and the client throttle (default 50 a minute). |
rate reset [-c <connection>] | Reset the counters. Without -c, it resets the default label. |
Change the throttle with PLANE_RATE_LIMIT_PER_MINUTE. Failed API calls are retried up to PLANE_PLANE_API_RETRY_ATTEMPTS times. See Environment variables.
Multiple projects
Keep several projects in one repository and work on them together. Plane Compose finds projects by looking for plane.yaml files under the current directory.
| Command | To act on every project |
|---|---|
plane status | --all, optionally with -w <workspace> and --filter <glob> |
plane push | --all, with -w and --filter |
plane pull | --all, with -w and --filter |
plane status --all
plane push --all -w myteam --dry-run
plane pull --all --filter "services/*" --forcepush --all runs one project at a time with force on, so you aren't asked about remote conflicts. It uses only --dry-run, --force, --schema-only, --work-only, -w and --filter, and ignores --skip, --path, --no-conflict-check and --exit-code.
.planeignore
Put a .planeignore file in the directory you run from to leave projects out. Write one pattern per line; blank lines and lines starting with # are ignored. Patterns are shell-style globs matched against each project's path relative to that directory.
# skip experiments and archived projects
archive/*
experiments/*Run in CI
Log in without prompts, then push with machine-readable exit codes:
plane auth login --server-url https://api.plane.so --auth-type pat \
--token "$PLANE_TOKEN" --workspace myteam -c ci
plane validate
plane push --force --no-conflict-check --exit-codeWith --exit-code, treat 0 (nothing to push) and 2 (work item changes applied) as success and 1 as failure. Use plane diff --exit-code or plane schema diff --exit-code as a drift check that fails when Plane and your files differ.
You can also log in from environment variables. Run one plane push per project at a time: state writes are only locked within one process.
Global options and exit codes
Global options go before the command, for example plane --debug push.
| Flag | What it controls |
|---|---|
-V, --version | Print the version and exit. |
-v, --verbose | Verbose output, with debug logging to the console. |
--debug | Debug logging, also written to ~/.config/plane-compose/plane.log. |
--install-completion, --show-completion | Shell completion. |
| Command | Exit codes |
|---|---|
push --exit-code | 0 nothing to push, 1 error, 2 work item changes applied (or found, with --dry-run) |
diff --exit-code | 0 in sync, 1 error, 2 differences |
schema diff --exit-code | 0 in sync, 1 error, 2 differences |
| Any command | 1 on failure, including partial push failures and validation errors. 130 on Ctrl+C for push, pull, clone, diff, validate, upgrade, schema and ws. |
Environment variables
| Variable | Default | Effect |
|---|---|---|
PLANE_CONFIG_DIR | ~/.config/plane-compose | Where config.json, rate-limits.json and the log live. |
PLANE_SERVER_URL | unset | Fallback for auth login --server-url. |
PLANE_AUTH_TYPE | unset | Fallback for --auth-type (pat, workspace, 1 or 2). |
PLANE_AUTH_TOKEN | unset | Fallback for --token. |
PLANE_WORKSPACE | unset | Fallback for --workspace. |
PLANE_CONNECTION | unset | Fallback for the connection name in auth login. |
PLANE_RATE_LIMIT_PER_MINUTE | 50 | Client-side request throttle. |
PLANE_RATE_LIMIT_PER_HOUR | 3000 | Must be at least the per-minute value, or plane won't start. It isn't enforced as a limit. |
PLANE_PLANE_API_RETRY_ATTEMPTS | 3 | Retries for failed API calls. The doubled PLANE_ prefix is correct. |
PLANE_API_URL, PLANE_API_TIMEOUT, PLANE_API_VERSION and PLANE_API_RETRY_ATTEMPTS have no effect in v0.5.2. Use --server-url at login or api_url: in plane.yaml to point at a server, and --debug instead of PLANE_DEBUG.
plane doesn't load a .env file from the working directory, so a repository can't redirect your API URL. Export variables in your shell or CI environment.
Troubleshooting
Start by re-running the command with plane --debug <command>. The log is also saved to ~/.config/plane-compose/plane.log. Don't share logs that contain tokens.
| Symptom | Fix |
|---|---|
Not authenticated. Run 'plane auth login' first | There's no saved connection. Run plane auth login. If you set PLANE_CONFIG_DIR, you're looking at a different, empty config directory. |
Not a Plane project (no plane.yaml found in ...) | You're outside a project folder. cd into it, or pass the folder name and --path. |
Workspace <slug> is not connected | Add it with plane auth login -w <slug> or plane auth connect-workspace <slug> -c <connection>. |
Workspace <slug> exists in multiple connections | Only happens with a hand-edited config.json. Pass --connection <id> on commands that take it, or clean up the file. |
Authentication failed, Permission denied or Workspace not found at <url> | From the login check: the token is invalid or expired (401), lacks access (403), or the slug or server URL is wrong (404). Nothing was saved. |
Token is too short | Tokens under 10 characters are rejected. Check you passed the token and not a placeholder. |
Identifier ... is N characters, Plane allows a maximum of 10 | Use a shorter project key with plane init. |
Unknown type, state or label in validate or push | The name isn't in the schema. Check spelling and case, run plane schema push, or refresh the local schema with plane pull --schema-only. |
| A duplicate work item after editing a title | The item had no id, so it was tracked by content hash. Add a stable id and delete the extra copy in Plane. Future pushes write IDs back automatically. |
N conflict(s) detected | Someone changed the item in Plane since your last sync. Run plane diff, then plane pull --merge to take their changes, or push with --force to overwrite them. |
| Some items failed to push | Fix the cause, then run plane push --resume to retry only the failed items. |
All work items are already synced! when you expected changes | The section may be skipped: its file is missing from work/, or its feature is false in schema/features.yaml. plane status shows pending counts. |
| Push tries to create things that already exist | Local state is missing or was reset. Run plane schema import, then plane pull. |
watchers or children error from validate | Push doesn't support them in v0.5.2. Remove watchers, and turn children into top-level items with parent set. |
Insecure http:// warning | Your token would be sent in plain text to a non-local host. Use https://. |
| Config file permissions warning | plane has reset config.json to owner-only (0600). No action needed. |
| Slow on a large project | Fetch less: --schema-only, --skip workitems or --no-properties on pull and clone, and --skip on diff. |

