openproject
OpenProject CLI
Single-command interface for OpenProject. All operations via op.py.
Quick Start
# From skill directory:
cd skills/openproject
# 1. First time: init config (only once per project)
uv run python op.py init 13
# 2. Check status
uv run python op.py status
# 3. Start working
uv run python op.py wp list --status open
Setup
cd skills/openproject
uv sync
Configure .env:
OPENPROJECT_URL=https://your-instance.com
OPENPROJECT_API_KEY=your-api-key
API key from: OpenProject → My Account → Access Tokens
CLI Commands
All commands: cd skills/openproject && uv run python op.py <command>
System
| Command | Description |
|---|---|
status |
Check connection + config status |
init <project_id> |
Init config for project (once) |
config |
Show full config (types, statuses, members, custom fields) |
Work Packages (wp)
| Command | Description |
|---|---|
wp list [options] |
List work packages |
wp get <id> |
Get single work package |
wp create --subject "..." [options] |
Create work package |
wp update <id> [options] |
Update work package |
wp delete <id> |
Delete work package |
wp comment <id> --message "..." |
Add comment |
wp activities <id> |
List activities/comments |
wp relations <id> |
List WP relations |
wp add-relation <from> <to> --type blocks |
Create relation |
wp del-relation <relation_id> |
Delete relation |
wp schema --type-id N |
Get form schema |
wp list filters: --status open|closed|all|"name" --type "Task" --assignee "name" --parent N --project N --limit N
wp create/update: --subject --type --status --priority --assignee --responsible --description --parent --version --start-date --due-date --estimated-hours --done --cf "key=val"
relation types: relates|blocks|blocked|precedes|follows|duplicates|includes|partof|requires
Time Tracking (time)
| Command | Description |
|---|---|
time log <wp_id> --hours N |
Log time entry |
time list [options] |
List time entries |
time today |
Today's entries for current user |
time get <id> |
Get time entry |
time update <id> [options] |
Update time entry |
time delete <id> |
Delete time entry |
time activities |
List activity types |
time log: --hours N (required) --comment "..." --date YYYY-MM-DD --activity N
time list: --wp N --user "name" --date --from-date --to-date --limit N
time update: --hours N --comment "..." --date --wp N --activity N
Projects (project)
| Command | Description |
|---|---|
project list |
List all projects |
project get <id> |
Get project |
project create --name "..." |
Create project |
project update <id> [options] |
Update project |
project delete <id> |
Delete project |
project versions [--id N] |
List versions |
project categories [--id N] |
List categories |
project create: --name --identifier --description --parent N --public
Notifications (notif)
| Command | Description |
|---|---|
notif list [--unread] [--reason X] |
List notifications |
notif count |
Unread count |
notif read <id> |
Mark as read |
notif unread <id> |
Mark as unread |
notif read-all |
Mark all read |
notif reasons: mentioned|assigned|watched|responsible|commented|created|prioritized|scheduled
Users (user)
| Command | Description |
|---|---|
user list |
List all users |
user get <id> |
Get user |
user me |
Current user info |
Lookups (from config cache)
| Command | Description |
|---|---|
members |
Project members (name + user_id) |
types |
WP types (Task, Bug, etc.) |
statuses |
All statuses |
priorities |
All priorities |
Examples
# List open tasks assigned to Hung NB
uv run python op.py wp list --status open --assignee "Hung NB" --type Task
# Create a bug
uv run python op.py wp create --subject "Login page broken" --type Bug --priority High
# Update status and assignee
uv run python op.py wp update 675 --status "In progress" --assignee "Hung NB"
# Add comment to WP
uv run python op.py wp comment 675 --message "Fixed in commit abc123"
# Create a relation: WP 100 blocks WP 200
uv run python op.py wp add-relation 100 200 --type blocks
# Log 2.5 hours
uv run python op.py time log 675 --hours 2.5 --comment "Fixed login bug"
# Get today's logged time
uv run python op.py time today
# Time entries for date range
uv run python op.py time list --from-date 2026-02-01 --to-date 2026-02-28 --user "Tuan HV"
# Check unread notifications
uv run python op.py notif count
# List unread notifications
uv run python op.py notif list --unread --limit 10
# Get current user
uv run python op.py user me
# List project versions
uv run python op.py project versions
Output Format
All commands output JSON. Example:
{"count": 2, "work_packages": [{"id": 675, "subject": "Login page", "type": "Bug", "status": "In progress"}]}
⚠️ Important Notes
- Name resolution uses config cache. Refresh with:
uv run python op.py init <project_id> - Custom fields are project/type specific. Use
op.py configto see available ones. op.pyauto-loads.env— no manualload_dotenv()needed.
Advanced: Python API
For complex operations not covered by CLI, use Python packages directly:
uv run python -c "
from openproject_work_packages import list_work_packages
for wp in list_work_packages(project_id=13):
print(wp['subject'])
"
Sub-package docs:
| Package | SKILL.md |
|---|---|
openproject_core |
openproject-core/SKILL.md |
openproject_projects |
openproject-projects/SKILL.md |
openproject_work_packages |
openproject-work-packages/SKILL.md |
openproject_time |
openproject-time/SKILL.md |
openproject_users |
openproject-users/SKILL.md |
openproject_documents |
openproject-documents/SKILL.md |
openproject_queries |
openproject-queries/SKILL.md |
openproject_notifications |
openproject-notifications/SKILL.md |
openproject_admin |
openproject-admin/SKILL.md |
Python API Gotchas
list_*functions return generators → uselist(...)to convert- Time
hoursis ISO 8601 duration (e.g.,PT1H30M) → useparse_duration() update_work_package()auto-fetcheslockVersionif not providedget_schema()requires bothproject_idANDtype_id