From moonkit
Work journal, performance report, and resume builder. Collects activity from GitHub, Slack, Jira, Google Calendar, and Notion — generates structured outputs. Three modes: journal (chronological activity log + insights), report (6 business-value categories + impact tagging + TOP 5 + Executive Summary), resume (13 competency perspectives + scoring + rewriting suggestions). Maintains a brag document. Trigger: "/work-log", "업무일지", "work log", "성과 보고", "성과 정리", "이력서 업데이트", "resume update", "뭐했지", "what did I do"
How this skill is triggered — by the user, by Claude, or both
Slash command
/moonkit:work-logThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
**Preamble — run this FIRST before any skill logic:**
Preamble — run this FIRST before any skill logic:
# Find moonkit root via symlink resolution
_MK_DIR=$(cd "$(dirname "$(readlink ~/.claude/skills/work-log 2>/dev/null || readlink .claude/skills/work-log 2>/dev/null || echo .)")/.." 2>/dev/null && pwd) || true
[ -n "$_MK_DIR" ] && _UPD=$("$_MK_DIR/bin/moonkit-update-check" 2>/dev/null || true) && [ -n "$_UPD" ] && echo "$_UPD"
If the output shows UPGRADE_AVAILABLE <old> <new>:
$_MK_DIR/bin/moonkit-upgradeecho $(( $(date +%s) + 86400 )) > ~/.moonkit/update-snoozeIf preamble produces no output, proceed normally.
Three modes:
When the user types /work-log, run this skill.
/work-log — interactive mode & period & source selection/work-log last — previous full week journal/work-log 2026-01-01 2026-03-22 — custom date range journal/work-log Q1 — current year Q1 journal/work-log H1 — current year first half (Jan~Jun)/work-log report — this week's performance report/work-log report Q1 — Q1 performance report/work-log report 2025-07-01 2025-12-31 — custom range report/work-log resume — this week's resume preparation/work-log resume H1 — H1 resume summary/work-log setup — re-run first-time setup wizardAppend --html to any command to also generate a styled HTML version:
/work-log report Q1 --html/work-log resume H1 --html/work-log --html (interactive mode — asks as usual, HTML output included)Parse $ARGUMENTS to determine:
report (anywhere in args) → report moderesume (anywhere in args) → resume modeQ1, last, dates) → journal modelast, Q1-Q4, H1/H2 from arguments. If no period argument is provided, ask interactively (see Phase 0 Step 3). Do NOT silently default to current week.--html is present in args, set html_output = true. Also check html_output in config. The flag overrides config (flag present = true). In interactive mode, ask via Question 4 in Step 2.5.cat ~/.work-log/config.yaml 2>/dev/null || cat ~/.weekly-log/config.yaml 2>/dev/null || echo "CONFIG_NOT_FOUND"
Supports both ~/.work-log/ and legacy ~/.weekly-log/ paths.
If CONFIG_NOT_FOUND or arguments contain setup, run the First-Run Wizard.
Use AskUserQuestion calls:
First call (up to 3 questions):
Second call (scheduling): 4. Organize schedule: "organize 모드를 자동으로 실행할까요?" — options: "매주 자동 실행 (토요일 10시) (Recommended)", "수동으로만 실행", "커스텀 스케줄"
organize.schedule.enabled: true, cron: "0 10 * * 6"organize.schedule.enabled: falseGenerate ~/.work-log/config.yaml using the skill's config.example.yaml as template.
Only runs when $ARGUMENTS is empty AND interactive mode.
Use a single AskUserQuestion call with up to 4 questions to collect mode, period, sources, and organize submode at once:
Question 1 — Mode:
Question 2 — Period:
Question 3 — Sources:
enabled: true in config, pre-labeled with checkmarks. For example if all 5 are enabled:
Question 4 — HTML output:
html_output: true in config, default to "Markdown + HTML".--html flag was passed in arguments, skip this question and set html_output = true.In automated mode (scheduled task), skip this step — default to journal mode + current week + all enabled sources + config's html_output setting.
If AskUserQuestion is rejected but partial answers are visible in the rejection message:
If a period argument was provided, parse it directly:
last → previous Monday to SundayQ1~Q4 → quarter boundaries of current yearH1 → Jan 1 ~ Jun 30, H2 → Jul 1 ~ Dec 31If NO period argument was provided (interactive mode only), use AskUserQuestion to ask:
In automated mode (scheduled task), default to current week without asking:
DOW=$(date +%u)
WEEK_START=$(date -v-$((DOW-1))d +%Y-%m-%d) # macOS
WEEK_END=$(date +%Y-%m-%d)
OUTPUT_DIR=$(grep 'output_dir:' <config_path> | awk '{print $2}' | sed "s|~|$HOME|")
mkdir -p "$OUTPUT_DIR/journals" "$OUTPUT_DIR/snapshots" "$OUTPUT_DIR/impact-reports" "$OUTPUT_DIR/pending-resume-updates"
IMPORTANT: Use parallel sub-agents for data collection. Launch one Agent per enabled source (up to 5 agents: GitHub, Slack, Jira, Calendar, Notion) running in the background simultaneously. Each agent collects its source data and returns a structured summary. Wait for all agents to complete, then merge results for Phase 2.
This dramatically reduces total collection time — especially for long periods where each source may take 30-60 seconds.
Collect from each enabled source independently. If a source fails, log and continue.
For long periods (>2 weeks): First check for existing snapshots and journals in the output directory. Use them as primary data to avoid redundant API calls. Only collect fresh data for uncovered date ranges.
ls "$OUTPUT_DIR/snapshots/"*.json 2>/dev/null | sort
ls "$OUTPUT_DIR/journals/"*.md 2>/dev/null | sort
If existing data covers the requested period, read those files instead of re-collecting. If gaps exist, collect only for the missing date ranges.
Use gh CLI. Auto-detect username via gh api user --jq '.login'.
For short periods (≤4 weeks): query the full range at once.
For long periods (>4 weeks): split into monthly sub-ranges to avoid GitHub Search API limits (100 commits, 50 PRs per query). For example, a 6-month range becomes 6 monthly queries. Aggregate and deduplicate results across all sub-ranges.
For commit discovery, prefer gh search commits (works with private repos):
# Short period:
gh search commits --author={username} --author-date=">={START}" \
--json repository,sha,commit --limit 100
# Long period (repeat per month):
gh search commits --author={username} --author-date="{MONTH_START}..{MONTH_END}" \
--json repository,sha,commit --limit 100
For PRs:
gh search prs --author={username} --created=">={START}" \
--json repository,title,number,state,url,createdAt --limit 50
# Long period: use --created="{MONTH_START}..{MONTH_END}" per month
For reviews:
gh search prs --reviewed-by={username} --updated=">={START}" \
--json repository,title,number,state,url --limit 50
# Long period: use --updated="{MONTH_START}..{MONTH_END}" per month
Apply repos_include / repos_exclude filters from config.
Use slack_read_user_profile MCP (no params) → get user_id.
Then slack_search_public_and_private:
query: "from:<@{user_id}> after:{WEEK_START} before:{WEEK_END}"
limit: 20, sort: "timestamp", include_context: false
Apply channels_include/channels_exclude filters. Group by channel, extract topics.
Try Atlassian MCP first (getAccessibleAtlassianResources → searchJiraIssuesUsingJql).
JQL: assignee = currentUser() AND updated >= "{WEEK_START}"
Fall back to REST API if MCP unavailable.
Use gcal_list_events MCP. Filter: accepted, tentative, or organizer. Skip declined.
Extract: title, time, duration, attendee count.
Use notion-search MCP. Extract: title, URL, edit time.
API limitations to work around:
query must be non-empty (use a space if no keyword).created_date_range filter applies to creation date, but the returned timestamp is last edited time. These can diverge significantly.last_edited_time falls within the requested date range.Branch based on mode:
Journal mode runs Phase 2H (HTML, if enabled), Phase 3 (Brag Doc), Phase 4 (Resume Update), Phase 5 (Snapshot). Report and Resume modes skip Phase 3 and Phase 4, run Phase 2H (HTML, if enabled), Phase 5 (Snapshot) and Phase 6 (Completion).
Generate chronological activity journal. Read references/journal-template.md for the
full template structure including the Insights section (Growth Metrics, Skill Radar,
What to Improve, Strategic Direction, Owner's Scorecard).
Save to: {OUTPUT_DIR}/journals/{END}.md
Read references/report-template.md for the full template structure, categorization rules,
and auto-categorization signals.
Take all collected data from Phase 1 and categorize each activity into one of 6 business-value categories: 매출/딜리버리, 운영 효율화, 장애 & 보안 리스크 감소, 비용 절감, 채용 & 홍보, 팀 빌딩/리더십.
Also tag each activity with impact metrics where possible:
| 임팩트 태그 | 키워드/시그널 |
|---|---|
| 💰 매출 | customer, partner, delivery, release, launch, 고객, 파트너, 납품 |
| 💰 비용 | optimize, reduce, automate, remove dependency, 최적화, 비용, 절감 |
| ⏱ 시간 | speed up, reduce time, pipeline, CI/CD, 시간 단축, 자동화 |
| 🛡 리스크 | fix, security, bug, crash, validation, 장애, 보안, 수정 |
| ✅ 품질 | test, refactor, clean, lint, 테스트, 리팩토링, 품질 |
Use the keyword signals and source-based defaults from the template to auto-categorize. For ambiguous items, pick the category with the strongest signal match. If impact is quantified in the commit message or PR (e.g., "reduced from 50s to 22s") → use that number directly.
Generate the report using the Korean or English template based on the config language setting.
Save to: {OUTPUT_DIR}/reports/{END}-report.md
Read references/resume-template.md for the full competency framework, 13 evaluation
perspectives, scoring rubric, and rewriting rules.
Take all collected data from Phase 1 and classify each activity into the most relevant perspective among the 13 perspectives across 4 areas:
For each perspective with matching activities:
Interactive mode: If activity data alone is insufficient for a complete narrative, use AskUserQuestion to ask the user for context (batch 3-4 items per question).
Automated mode: Generate narratives from data only. Mark insufficient items with "[추가 컨텍스트 필요]" placeholder.
Generate the output using the Korean or English template based on the config language setting.
Save to: {OUTPUT_DIR}/resume/{END}-resume.md
Skip this phase if html_output is false.
After generating the markdown output (Phase 2A, 2B, or 2C), convert it to a styled HTML file.
Read references/html-template.md for the design system and structural mapping rules.
.html extension:
{OUTPUT_DIR}/journals/{WEEK_END}.html{OUTPUT_DIR}/reports/{WEEK_END}-report.html{OUTPUT_DIR}/resume/{WEEK_END}-resume.htmlopen {html_path}@media print.# H1 → header block with gradient background## H2 → section header with numbered badge### H3 → card with left border accent**Bold label**: value → styled key-value pair**임팩트** / **Impact** blocks → highlighted impact box**증거** / **Evidence** → subtle reference lineNote: Phase 3 is skipped in organize mode.
Read existing {OUTPUT_DIR}/brag-doc.md. Extract accomplishments from the generated
journal or impact report:
Transform into: action verb + what + result/impact format.
Append under ### {WEEK_END} heading. Do NOT duplicate existing items.
Note: Phase 4 is skipped in organize mode. The organize resume submode generates
its own resume-ready output but does NOT modify the resume file directly.
Read resume at resume_path from config. Detect format (.tex or .md).
Interactive mode: Use AskUserQuestion to let user select which brag items to add.
Format-aware insertion (LaTeX: \SmallBulletItem + \Impact{}, Markdown: bullet points).
Automated mode: Write candidates to {OUTPUT_DIR}/pending-resume-updates/{WEEK_END}.md.
Save JSON to {OUTPUT_DIR}/snapshots/{WEEK_END}.json:
{
"date": "{WEEK_END}",
"range": { "start": "{WEEK_START}", "end": "{WEEK_END}" },
"mode": "journal|impact|organize",
"organize_submode": "report|resume|null",
"sources": {
"github": { "collected": true, "commits": 0, "prs": 0, "reviews": 0 },
"slack": { "collected": true, "messages": 0 },
"jira": { "collected": true, "tickets": 0 },
"calendar": { "collected": true, "meetings": 0 },
"notion": { "collected": true, "pages": 0 }
},
"failed_sources": [],
"output_path": "{path to journal, impact report, or organize output}",
"html_path": "{path to .html file, or null if html_output is false}",
"brag_items_added": 0
}
## work-log 완료
**기간**: {START} ~ {END} | **모드**: {journal / impact / organize-report / organize-resume}
| 소스 | 상태 | 수치 |
|------|------|------|
| GitHub | ✅ | 커밋 {N}, PR {N}, 리뷰 {N} |
| Slack | ✅ | 메시지 {N} |
| Jira | ⬚ 비활성 | — |
| Calendar | ✅ | 미팅 {N} |
| Notion | ❌ 실패 | {reason} |
**저장된 파일:**
- {journal / impact report / organize output}: `{path}`
- HTML: `{html_path}` (html_output이 true일 때만 표시)
- Brag doc: {N}개 항목 추가 (organize 모드에서는 생략)
- 이력서: {업데이트됨 / pending / 변경 없음} (organize 모드에서는 생략)
For organize mode, the completion report additionally shows:
Resume 모드의 완료 보고 시, 위 테이블 아래에 아래 4개 섹션을 모두 대화에 출력한다:
## 복사용 포맷 (English) — 영문 원본 코드블록 (LaTeX 또는 Markdown)## 복사용 포맷 (한국어) — 한글 원본 코드블록 (동일 매크로, 내용만 한국어)## 프리뷰 (English) — 영문 원본을 읽기 쉬운 Markdown으로 렌더링## 프리뷰 (한국어) — 한글 원본을 읽기 쉬운 Markdown으로 렌더링Markdown 파일(.md)과 HTML 파일(.html)에도 동일하게 4개 섹션을 모두 포함한다. 4개 중 하나라도 빠지면 안 된다. 상세 규칙은 resume-template.md, html-template.md 참조.
/work-log setupreport 사용npx claudepluginhub symoon94/moonkit --plugin moonkitConducts structured weekly retrospectives for solopreneurs: scans git repos, interviews the founder, and records findings into issues and canonical files.
Analyzes worklog files to generate daily standups, weekly summaries, monthly reviews, performance reviews, and resume-ready bullets using Python script.
Synthesizes user's recent work activity, contributions, projects, and accomplishments using Glean's user_activity, memory, search, and meeting tools.