mcpField
C
cawplan-my-work

cawplan-my-work

github.com/cawcutProductivity1131 installsUpdated 2d ago
Repository

About cawplan-my-work

A skill for querying and organizing personal CawPlan work, for users tracking todos, critical issues, and ticket status changes. It supports project-level scoping and provides checks for status changes, reopens, and linked code references.

Key features

  1. 01Group todos by product line, product, and version
  2. 02Review personal critical issues
  3. 03Filter open tickets by status category
  4. 04Verify ticket status changes and reopens
  5. 05Find linked PRs and commits

Use cases

  1. 01Review personal todos within a specific version
  2. 02Sort open tickets by priority
  3. 03Summarize ticket status changes for a date
  4. 04Find tickets with PRs or commits but no status update

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/cawcut/skill-cawplan --skill cawplan-my-work

After installing, type/cawplan-my-workin Claude Code to confirm it loaded.

Bundled filesreferences/QUERY_RESILIENCE.md

Details

From the project README

CawPlan My Work

Bootstrap

cawplan skill check

Workflow

  1. Resolve your own user_id — this is decoded from your local access token, no network call needed:

    cawplan auth status
    

    Read the User ID: line from the output. If it's missing, re-authenticate (cawplan auth login, show the printed URL to the user, then cawplan auth login --device-auth --complete once they approve) rather than falling back to cawplan users query --email — that would spend a network call resolving something auth status should already have.

  2. Fetch your todos:

    cawplan todos user <user_id>
    

    This returns tickets (grouped by product_line → product → version), critical_issues (grouped by product_line → product), and summary. No status filter is applied by default — the response includes everything assigned to you, not just open items.

  3. If the user named a specific project/version, narrow tickets to that exact product → version leaf. critical_issues has no version dimension (only product_line → product), so it can't be narrowed to the same granularity — when the user named a version, narrow critical_issues to the matching product only, and say explicitly that these critical issues are product-wide and not confirmed to be specific to the named version. If the named project/version doesn't appear anywhere in tickets, say so explicitly ("no tickets found for you under ") rather than falling back to showing everything.

  4. If the user asks for only open/未完成 items, resolve status categories for every distinct product line present in the response and filter properly — this is your own work, so it's realistically a handful of lines, not worth shortcutting:

    cawplan product-lines statuses <product_line_id>   # once per distinct product line in the response
    

    Exclude tickets whose status key maps to category COMPLETE or CANCELED. Only fall back to "just show every item's status clearly instead, let the user judge" if this turns out to span more product lines than is reasonable to resolve (rare for one person's own work) — and say explicitly that's what you're doing rather than silently presenting an unfiltered list as if it were filtered.

  5. Priority-sorted flat list (only when the user asks for "my open tickets by priority" / sorted-by-priority framing, rather than a project/version breakdown): flatten tickets across every product line/product/version into one list. This framing implies open-only even if not stated explicitly — run step 4's filtering for it. Then sort CRITICAL → HIGH → MEDIUM → LOW. Still show which product/version each ticket belongs to per row — flattening the grouping for sort order doesn't mean dropping that context.

5a. My task completion / status-change summary for a day or range (only when the user asks “帮我总结今天的任务完成情况”, “今天哪些任务状态变更了”, or equivalent): this is not the current-todos view in step 2. Default the window to today; honor an explicit date/range.

cawplan tickets search --assignees <user_id> --start_date 2000-01-01 --end_date <today> --updated_start_date <window_start> --updated_end_date <today> --page_size 100 --page_num 1

Page through fully using total. The updated_at window supplies candidates only: a Parent Ticket can be refreshed because a Sub-ticket changed, even when the Parent's own status did not. Then fetch the candidates' status changes in bulk, at most 50 IDs per call:

cawplan tickets changes --unique_ids <candidate_ids_csv> --fields status --start_date <window_start> --end_date <window_end>

Every returned event is a real status change inside the window (at, old → new, new_category). Keep a Ticket only if it has at least one event. Do not use updated_at as final evidence. Report each Ticket once, using its latest in-window event; an unchanged Parent Ticket has no event and is excluded even if a child transition refreshed its record.

Fallback (only if tickets changes is unavailable, see references/QUERY_RESILIENCE.md): for every candidate, fetch cawplan tickets history <product_id> <version_id> <ticket_id> and keep a Ticket only if an UPDATED entry contains changed_fields.status (a new-status string or an {old, new} object) with created_at in the window. CREATED is not a status change.

  1. My reopened tickets (only when the user asks about reopened tickets / why something got reopened): there's no REOPENED status category (only UNSTARTED/STARTED/TESTING/COMPLETE/CANCELED) — reopening shows up as a status key whose name says so, or as a history transition backward out of a terminal category. History-scanning (bullet 2) is always the ground truth; the status-key check (bullet 1) is only a shortcut for the common case where a ticket is currently sitting on the reopen status — it does not replace history-scanning.

    • Find reopens with the shared definition and command in references/QUERY_RESILIENCE.md ("Reopens"), checking every one of your tickets regardless of current status: scope the call with --unique_ids <ticket_ids_csv> (at most 50 IDs per call) and default to the last 90 days (--start_date <today-89d> --end_date <today>) — say so, and add earlier 90-day windows only if the user asks about older reopens. If the user asks about one specific ticket whose change could not be classified, re-run without the two category filters and read its events in order. Fallback (only if tickets changes is unavailable): cawplan tickets history <product_id> <version_id> <ticket_id> per ticket.
    • As a labeling aid only, resolve each distinct product line's statuses (cawplan product-lines statuses <product_line_id>) to check whether the ticket's status right after a reopen transition has "reopen" in its display_name — if so you can call it out as "reopened" by name in the report; if not (e.g. it went straight back to in_progress or TESTING), it's still a reopen per the history transition, just report the actual status name instead of assuming there's a dedicated label for it.
    • For each reopen event, report the timestamp and actor from that history entry if present, and the reason: use the history entry's own comment if the API returns one on status-change events and it's plausibly about that specific transition (a general free-text comment field that isn't tied to the transition shouldn't be presented as if it explains the reopen); otherwise fall back to the ticket's progress_comment and label it explicitly as "latest progress note, not necessarily the reopen reason" rather than presenting it as if it directly explains the reopen. If neither exists, say the reason wasn't recorded — do not infer a reason from the ticket title or description. If the change lookup fails for a ticket, list it as "not checked" (a partial result, see references/QUERY_RESILIENCE.md), not as "no reopen found" and not as evidence of a missing reason.
  2. My tickets' linked repo PRs/commits (only when asked — "today's tickets with their PR/commits", "整理我当天任务涉及的tickets和PR/commit"): tickets carry a links[] array that can hold GitHub PR/commit URLs (shape documented in references/CAWPLAN_OPEN_API.md under "VersionTicket fields of note") — todos/poll don't return this field, only the full ticket record does, so this step uses tickets search instead of steps 1-6's todos call.

    cawplan tickets search --assignees <user_id> --start_date 2000-01-01 --end_date <today> --updated_start_date <date> --updated_end_date <date> --page_size 100 --page_num 1
    

    Default <date>-<date> to today for both --updated_start_date/--updated_end_date unless the user asked for a different day/range; treat the end date as inclusive of the whole day unless a result set proves otherwise. Use --updated_start_date/--updated_end_date, not --start_date/--end_date, for "today's tickets" — the latter filter ticket creation time (confirmed against example-backend's DAO, see references/CAWPLAN_OPEN_API.md), so a ticket created last week that you're actively working on today would be silently missed. --start_date/--end_date still has to be passed (the endpoint requires a created_at window or --time_range) — pin it to the maximal-window workaround (2000-01-01 to today) so it doesn't itself narrow the result. platform on a link isn't a reliable fixed value — the same manually-added GitHub link can show up as platform: "LINK" — so classify by the url itself: contains /pull/ → PR, contains /commit/ → commit, otherwise report it as a plain link with its title. A ticket with an empty links array has no repo links; say so rather than omitting it from the report. Page through using the response's total/page_num/page_size fields (keep fetching while page_num * page_size < total) rather than assuming one page of 100 covers everything.

  3. Ticket has a PR/commit linked but status hasn't moved (only when asked — "哪些ticket已经有PR/commit但状态还没更新"): reuse step 7's fetch mechanism and pagination rule, adding --status_categories UNSTARTED,STARTED. Scope: if the user names a product/version, use --product_ids/--version_ids in place of --assignees; if they explicitly say "my"/自己的, use --assignees <user_id>. If they specify neither, default to your own tickets (--assignees <user_id>) and say so. Use --start_date 2000-01-01 --end_date <today> because stale tickets may not be recent.

    • A ticket "has a PR/commit" when any of its links has a url containing /pull/ or /commit/ — either one counts, since an open PR (not yet merged into a commit reference) is just as much a sign of active code work as a bare commit link.
    • Report each qualifying ticket with the PR/commit link(s) found (and whether each is a PR or a commit, same classification as step 7) and its current status, so the user can judge whether the ticket genuinely needs a status bump.

Output

  • Group by product line → product → version, matching the API's own grouping — don't re-flatten it into one undifferentiated list, unless step 5 ran, in which case present the single priority-sorted list instead (still showing product/version per row).
  • For each ticket: display ID, type, priority, status, one-line title.
  • Critical issues: separate section, grouped by product line → product, with severity/status.
  • Lead with summary if the response includes one and step 3 didn't narrow the scope — summary describes the full unnarrowed response, so showing it alongside a narrowed list would contradict what's actually listed. When narrowed, state counts for the narrowed slice instead (e.g. "1 ticket, 1 product-wide critical issue for UniFi Access 4.1.10").
  • If step 3 narrowed the scope, say what it was narrowed to before listing results.
  • If there's genuinely nothing assigned, say so plainly rather than returning an empty section with no comment.
  • If any lookup, page or batch could not be completed, say what was verified and what was not before the list (references/QUERY_RESILIENCE.md). Write the answer by the rules in references/QUERY_RESILIENCE.md §5: no CLI commands, internal field names or reasoning text.
  • If step 6 ran: one entry per reopened ticket (display ID, title, reopened-at, reopened-by if known, reason or "not recorded"). If none of your tickets were reopened, say so explicitly rather than showing an empty list.
  • If step 7 ran: one entry per ticket in the fetched window, its PRs/commits/other links (or "no repo links"); note the date-field assumption once, not per ticket.
  • If step 8 ran: one entry per qualifying ticket — display ID, title, current status, and the PR/commit link(s) that triggered the flag. If none qualify, say so explicitly.
  • If step 5a ran: list only history-verified status changes, with display ID, title, old → new status when available, change timestamp, and whether the new status is terminal. State that unchanged Parent Tickets are intentionally excluded.

References

  • references/CAWPLAN_OPEN_API.md
  • references/QUERY_RESILIENCE.md

Comments

Markdown supported