Manage OpenProject time entries via API v3. Operations: list, create, update, delete time entries. Log work hours on work packages with activity types, comments. Supports filtering by user, project, work package, date range. Use when tracking time, generating time reports, or managing logged hours.
Resources
3Install
npx skillscat add hoangvantuan/claude-plugin/openproject-time Install via the SkillsCat registry.
SKILL.md
OpenProject Time Tracking
Manage time entries in OpenProject.
Prerequisites
- Environment:
OPENPROJECT_URL,OPENPROJECT_API_KEYin.env - Log time permission in project
Package: openproject_time
⚠️ IMPORTANT: list_time_entries() returns a generator, not a list!
- Use
list()to convert if you needlen()or multiple iterations - Example:
entries = list(list_time_entries(filters=...))
⚠️ IMPORTANT: hours field returns ISO 8601 duration, not a number!
- Format:
PT1H30M45S= 1 hour, 30 minutes, 45 seconds - Use
parse_duration()to convert to decimal hours - Example:
parse_duration('PT1H30M') → 1.5
⚠️ IMPORTANT: get_work_packages_time() returns Dict, not list!
- Return type:
Dict[int, List[dict]]- key là WP ID, value là list entries - Iterate with
.items():for wp_id, entries in result.items()
⚠️ IMPORTANT: list_activities() may return empty!
- Global activities often empty, activities are project-specific
- Use
openproject_work_packages.list_activities(wp_id)for WP comments/history
Functions:
list_time_entries(filters)- List with filters (returns generator)get_time_entry(id)- Get single entrycreate_time_entry(work_package_id, hours, **kwargs)- Log timeupdate_time_entry(id, **kwargs)- Update entrydelete_time_entry(id)- Delete entrylog_time(work_package_id, hours, **kwargs)- Shortcut for createlist_activities()- Get activity typesget_user_time_today(user_id)- User's today entriesget_work_package_time(wp_id)- Single WP's time entries (returns list)get_work_packages_time(wp_ids)- Multiple WPs, returnsDict[int, List]keyed by WP IDparse_duration(str)- Parse ISO 8601 duration to decimal hours
Usage
Always run from skill directory with uv run:
cd .claude/skills/openproject
uv run python -c "YOUR_CODE"Examples
from openproject_time import (
log_time, list_time_entries, list_activities,
get_user_time_today, parse_duration
)
from dotenv import load_dotenv
load_dotenv()
# Log 2 hours on work package
entry = log_time(
work_package_id=123,
hours=2.0,
activity_id=1, # Development
comment="Implemented login feature",
spent_on="2026-01-12"
)
print(f"Logged: {entry['id']}")
# List time entries and convert hours to decimal
for entry in list_time_entries(filters=[
{"user": {"operator": "=", "values": ["me"]}},
{"spent_on": {"operator": ">t-", "values": ["7"]}}
]):
# hours is ISO 8601 duration (e.g., 'PT1H30M45S')
hours = parse_duration(entry['hours'])
print(f"{hours:.2f}h - {entry.get('comment', '')}")
# Get activity types
for activity in list_activities():
print(activity["name"])
# Calculate total hours for today
total = sum(parse_duration(e['hours']) for e in get_user_time_today("me"))
print(f"Total today: {total:.2f}h")Lấy time entries theo Work Package
Dùng entity_type + entity_id filters (không phải work_package):
from openproject_time import (
get_work_package_time, # Cho 1 WP
get_work_packages_time, # Cho nhiều WPs
parse_duration
)
# Lấy time cho 1 work package
entries = get_work_package_time(wp_id=675)
hours = sum(parse_duration(e['hours']) for e in entries)
print(f"Total: {hours:.2f}h")
# Lấy time cho nhiều work packages (1 API call)
result = get_work_packages_time(wp_ids=[675, 598, 577])
for wp_id, entries in result.items():
hours = sum(parse_duration(e['hours']) for e in entries)
print(f"WP #{wp_id}: {hours:.2f}h")
# Hoặc filter trực tiếp
filters = [
{"entity_type": {"operator": "=", "values": ["WorkPackage"]}},
{"entity_id": {"operator": "=", "values": ["675", "598"]}}
]
entries = list(list_time_entries(filters=filters))References
references/time-api.md- Full API details