Loading...
Loading...
OpenProject API v3 integration for project management. Manage projects, work packages, time entries, documents, users, notifications, queries. Use when user needs to interact with OpenProject instance - create/update work packages, track time, manage projects, query data, handle documents and attachments.
npx skill4agent add hoangvantuan/claude-plugin openproject| Skill | Purpose | Package |
|---|---|---|
| Base client, auth, HAL parsing | |
| Project CRUD | |
| Tasks, issues, features | |
| Time tracking | |
| User management | |
| Files & wiki | |
| Saved queries | |
| Notifications | |
| System config | |
# 1. Navigate to skill directory
cd .claude/skills/openproject
# 2. Install dependencies
uv sync
# 3. Configure .env
OPENPROJECT_URL=https://your-instance.com
OPENPROJECT_API_KEY=your-api-key.openproject-config.ymlcd .claude/skills/openproject
uv run python -c "
from openproject_core import init_config, print_config_summary
from dotenv import load_dotenv
load_dotenv()
init_config(PROJECT_ID) # Thay PROJECT_ID bằng ID số của project
print_config_summary()
"cd .claude/skills/openproject
uv run python -c "
from openproject_core import refresh_config, print_config_summary
from dotenv import load_dotenv
load_dotenv()
refresh_config()
print_config_summary()
"from openproject_core import (
load_config, # Load toàn bộ config
require_config, # Load config, raise error nếu chưa init
get_project_id, # Lấy project ID đã config
get_type_id, # Lấy type ID theo tên: get_type_id("Task") → 1
get_status_id, # Lấy status ID theo tên: get_status_id("New") → 1
get_priority_id, # Lấy priority ID theo tên: get_priority_id("Normal") → 8
get_version_id, # Lấy version ID theo tên
get_custom_field_name, # Lấy tên custom field: get_custom_field_name("customField8", 1) → "Excute Point"
is_config_initialized, # Kiểm tra config đã init chưa
)require_config()is_config_initialized()cd .claude/skills/openproject
uv run python -c "
from openproject_core import load_session_config
from dotenv import load_dotenv
load_dotenv()
session = load_session_config()
if not session['ok']:
print(f'ERROR: {session[\"error\"]}')
print('Run init_config(project_id) to initialize!')
else:
print(f'Project: {session[\"project\"]} (ID: {session[\"project_id\"]})')
print(f'User: {session[\"user\"]} @ {session[\"instance\"]}')
print(f'Config updated: {session[\"updated_at\"]}')
print(f'Types: {session[\"types_count\"]}, Members: {session[\"members_count\"]}')
"ok=Falseinit_config(project_id)ok=Trueload_session_config()ok=Falseinit_config(project_id)uv run pythonload_dotenv()get_type_id()get_status_id()paginate()# ❌ WRONG - project name không phải identifier
project = get_project('sol-proj-25001') # 404 Error!
# ✅ CORRECT - tìm project trước để lấy đúng identifier hoặc ID
for p in list_projects():
if 'sol-proj-25001' in p['name']:
project_id = p['id'] # ID số: 3
identifier = p['identifier'] # '008-mii-pb-mh008'
break
project = get_project(project_id) # Works!nameidentifierlist_projects()get_project()list_*# ❌ WRONG - generator has no len()
entries = list_time_entries(filters=filters)
print(len(entries)) # TypeError!
# ✅ CORRECT - convert to list first
entries = list(list_time_entries(filters=filters))
print(len(entries)) # Works!list_projectslist_work_packageslist_time_entrieslist_userslist_notificationslist_querieshours# ❌ WRONG - hours is 'PT1H30M45S', not 1.5
hours = entry['hours']
total += hours # TypeError!
# ✅ CORRECT - use parse_duration()
from openproject_time import parse_duration
hours = parse_duration(entry['hours']) # 1.5125
total += hours # Works!# ❌ WRONG - filter work_package không tồn tại
filters = [{'work_package': {'operator': '=', 'values': ['123']}}]
# ✅ CORRECT - dùng entity_type + entity_id
from openproject_time import get_work_package_time, get_work_packages_time
# Cho 1 WP
entries = get_work_package_time(wp_id=675)
# Cho nhiều WPs (1 API call)
result = get_work_packages_time(wp_ids=[675, 598, 577])
# Hoặc filter trực tiếp
filters = [
{"entity_type": {"operator": "=", "values": ["WorkPackage"]}},
{"entity_id": {"operator": "=", "values": ["675"]}}
]entity_typeentity_idproject_iduser_idspent_onactivity_idongoingcreated_atupdated_atget_work_packages_time()# ❌ WRONG - result is dict, not list
result = get_work_packages_time(wp_ids=[675, 598, 577])
for entry in result[:5]: # KeyError!
print(entry)
# ✅ CORRECT - iterate over dict items
result = get_work_packages_time(wp_ids=[675, 598, 577])
# result = {675: [entries...], 598: [entries...], 577: [entries...]}
for wp_id, entries in result.items():
for entry in entries:
hours = parse_duration(entry['hours'])
print(f'WP {wp_id}: {hours}h')Dict[int, List[dict]]get_schema()project_idtype_id# ❌ WRONG - missing type_id
schema = get_schema(project_id=3) # TypeError!
# ✅ CORRECT - provide both params
schema = get_schema(project_id=3, type_id=6) # type 6 = User Story
# Get custom field names
for key, val in schema.items():
if key.startswith('customField') and isinstance(val, dict):
print(f'{key}: {val.get("name")}')
# Output:
# customField10: Research Point
# customField8: Excute Point
# customField9: Verify Point
# customField15: Review Point1610list_types()# Custom fields vary by project and type
# Always use get_schema() to discover field names
from openproject_work_packages import get_schema, list_work_packages
# 1. Get schema to know custom field mapping
schema = get_schema(project_id=3, type_id=6)
cf_names = {k: v.get('name') for k, v in schema.items()
if k.startswith('customField') and isinstance(v, dict)}
print(cf_names)
# {'customField10': 'Research Point', 'customField8': 'Excute Point', ...}
# 2. Then access custom fields in work packages
for wp in list_work_packages(project_id=3):
research = wp.get('customField10') or 0
execute = wp.get('customField8') or 0list_activities()# ❌ May return empty
from openproject_time import list_activities
activities = list(list_activities()) # []
# ✅ Use work package activities for comments/history
from openproject_work_packages import list_activities
activities = list(list_activities(work_package_id=675))uv runcd .claude/skills/openproject
uv run python -c "YOUR_CODE"from openproject_core import check_connection
from openproject_projects import list_projects
from dotenv import load_dotenv
load_dotenv() # Required!
# Your code here
status = check_connection()
print(f"Connected as: {status['user']}")from openproject_core import (
# Connection
check_connection, # Verify API connection
OpenProjectClient, # HTTP client class
# Session (REQUIRED - call first each session!)
load_session_config, # Load & verify config for session
# Config (init once, use helpers)
init_config, # Init config: init_config(project_id)
load_config, # Load full config from YAML
refresh_config, # Refresh/update config
require_config, # Load config, raise if not init
is_config_initialized, # Check if config exists
get_project_id, # Get configured project ID
get_type_id, # Get type ID by name
get_status_id, # Get status ID by name
get_priority_id, # Get priority ID by name
get_version_id, # Get version ID by name
get_member_id, # Get user ID by member name (partial match)
get_member_name, # Get member name by user ID
get_custom_field_id, # Get custom field key by name
get_custom_field_name, # Get custom field name by key
print_config_summary, # Print human-readable config
# Helpers
build_filters, # Build filter JSON
build_sort, # Build sort JSON
paginate, # Auto-paginate results
extract_id_from_href, # Extract ID from HAL href
)from openproject_projects import (
list_projects, # List all projects
get_project, # Get by ID or identifier
create_project, # Create new project
update_project, # Update project
delete_project, # Delete project
copy_project, # Copy project structure
get_versions, # Get project versions
get_categories, # Get project categories
get_types, # Get available types
toggle_favorite, # Star/unstar project
)from openproject_work_packages import (
list_work_packages, # List with filters
get_work_package, # Get by ID
create_work_package, # Create task/issue
update_work_package, # Update fields (auto-handles lockVersion)
delete_work_package, # Delete
get_schema, # Get form schema
list_activities, # Get comments/history
add_comment, # Add comment
list_relations, # Get relations
create_relation, # Create relation
delete_relation, # Delete relation
)from openproject_time import (
list_time_entries, # List with filters (use entity_type+entity_id for WP)
get_time_entry, # Get by ID
create_time_entry, # Create entry
update_time_entry, # Update entry
delete_time_entry, # Delete entry
log_time, # Shortcut for create
list_activities, # Available activities
get_user_time_today, # User's today entries
get_work_package_time, # Single WP's time entries
get_work_packages_time,# Multiple WPs (1 API call)
parse_duration, # Parse ISO 8601 duration to hours
)from openproject_users import (
list_users, # List users
get_user, # Get by ID
get_current_user, # Get current user
create_user, # Create/invite user
update_user, # Update user
delete_user, # Delete user
lock_user, # Lock account
unlock_user, # Unlock account
list_groups, # List groups
get_group, # Get group
create_group, # Create group
add_member, # Add to group
remove_member, # Remove from group
list_memberships, # List project memberships
create_membership, # Add to project
delete_membership, # Remove from project
)from openproject_documents import (
get_attachment, # Get attachment metadata
list_attachments, # List container attachments (NOT documents!)
download_attachment, # Download file
upload_attachment, # Upload file
delete_attachment, # Delete attachment
list_documents, # List all documents (read-only API)
get_document, # Get document
get_wiki_page, # Get wiki page
update_wiki_page, # Update wiki page
)
# NOTE: Documents API is read-only. Create/delete via web UI only.from openproject_queries import (
list_queries, # List saved queries
get_query, # Get query config
create_query, # Create query
update_query, # Update query
delete_query, # Delete query
star_query, # Add to favorites
unstar_query, # Remove from favorites
get_query_default, # Get default query
get_available_columns,# Get column options
)from openproject_notifications import (
list_notifications, # List all
get_notification, # Get by ID
mark_read, # Mark as read
mark_unread, # Mark as unread
mark_all_read, # Mark all read
get_unread_count, # Count unread
list_unread, # List unread only
list_by_reason, # Filter by reason
)from openproject_admin import (
get_configuration, # System config
list_statuses, # All statuses
get_status, # Status details
list_open_statuses, # Open statuses only
list_closed_statuses, # Closed statuses only
list_priorities, # All priorities
get_priority, # Priority details
get_default_priority, # Default priority
list_types, # WP types
get_type, # Type details
list_project_types, # Project-specific types
list_roles, # All roles
get_role, # Role with permissions
)cd .claude/skills/openproject
uv run python -c "
from openproject_core import check_connection
from dotenv import load_dotenv
load_dotenv()
status = check_connection()
print(f'OK: {status[\"ok\"]}, User: {status[\"user\"]}')
"cd .claude/skills/openproject
uv run python -c "
from openproject_projects import list_projects
from dotenv import load_dotenv
load_dotenv()
for p in list_projects():
print(f'{p[\"id\"]}: {p[\"name\"]}')
"cd .claude/skills/openproject
uv run python -c "
from openproject_work_packages import create_work_package
from dotenv import load_dotenv
load_dotenv()
wp = create_work_package(project_id=5, subject='New task', type_id=1)
print(f'Created: #{wp[\"id\"]}')
"cd .claude/skills/openproject
uv run python -c "
from openproject_time import log_time
from dotenv import load_dotenv
load_dotenv()
entry = log_time(work_package_id=123, hours=2.5, comment='Dev work')
print(f'Logged: {entry[\"id\"]}')
"cd .claude/skills/openproject
uv run python -c "
from openproject_work_packages import list_work_packages
from dotenv import load_dotenv
load_dotenv()
# Filter: open status
filters = [{'status': {'operator': 'o', 'values': []}}]
for wp in list_work_packages(filters=filters):
print(f'#{wp[\"id\"]}: {wp[\"subject\"]}')
"| Skill | SKILL.md | API Reference |
|---|---|---|
| Core | | |
| Projects | | |
| Work Packages | | |
| Time | | |
| Users | | |
| Documents | | |
| Queries | | |
| Notifications | | |
| Admin | | |
spec.yml