Weekly work log
Build and refresh the brycewatson.com "Weekly Work Log" report page (/weekly-report, archived under /log) for the last completed week. Discovers the week's work from session-end handoffs + git, distils it into honest public-voice items, re-derives and verifies every number, and (unattended, every Sunday night via a Claude scheduled task) opens a judgment-assisted review PR. Never publishes unattended.From its SKILL.md
npx -y skills add BryceEWatson/claude-global-skills --skill weekly-work-logAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
16.2 KB, ~3.9k tokens by cl100k_base, as published. Nobody here has run it
Weekly Work Log
Builds and refreshes the Weekly Work Log at brycewatson.com/weekly-report: a per-project feed of the specific work Bryce did last week, each item with an honest status badge and an expandable evidence drawer, a git-derived commits/day chart for the week, and per-project archive pages. Each week's report is snapshotted; brycewatson.com/log is the index of all past weekly reports.
Routes: /weekly-report (live, current week) · /weekly-report/<project> (per-project commit-history archive) · /log (index of weekly reports) · /log/<week> (an archived week).
Target project: C:\Users\Bryce\Projects\brycewatson.com. The page + build scripts live there; this skill is the reusable orchestrator + the weekly scheduler.
The window: the last completed week
The report always covers the most recently completed Monday–Sunday week (a week completes on Sunday). Run on a Sunday night, that is the week that just ended; run any other day, it is the previous full week. Discovery (handoffs + git), the chart, and the per-project metrics all use this same week, resolved by the single shared resolveWeek() in scripts/lib/work-log-sessions.mjs. It is anchored on the calendar week, never a rolling window walking back from today.
Backfill (--week YYYY-MM-DD) regenerates a PAST completed week's /log archive (snapshot + index + re-aggregated goals) and leaves the live work-log.json untouched. Any day inside the target week resolves to that whole Mon–Sun window; a future date or the current in-progress week aborts. Backfill is opt-in / operator-confirmed and regenerates exactly one completed week per invocation (blast radius bounded to one PR); it is never fired by the scheduled run (the unattended agent always targets the last completed week — one PR, not N).
What runs where
Everything runs LOCALLY (it reads ~/.claude handoffs + the sibling repos under C:\Users\Bryce\Projects\); GitHub Pages CI cannot. The committed JSON is what CI builds, exactly like art.json/books.json.
<repo>/src/data/work-log.source.json— approval-gated content (the human gate): Claude distills it from the week's handoffs + redacted session digest + git; you review and approve the PR; the generator verifies every number. Prose is distilled and human-reviewed, not number-verified.<repo>/src/data/work-log.json— GENERATED + committed (every number re-derived + git-verified).<repo>/src/data/reports/<weekStart>.json+reports/index.json— committed per-week snapshots (the/logarchive series); the generator writes these.<repo>/src/data/goals.json— GENERATED + committed (the/goalscross-week aggregation).<repo>/src/components/ReportPanel.astro— the report panel, shared by/weekly-reportand/log/<week>.<repo>/src/pages/weekly-report.astro+weekly-report/[project].astro+log.astro+log/[week].astro+goals.astro— the pages.<repo>/scripts/draft-work-log-from-handoffs.mjs— discover (handoffs → redacted digest).<repo>/scripts/draft-work-log-sessions.mjs— mine the week's interactive sessions → redacted digest.<repo>/scripts/draft-work-log-proposed.mjs— ranked.proposeddistil scaffold (interactive; the builder NEVER reads it).<repo>/scripts/work-log-harvest-nouns.mjs— propose redactor denylist additions → gitignored sidecar (count surfaced, never raw nouns).<repo>/scripts/work-log-validate-source.mjs— voice/leak gate on the DRAFTED source prose (fails loud on a dash / denylisted token / bad badge / display-role git-leak), run after distillation and before the build (also chained inpnpm build).<repo>/scripts/work-log-via-honestweek.mjs— build (the honestweek engine: verify-or-abort every commit, re-derive + number-fence every number, redact, then write work-log.json + the /log snapshot + index + goals.json).<repo>/scripts/build-work-log.mjsis retained as the parity oracle (scripts/work-log-parity.mjsproves the two agree on all four artifacts).<repo>/scripts/work-log-weekly.mjs— open the review PR (--advisory <path>splices the fail-open advisory; never main, never deploy).<repo>/scripts/lib/work-log-redact.mjs— shared secret/leak scrubber (the ONE canonical redactor; extend its term lists, never duplicate).~/.claude/skills/weekly-work-log/run-state.cjs— atomically records a privacy-saferunning/succeeded/failedstatus for the Sunday run. The Monday preview reads this instead of treating every missing PR as a quiet no-op.
Modes
/weekly-work-log(interactive, a human in the loop): the full build — discover → distil candidates → build → preview. New items get WRITTEN here (judgment). The optional.proposedscaffold (draft-work-log-proposed.mjs) gives you a ranked, mirror-shaped starting point to fill in the public voice; you then MOVE accepted items by hand intosource.json(the gate).- Unattended (the Sunday-night Claude scheduled task) — curates the whole week, then opens one PR:
- Isolated checkout: the user's
brycewatson.comcheckout is never switched, reset, stashed, or cleaned. The task fetchesorigin/mainand works in the dedicated sibling worktreebrycewatson.com-weekly-work-log. A clean registered stale worktree may be replaced; a dirty or unregistered directory is preserved and surfaced as a failed run. - Curate every session (distillation): distil EVERY interactive Claude Code session of the week into
source.jsonitems so the page shows the full week (the original "curate every session" directive, automated). Done in-context from the redacted digest (not subagents). Private/sensitive sessions are summarized through the privacy filter, not dropped or stubbed (display roles: Akaya/Personal/ShopForge — generalized to the kind of work, never git-read; "personal finance is fine, we just need iron clad rules"). Each item is linked to the SPECIFIC goal it advances viaobjectiveId(readobjectives.public.json) — never leave a multi-goal project like Command to fall through to its catch-all/parent goal, or the goal lens collapses to one bucket; client/private items get noobjectiveId(they stay off/goals). The drafted prose is gated bywork-log-validate-source.mjs(fails loud on a dash/leak/bad-badge) + a claim-falsification self-check BEFORE the build. - Deterministic backstop:
work-log-via-honestweek.mjs(honestweek) git-verifies + number-fences every number (aborts on any unresolved/non-Bryce commit, so NO PR on bad data). Items the job drafts carry"drafted": "auto-<date>". - Fail-open advisory: judgment that ASSISTS the reviewer (badge-vs-prose, coverage gaps, badge-vs-git, a downgrade-only privacy adjudicator, reversal-coverage) spliced into the PR body, plus the noun-harvester (count only). Any LLM/network/
ghfailure → a single "advisory unavailable" line; never blocks the PR. Advisory may only DOWNGRADE/FLAG. - The PR is the gate: auto-DRAFT, human-APPROVE. The run never pushes
main, never deploys, opens exactly one PR.
- Isolated checkout: the user's
--week YYYY-MM-DD: backfill a past completed week's archive (see above). Manual only.--days N: override the window to a rolling N-day scan (manual broader discovery).
The full flow (interactive)
- Discover —
node scripts/draft-work-log-from-handoffs.mjs(and/ordraft-work-log-sessions.mjs). Scans the week's session-end handoffs / interactive sessions across the allowlisted repos, extracts tagged claims + reversals + cited commits, redacts, writes the gitignoredsrc/data/work-log.drafts.jsondigest. - Curate every session —
node scripts/draft-work-log-sessions.mjsfor the redacted per-session digest, then distil EVERY session intosource.jsonitems in the plain public voice (private/sensitive sessions summarized through the privacy filter, never dropped — see the rules + the unattended promptscheduled-task-prompt.md).draft-work-log-proposed.mjscan give a ranked scaffold to fill. Thennode scripts/work-log-validate-source.mjs(fails loud on a dash/leak/bad-badge) before building. Obey every rule below; accuracy is the floor even for private. - Build —
node scripts/work-log-via-honestweek.mjs(the honestweek engine). Re-derives every date/number from git, rewrites commit snippets to the real subject, verify-or-aborts all cited commits, number-fences every number, redacts. Writeswork-log.json(+ snapshot + index +goals.json).build-work-log.mjsis the parity oracle;node scripts/work-log-parity.mjsproves they agree. - Preview —
pnpm dev, openhttp://localhost:4321/weekly-report(archive index at/log, goals at/goals). - Ship — commit the data files. A merge to
maindeploys via CI. (Unattended:node scripts/work-log-weekly.mjs --advisory <sidecar>opens the PR instead of committing to main.)
The rules (load-bearing — every run, especially unattended, must honor these)
- Voice: plain, concrete, no marketing flourishes. Subject-led headlines — lead with the work or the finding, NOT "I"/"My" (headlines must not all start the same way or read self-focused). First-person belongs in the body. No em dashes. Never announce the page's own honesty ("honest", "keeping myself honest", "proof I don't fake it") — show it through the badges + receipts. This includes generalized/private entries: state the KIND of work concretely (like any public entry) and NEVER narrate the withholding itself ("keeping it sealed", "recording only the kind of work", "surfaced here as its own thread", "keeping it generic here", "belongs in an honest log") — model on the Akaya display-role rows.
- Honest status badges:
shipped(built, merged, verified),in progress,designed, not proven(machinery exists, no real result yet). The most interesting work is often the least finished; let it wear the badge openly. Map a handoff's[verified]claim → shipped;[assumed]/[unverified]/[handoff-claimed]→ designed-not-proven. - Every number git-verified: re-derived at build, never hardcoded. A cited commit that does not resolve (or is not Bryce's:
[email protected]/[email protected]) aborts the build. Item dates come from the commit, not the prose. - Privacy (default-deny): only Bryce's OWN repos are read (Command, DemandForge, claude-global-skills, brycewatson.com). Client / no-remote repos (dropKnowledge, etc.) are never read or named. The shared redactor scrubs codenames (plumagedispatch), client names (dropKnowledge / castgryff), vendor + niche names, session UUIDs, home paths, and secrets. Draft-and-distil, never lift: handoff prose is operational and leaky; distil it into plain public-voice items, never paste it verbatim. The
.proposedscaffold and the harvester sidecar are gitignored; never commit them, and never route raw harvested nouns into the PR body (count only). - Structure: the feed is grouped by project into containers; each project is a card with git-derived metrics (commits this week, active days, entries) + an
archive →link to/weekly-report/<project>(6-month commit history). Dark console aesthetic; the shared site header usesheaderVariant="dark-canvas". - The approval gate is the PR: the unattended run never pushes to
mainand never deploys. It only opens a PR. Bryce reviews + merges; CI deploys the merge. Advisory judgment never gates — it only assists.
Scheduling (every Sunday night) — Claude scheduled task
The unattended weekly run is a Claude scheduled task (mcp__scheduled-tasks), NOT a Windows Task Scheduler job. It runs as a local Claude agent with full filesystem access and catches up on next app launch if the app/machine was closed at the scheduled time — fixing the old schtasks job's silent-drop failure (it had StartWhenAvailable=False / WakeToRun=False / DisallowStartIfOnBatteries=True and no catch-up).
- The task:
taskId: weekly-work-log,cronExpression: "0 22 * * 0"(Sunday 22:00 local). Its prompt is authored inscheduled-task-prompt.md(this skill dir) — keep that file in sync with the live task. Its Monday preview prompt is authored inpreview-scheduled-task-prompt.mdand accepts only a verifiedwork-log/weekly-*PR that changes both the authored source and generated report. - Create / update it (the runtime swap; done by an operator session after the repo seams are on
main):
Confirm withmcp__scheduled-tasks__create_scheduled_task({ taskId: "weekly-work-log", cronExpression: "0 22 * * 0", description: "Sunday-night Weekly Work Log: deterministic build + verify, fail-open advisory, opens one review PR (never deploys)", prompt: <contents of scheduled-task-prompt.md> })mcp__scheduled-tasks__list_scheduled_tasks. - Retire the legacy Windows task at the same swap:
node uninstall.cjs(orschtasks /Delete /TN ClaudeWeeklyWorkLog /F).install.cjs/weekly-run.cmdare the legacy schtasks launchers, retired at the swap; do not runinstall.cjsgoing forward. - Failure visibility: every run starts by writing
last-run.jsonunder the live scheduled-task directory and must write one terminal state. Fetch/worktree setup and a non-data PR-open failure retry exactly once; data verification never retries into a PR. - Verification debt: the run-on-next-launch catch-up is documented, not yet behaviorally proven here. Worth a one-time controlled catch-up test (close the app over a due time, relaunch, confirm fire) before fully trusting it — the
demandforge-verify-cron-first-firingtask is precedent. - It activates once the page is shipped (the data files are committed). Requires:
ghauthenticated and git push credentials. The shared repo may be on any branch and may contain the user's work because the scheduled run operates fromorigin/mainin its own worktree.
Safety invariants
- Never push to
main; never deploy; only ever open a PR. The unattended run opens exactly one PR. - Never mutate the user's shared checkout. All unattended writes happen in the dedicated worktree; every setup or terminal failure is persisted before the task exits.
- Abort (no PR) if the generator fails verification — never open a PR with unverified data.
- Advisory is fail-open: any LLM/network/
ghfailure → a single "advisory unavailable" line; the PR still opens with deterministic data + the human checklist intact. Advisory may only DOWNGRADE/FLAG — never clear-for-publish, never suppress the human leak/voice checklist. - The cron NEVER fires
--weekbackfill; the harvester's raw nouns NEVER enter the PR body (count only). - Reuse the review-loop
--mode claimengine/rubric verbatim for the badge-vs-prose checks — read itsagents/claim-*.mdlenses at runtime; do not fork them. - Curate every session, redacted — not dropped, not stubbed. Private/sensitive sessions are summarized through the privacy filter (display roles never git-read; client→"Akaya", finances→"Personal"; generalized to the kind of work; accuracy is the hard floor even for private). A session you cannot distil confidently gets the most generic HONEST entry, never a fabricated one.
- The drafted prose is gated before it builds:
work-log-validate-source.mjsfails loud on a dash/leak/bad-badge/git-leak; the iron-clad redactor + the dist-PII scan are the deterministic backstop; the PR is the human gate. Auto-DRAFT, human-APPROVE — never auto-publish in Bryce's voice. - The unattended run writes ONLY
work-log.source.*(its drafted items) + gitignored sidecars; it NEVER hand-writeswork-log.json/reports/*/goals.json(the build does, deterministically), nevermain, never deploy. - The drafts digest and harvester sidecar are gitignored and redacted; never commit them.
What ships with it: 7 files
24.9 KB alongside SKILL.md, 5 of them executable
test/
- run-state.test.cjsruns2.3 KB
- install.cjsruns2.4 KB
- preview-scheduled-task-prompt.md2.9 KB
- run-state.cjsruns3.0 KB
- scheduled-task-prompt.md12.6 KB
- uninstall.cjsruns956 B
- weekly-run.cmdruns808 B