# p3-cli

`p3` is a task management CLI for software teams. It lets you create, select,
update, and complete tasks from the terminal, with built-in branch workflows and
`--json` output for scripts and agents.

Use it when you want task tracking to stay inside your normal dev loop instead
of bouncing between git, the browser, and your project tracker.

![p3 CLI demo](https://www.taskp3.com/p3-cli-demo.gif)

## Install

### Homebrew

```bash
brew tap raidon-inc/tap
brew install p3
```

### npm

```bash
npm install -g @taskp3/cli
```

## Quickstart

```bash
npm install -g @taskp3/cli
p3 login --google
p3 select
```

That flow signs you in, lets you pick one of your assigned tasks, saves it as
the current task for the repo, and can create or switch to the task branch.

Running `p3` with no subcommand in an interactive terminal opens a menu for
common actions like creating tasks, creating many tasks, listing tasks, and
checking auth status.

## Quick Reference

```bash
p3                    # no args: open interactive menu (TTY only)
p3 login --google     # sign in with Google (opens browser)
p3 auth whoami        # show authenticated user
p3 select             # pick an assigned task, set as current, optional branch create/checkout
p3 open               # open the selected task in the browser
p3 next               # show your highest-priority active assigned task
p3 current            # show the current task for this repo
p3 project select     # choose default project for this repo
p3 task create "Task name"   # create a task (prompts to set as current when interactive)
p3 task select        # same as p3 select
p3 project current    # show the current project for this repo
p3 task current       # same as p3 current
p3 task update           # interactively update the current task
p3 task update <taskId>  # interactively update a specific task
p3 task update --status "Working on it"   # update the current task via flags
p3 task response create --response "Thanks, looking now"   # reply on current triage task
p3 task response list    # list triage responses for current task
p3 task submission close # close triage submission for current task
p3 current            # show current task
p3 done               # mark the current task Done (or pick one), then optionally checkout development
```

## API Command Reference

Use `p3 <group> --help` or `p3 <group> <subgroup> --help` for arguments and
options. Add root `--json` for machine-readable output.

```txt
auth          status, select-user, logout
user          me, get, list, update, archive
user avatar   upload
organization  get, update
organization avatar  upload
invite        list, create, resend
bot           list, create, update, rotate-key, archive, restore
billing       plan, seats, invoices, payment-method, open
billing plan  update
billing payment-method  remove
client        list, create, update
project       list, list-archived, create, update, archive, restore, aggregate
project team  list, set, add, remove, set-admin
feature       list, create, get, update, remove
```

```txt
task          list, list-feature, get, create, create-batch, update,
              update-many, delete, restore, search, parse-text, match-text,
              generate-name
task aggregate  feature, user
task link     list, referenced-by, create, delete
task thread   list, create, update, delete, react, unreact
task history  list, react, unreact
task submission  get, open, close
task response  list, create, update, delete
task file     upload, list, get, download, delete, transcript,
              process-recording
```

```txt
label         list, create, update, delete
tag           list, create, create-bulk, find-or-create, update, delete
search
notification  list, unread, mark, mark-all-read
github        status, connect, repositories, branches, connect-repository,
              disconnect, auto-changelog, commits, files, file-content,
              search-files
vanta         status, connect, revoke, sync-users
changelog     list, generate, create, update, delete, publish, unpublish,
              regenerate
changelog code-change  list, create, update, delete, reorder, regenerate
webhook       list, create, update, delete, roll-secret
job           get, list
analytics     query
```

## Common Workflows

### Start work on the next task

```bash
p3 next
p3 select
p3 current
p3 task update
p3 done
```

### Create a task without leaving the terminal

```bash
p3 task create "Improve onboarding copy"
p3 task create --editor
p3 task create-many --file tasks.md
```

### Update status and finish work

```bash
p3 task update
p3 done
```

### Use in scripts and agents

```bash
p3 --json task get <taskId>
p3 --json task list --limit 25
```

## Authentication

### Email + password

```bash
p3 login --email you@company.com
p3 signup --email you@company.com
```

### Google sign-in

```bash
p3 login --google
p3 signup --google
```

The CLI prints a browser URL. Complete sign-in or signup in the browser, then
return to the terminal and press Enter. The CLI finalizes auth automatically
and prompts for a user if the credential has multiple users.

### Check status / logout

```bash
p3 auth status
p3 auth logout
```

## Task Commands

With `--json`, typical fields include `task`, `tasks`, `total`, `page`, and
`limit` depending on the route.

### Interactive Select

```bash
p3 select
p3 list
p3 task select
```

In an interactive terminal, `p3 select` shows your assigned tasks, lets you pick
one, stores it as the current task for the repo, then can:

- create or checkout the task branch
- move the task to `Working on it`
- copy the task definition to your clipboard

If this repo has no current project configured yet, the CLI first prompts you to
select a project and saves it for the repo.

By default, `p3 select` only shows tasks in `Not Started` or `Working on it`.
Optional flags:

```bash
p3 select --all-statuses
p3 select --include-stuck --include-in-review
p3 select --include-done --include-cancelled
```

Branch behavior:

- `Not Started`: create or checkout the task branch, then move the task to `Working on it`
- `Working on it`: switch to the local branch if it exists, otherwise create a local tracking branch from remote if it exists there, otherwise offer to create it locally

Branch format:

```txt
first-name/feature-slug-task-slug-taskid8
```

Example:

```txt
ryan/app-add-loading-state-2a16151
```

### List

```bash
p3 task list --limit 25 --page 1
p3 task list --feature-id <featureId>
```

### Get

```bash
p3 task get <taskId>
```

### Triage Responses

Respond to triage submissions from the terminal. If you omit `--task-id` or the
positional task id, commands use the current task for this repo.

```bash
p3 task response list
p3 task response list <taskId> --limit 25
p3 task response create --response "Thanks, I can reproduce this."
p3 task response create <taskId> --response-file ./reply.md
p3 task response create --editor --file screenshot.png
p3 task response update <responseId> --response "Updated response"
p3 task response delete <responseId> --yes
p3 --json task response list <taskId>
```

### Triage Submission Status

Close or reopen the triage submission attached to a task. If you omit `--task-id`
or the positional task id, commands use the current task for this repo.

```bash
p3 task submission close
p3 task submission close <taskId>
p3 task submission open <taskId>
p3 --json task submission close <taskId>
```

### Search

```bash
p3 task search --term "billing"
```

### Create

`p3 task create` accepts the task name either as positional text or with
`--name`. If you omit both `--feature-id` and `--project-id`, the CLI uses the
repo's saved default project or prompts you to choose one.

```bash
p3 task create "Improve onboarding"
p3 task create "Assign me" --assignTo @hazel --description "..."
p3 task create --name "Improve onboarding" --project-id <projectId>
p3 task create --feature-id <featureId> --name "Improve onboarding"
p3 task create --feature-id <featureId> --name "Fix bug" --description "..."
p3 task create --feature-id <featureId> --name "Assign me" --assignTo <userId>
p3 task create --feature-id <featureId> --name "Assign me" --assignTo @hazel
p3 task create --feature-id <featureId> --name "Linked" --linked-task-id <id> --linked-task-type 1
p3 task create --project-id <projectId> --name "Improve onboarding"
p3 task create --file task.md
p3 task create --file task.txt
p3 task create --description-file ./description.txt --name "Improve onboarding"
p3 task create --editor --template chore
p3 task create --editor --template bug --from-branch
p3 task create
p3 create
p3 task create --from-commit HEAD
p3 task create "Investigate flaky test" --clipboard
p3 task create "Fix login" --check-duplicates
```

Notes:

- `@username` resolves to the assignee's profile username (set in Profile -> Username)
- `--assignTo` is the canonical assignee flag; `--assignedTo` and `--assigned-to-id` remain supported for compatibility
- `--file task.md` uses the first markdown heading as the task name and the rest as the description
- `--file task.txt` uses the first non-empty line as the task name and the rest as the description
- `--description-file ./description.txt` reads a multiline description from a file and preserves paragraph breaks
- `--editor` opens `$EDITOR`/`$VISUAL` when set, otherwise it prefers Cursor, then VS Code, then terminal editors, then the system editor
- `p3 task create` with no positional name and no `--name` automatically opens the editor draft
- `p3 create` is an alias of `p3 task create`
- `--from-branch` uses the current git branch name as the default task name
- `--from-commit <sha>` uses the commit subject as the task name and the body as the description
- `--clipboard` reads the task description from the system clipboard
- `--template bug|feature|chore` scaffolds a markdown description template
- `--check-duplicates` searches for similar task names and warns before creating
- when passing literal shell metacharacters such as backticks, quote for your shell first, e.g. `p3 task create 'name with --flag and \`backticks\`'`
- after creating a task in an interactive terminal, the CLI prints the task URL and asks whether to set it as the current task (default: yes)

Multiline description examples:

```bash
p3 task create "Improve onboarding" --description "$(cat <<'EOF'
Add a shorter first-run flow.

Keep the checklist and project links.
EOF
)"

p3 task create "Improve onboarding" --description-file ./description.txt
```

### Create Many

Interactive mode:

```bash
p3 task create-many
p3 task create-many --apply "--project-id <projectId> --assignTo @hazel"
p3 task create-many --dry-run
```

Enter one task per prompt line using the same syntax as `p3 task create`.
Submit a blank line to finish.

Example prompt lines:

```txt
Fix auth redirect --assignTo @hazel
Improve onboarding --description "Shorten first-run flow"
Linked follow-up --linked-task-id <id> --linked-task-type 1
```

File mode:

```txt
- Add loading state --assignTo @hazel
- Add loading state in modal --project-id <projectId>
- Fix auth redirect --description "Skip select-user fetch"
- Improve onboarding --name "Improve onboarding copy"
- Update CLI docs
1. Numbered items also work
```

Markdown file mode:

```md
# Fix auth redirect

Skip select-user fetch.

---

# Improve onboarding

Shorten first-run flow.
```

Use the same line format in a file, then preview or create them:

```bash
p3 task create-many --file tasks.txt --dry-run
p3 task create-many --file tasks.txt
p3 task create-many --file tasks.md --dry-run --preview-rich
p3 task create-many --file tasks.txt --apply "--project-id <projectId> --assignTo @hazel"
p3 task create-many --editor
p3 task create-many --watch tasks.md
```

Behavior:

- `p3 task create-many` starts interactive entry mode
- `p3 task create-many --file tasks.txt` reads one task per line from a file
- `p3 task create-many --file tasks.md` reads markdown sections separated by `---`
- blank lines and `# comments` are ignored
- leading list markers like `-`, `*`, `+`, and numbered prefixes like `1.` are ignored
- each line supports the same create options as `p3 task create`
- unknown `--something` text stays in the task name/description unless it matches a supported create option
- `--editor` opens `$EDITOR`/`$VISUAL` when set, otherwise it prefers Cursor, then VS Code, then terminal editors, then the system editor
- `--watch tasks.md` keeps watching the file and auto-creates newly added tasks
- `--preview-rich` prints task descriptions as markdown-style blocks before confirmation
- `--apply` adds shared options to every line
- per-line options override `--apply`
- interactive runs show a confirmation table before submit
- file runs use the same parser and preview/creation flow as interactive runs
- partial failures are reported after the run

### Update

```bash
p3 task update
p3 task update <taskId>
p3 task update <taskId> --status "Working on it"
p3 task update <taskId> --priority high --assignTo <userId>
p3 task update <taskId> --assignTo @hazel
p3 task update <taskId> --description-file ./description.txt
p3 task update <taskId> --tag-ids id1,id2 --action Build
p3 task assign <taskId> --user-id <userId>
p3 task assign --task-ids id1,id2 --user-id <userId>
```

Behavior:

- omit `<taskId>` to update the current task
- in an interactive terminal, `p3 task update` with no flags opens a property picker for status, priority, complexity, clarity, action, assignee, name, description, and tags
- tag selection loads project tag categories first, then lets you choose tags within that category while preserving tags from other categories
- use `--description-file` when you want to update a task with a multiline description from the command line

### Bulk update

```bash
p3 task update-many --task-ids id1,id2 --status Done
```

### Convenience commands

```bash
p3 next  # -> alias of `p3 task next`
p3 task next  # -> returns the highest-priority active task assigned to you
p3 open  # -> open the selected task in the browser (taskp3.com/p/<projectId>?selectedTaskId=<id>)
p3 done  # -> marks the current task Done (or prompts to pick one), then asks to checkout development
p3 task done <taskId>  # -> marks the provided task Done
```

### Current Task

```bash
p3 current
p3 task current
p3 current set <taskId>
p3 current clear
```

Current task resolution order:

- repo-scoped selected task from CLI config
- current branch task id suffix, if detectable

### Current Project

```bash
p3 project current
p3 project select
p3 project list
p3 project get <projectId>
p3 project team list [--project-id <id>]
p3 project team set <id> [id...] [--project-id <id>] [--yes]   # set exact team (shows diff, confirms)
p3 project team add <userId> [--project-id <id>] [--admin]
p3 project team remove <userId> [--project-id <id>]
p3 project team set-admin <userId> <true|false> [--project-id <id>]
p3 project create --name <name> --client-id <id>
p3 project update <projectId> [--name <name>] [--client-id <id>]
p3 project archive <projectId>
p3 project restore <projectId>
p3 project list-by-client <clientId>
```

### Clients

```bash
p3 client list [--search <term>] [--page <n>] [--limit <n>]
p3 client create [--name <name>]
p3 client update <clientId> --name <name>
```

### Features

```bash
p3 feature list [--project-id <id>]
p3 feature create [--project-id <id>] --name <name> [--parent-id <id>] [--tag-ids <ids>]
p3 feature update <featureId> [--name <name>] [--parent-id <id>] [--tag-ids <ids>]
p3 feature get <featureId>
p3 feature remove <featureId>
```

### Task files (attachments)

```bash
p3 task file upload [path ...] [--task-id <id>]   # omit paths to enter interactively in TTY
p3 task file list [--task-id <id>]
p3 task file delete <fileId>
```

Supported file types: PNG, JPEG, GIF, PDF, TXT, MD, MARKDOWN, CSV, DOC, DOCX, XLS, XLSX, ZIP (max 50MB).

### Changelog

```bash
p3 changelog list [--project-id <id>]
p3 changelog create [--project-id <id>] --description <text> --types <types> --release-date <date> [--published]
p3 changelog update <entryId> [--description <text>] [--types <types>] [--release-date <date>] [--published <bool>]
p3 changelog delete <entryId>
p3 changelog publish <entryId>
p3 changelog unpublish <entryId>
```

Changelog types: `Bug fix`, `New Feature`, `Improvement`, `Deprecation`.

### Search

```bash
p3 search <term>
```

Global search across tasks, features, etc.

### Webhook endpoints

```bash
p3 webhook list [--project-id <id>]
p3 webhook create [--project-id <id>] --url <url> --events <comma-separated> [--description <text>]
p3 webhook delete <endpointId> [--project-id <id>]
p3 webhook roll-secret <endpointId> [--project-id <id>]
```

Events: `triage.response.created`, `triage.submission.closed`, `*` (all).

## Webhook Listener

Forward webhook events to a local URL during development — no tunnel required when running the API locally.

```bash
p3 listen --forward-to http://localhost:3000/webhooks
p3 listen --forward-to http://localhost:3000/webhooks --project-id <id>
```

The CLI polls for new webhook events and forwards each one to the target URL with the same `x-p3-signature` header format used in production. A local signing secret is printed at startup so your app can verify signatures identically to production.

Uses the default project if `--project-id` is omitted.

## Enum Values (validated)

Use these values (case-insensitive). Aliases like `InProgress` are normalized.

- `status`: `Not Started`, `Stuck`, `Working on it`, `Done`, `Cancelled`, `In Review`
- `priority`: `low`, `medium`, `high`, `critical`
- `action`: `N/A`, `Build`, `Design`, `Debug`, `Fix`, `Enhance`, `Research`

## Output

Commands print concise human-readable output by default.

Use `--json` for full JSON output:

```bash
p3 --json task get <taskId>
```

Example JSON:

```json
{
  "task": {
    "id": "123",
    "name": "Improve onboarding",
    "status": "Working on it"
  }
}
```

## Advanced

### Base URL

API base URL (default `https://api.taskp3.com`) is used for all CLI API calls. App base URL (default `https://www.taskp3.com`) is used for `p3 open` and task links; it is derived from the API URL unless set separately (e.g. for local dev: API on one port, app on another). Override with:

```bash
p3 config:set --base-url http://localhost:3001
p3 config:set --app-base-url http://localhost:3000
```

Or on a single command:

```bash
p3 auth status --base-url http://localhost:3001
```

## Config

You usually do not need to set a project manually:

- On the first `p3 task create` (or `p3 listen`) without `--project-id`, the CLI
  auto-selects when there is one project, or prompts you to choose when there
  are multiple.
- The chosen project is saved per local repo (git root), so context switching
  across repos keeps separate defaults.

Optional manual overrides:

```bash
p3 config:set --base-url http://localhost:3001
p3 config:set --app-base-url http://localhost:3000
p3 config:set --default-project-id <projectId>
p3 config:set --default-project-id <projectId> --global
p3 config:view
```

## Shell Completion

Generate completion scripts for your shell:

```bash
# Bash - add to ~/.bashrc
eval "$(p3 completion bash)"

# Zsh - add to ~/.zshrc
eval "$(p3 completion zsh)"

# Fish - save to completions directory
p3 completion fish > ~/.config/fish/completions/p3.fish
```

## Environment Variables

| Variable     | Description                           |
| ------------ | ------------------------------------- |
| `P3_API_URL` | Override the default API base URL     |
| `P3_APP_URL` | Override the default web app base URL |
| `P3_DEBUG`   | Set to `1` to enable debug output     |

## Debug Mode

For troubleshooting, enable debug output:

```bash
# Via environment variable
P3_DEBUG=1 p3 task list

# Via flag
p3 --debug task list
```

## Exit Codes

| Code | Meaning                 |
| ---- | ----------------------- |
| `0`  | Success                 |
| `1`  | General error           |
| `4`  | Authentication required |
