agentskills.codes
WO

working-summary

Use when the user asks for a work summary, weekly report, 工作总结,周报,working summary, or sprint/period recap. Aggregates GitHub PR/commit/issue activity from configured repos, optionally reads Linear cycle issues via MCP, honors Chinese public holidays, and produces a markdown report. Default range is

Install

mkdir -p .claude/skills/working-summary && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/16248" && unzip -o skill.zip -d .claude/skills/working-summary && rm skill.zip

Installs to .claude/skills/working-summary

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Use when the user asks for a work summary, weekly report, 工作总结,周报,working summary, or sprint/period recap. Aggregates GitHub PR/commit/issue activity from configured repos, optionally reads Linear cycle issues via MCP, honors Chinese public holidays, and produces a markdown report. Default range is the previous Mon-Sun week.
326 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)

About this skill

Working Summary

Generate a period work summary by aggregating GitHub PR/commit activity across configured repositories and — optionally — Linear cycle issues. The default time range is the previous Mon–Sun week, computed with awareness of Chinese public holidays. Output is markdown, suitable for Obsidian or any note system.

Config

Config path (default): ~/.config/working-summary/config.yaml Override via --config <path>.

If the file is missing, tell the user to copy config.example.yaml (next to this skill) into the expected path and edit. Do not fabricate defaults.

github:
  user: innei # optional; falls back to `gh api user -q .login`
  orgs: # org-scope query — ONE gh search call per org
    - lobehub
    - lobehub-biz
  repos: # optional explicit repos (in addition to orgs)
    - innei/next-real-comment
    - mx-space/core
  include_commits: true # pull per-repo commits for active repos
linear: # optional, needs `linear` CLI authed
  workspace: lobehub # informational
  team: LOBE # team key (issue prefix)
  cycle: auto # previous | current | auto
  include_states: [In Progress, Done]
output:
  # Language for synthesized prose. Section headers and raw PR/issue/commit
  # titles are kept verbatim regardless; only descriptions and framing prose
  # follow this setting. Examples: zh-CN, en, ja
  language: zh-CN
  # Optional persistence target. When set, the user may choose to save the
  # report to `dir` at the end of a run. Leave unset to operate ephemerally.
  dir: ~/Documents/Obsidian/Reports
  # Placeholders: {year} {month} {week} {start} {end} {ext}
  filename: '{year}-{month}-w{week}.{ext}'

Output Flow

The skill never writes a file by default. It synthesizes markdown in the conversation (which serves as the terminal display) and then asks the user whether to persist the result.

At the end of synthesis, prompt the user with these options:

ChoiceBehavior
no / nothingDone. Report lives only in the conversation.
mdWrite markdown to output.dir/{filename} (ext=md).
htmlRender themed HTML to $TMPDIR/working-summary-<stamp>.html via scripts/render_html.py, run open on it, then ask whether to also move a copy to output.dir/{filename} (ext=html).
bothDo md and html in that order.

Default choice from config: when output.format is set in the config file, use it as the highlighted default in the prompt (e.g. format: html → "落盘否?[html / md / both / no]"). The user can still override by typing another choice. When output.format is unset or is markdown, highlight md as default. When output.format is both, highlight both.

The HTML renderer is a deterministic post-processor — the LLM only ever produces markdown. See HTML Rendering below.

Never overwrite an existing file silently. If the target exists, ask the user (append, overwrite, or new suffix).

Default Time Range

The skill uses a previous Mon–Sun week as the default:

Today isRange
Mon[last Mon, yesterday Sun]
Tue..Sat[prev Mon, prev Sun]
Sun[prev Mon, prev Sun] (not this Sun)

Explicit overrides:

  • --from YYYY-MM-DD --to YYYY-MM-DD — hard range
  • --from YYYY-MM-DD — start from date, end at today
  • --date YYYY-MM-DD — pretend today is this date, then apply default rule

Chinese public holidays

scripts/compute_range.py uses the chinesecalendar Python library (loaded via uv --with chinesecalendar) to classify each day as workday / holiday. The orchestrator always emits a range.breakdown containing {date, weekday, workday, holiday} for every day, plus aggregated workdays / holidays counts. Use this data to:

  • Annotate the report header (e.g. "本周 3 工作日、2 节假日")
  • Decide whether the range is meaningful at all (if workdays == 0, ask the user whether they want the previous working week instead)

Data Collection

Step 1 — run the orchestrator

python skills/automation/working-summary/scripts/collect.py \
  [--config PATH] \
  [--from YYYY-MM-DD --to YYYY-MM-DD | --date YYYY-MM-DD]

Returns JSON to stdout:

{
  "range": { "start": "...", "end": "...", "workdays": N, "holidays": N, "breakdown": [...] },
  "config": { "author": "...", "orgs": [...], "repos": [...], "include_commits": true, "linear": {...}, "output": {...} },
  "github": {
    "owner/repo": {
      "prs_merged":  [...],  // reconstructed from commit (#NNN) refs → /repos/{r}/pulls/{n}
      "prs_open":    [...],  // /repos/{r}/pulls?state=open, filtered by author + updated window
      "commits":     [...],  // /repos/{r}/commits?author=&since=&until=
      "issues":      [...]   // /repos/{r}/issues?assignee=&since=, PRs filtered out
    }
  }
}

Why REST instead of gh search — the previous version used gh search prs/issues for org-wide queries. That index is unreliable: private orgs are unindexed entirely, and even public mono-repos return partial results (one test run showed 1/27 merged PRs hit). The current flow:

  1. GET /orgs/{org}/repos — page through every repo (incl. private), then merge with explicit repos.
  2. Per-repo GET /repos/{r}/commits?author=...&since/until — concurrent (16 workers). Commits filtered by GIT author + merge date window. Empty repos (HTTP 409) and archived repos (404) are silently skipped.
  3. Merged PRs are reconstructed from commit message refs: every (#NNN) in a commit message becomes a GET /repos/{r}/pulls/{n} call. Because commit dates are merge dates, these PRs are guaranteed merged in window.
  4. For "active" repos (had commits) plus explicit repos, fetch open PRs (/pulls?state=open) and assigned issues (/issues), filter by author + updatedAt client-side.

Set github.include_commits: false to skip steps 2-3 entirely (only open PRs / issues on the explicit repo list).

Step 2 — Linear (optional, via linear CLI)

When config.linear.team is set, collect.py invokes scripts/fetch_linear.py which shells out to linear api (the GraphQL endpoint of @schpet/linear-cli). Requires linear auth login once.

  1. Resolve viewer.id via { viewer { id } }.
  2. Resolve the target cycle for linear.team per linear.cycle:
    • previous — most recently completed cycle (endsAt <= today, max endsAt)
    • current — cycle whose [startsAt, endsAt) contains today
    • auto — cycle whose [startsAt, endsAt] overlaps the computed range (max overlap wins)
  3. Query issues(filter: { team, cycle, assignee = viewer }) with optional state filter from linear.include_states.
  4. Each issue carries attachments — GitHub PR/commit URLs are exposed there, enabling PR ↔ issue linking without text matching.

The script returns null (silent) when:

  • the linear binary is missing,
  • the user is not authenticated,
  • the cycle cannot be resolved.

In any of those cases, the report continues with GitHub-only output and must note that Linear was skipped.

In addition to the report cycle (resolved against the date range), the script also fetches the active cycle (the one containing today) and pulls only its started issues. For the typical "previous Mon-Sun" weekly report these are different cycles — the report cycle is the cycle that just ended, the active cycle is what the user is currently working on. When the two happen to be the same cycle, the in-progress slice is filtered from the already-fetched issues with no extra round-trip.

{
  "linear": {
    "team": "LOBE",
    "viewer_id": "...",
    "cycle": { "number": 9, "name": "...", "startsAt": "...", "endsAt": "...", "progress": 0.37 },
    "issues": [
      {
        "identifier": "LOBE-6603",
        "title": "...",
        "state": "Done",
        "stateType": "completed",
        "priority": 1,
        "priorityLabel": "Urgent",
        "labels": ["🐛 Bug", "Improvement"],
        "url": "https://linear.app/.../LOBE-6603",
        "completedAt": "...",
        "attachments": [
          { "url": "https://github.com/.../pull/13481", "title": "...", "sourceType": "github" }
        ]
      }
    ],
    "in_progress": {
      "cycle": { "number": 10, "name": "2026.04 W2", ... },
      "issues": [ /* same shape as above; only state.type == "started" */ ]
    }
  }
}

The report's "Linear cycle snapshot" section MUST surface in_progress.issues under a sub-heading like "本周仍在进行(active cycle #N)" so the user sees both retrospective Done items and forward-looking work in one place. Skip the sub-heading when in_progress.issues is empty.

Step 3 — noise filter

Drop the following from Highlights (they may still appear under a collapsible "Chore" section if substantial):

  • i18n / locale-only sync
  • Submodule bumps, lockfile-only updates
  • Formatting-only, single-line config tweaks

Substantive work (features, non-trivial fixes, infra, security) always appears in Highlights.

Report Synthesis

Synthesize markdown from


Content truncated.

Search skills

Search the agent skills registry