Skill v1.0.1
currentAutomated scan100/100+6 new
name: ea-time-block description: Cal Newport time-block plan for today as a linked Excalidraw diagram. metadata: version: "1.0.1" hermes: category: executive-assistant version: "1.5.1"
EA Time Block (Cal Newport)
On demand: build today's intentional schedule as a linked Excalidraw diagram in ${JOSHU_FILES_ROOT}/Planning/.
Inspired by Cal Newport's time blocking: schedule column = hour grid with named blocks; right column = capture notes and optional numbered task groups (① → task list). Replan when disrupted — rerun this skill to refresh the diagram.
GTD / linking context: docs/executive-assistant.md#gtd-workspace
When to use
- User asks: "time block today", "plan my day", "draw today's calendar", "Cal Newport schedule"
- After morning review confirms carryover — regenerate with updated
carryover[] - After major calendar changes — regenerate the same-day file
Prerequisites
skill_view('excalidraw')for JSON envelope rules (container-bound labels)${JOSHU_FILES_ROOT}withconnectors/calendar/mirrors,Projects/, and optionallyPlanning/capture-YYYY-MM-DD.md/opt/joshu/scripts/gather-time-block-input.mjsand/opt/joshu/scripts/render-time-block-excalidraw.mjson VPS (Joshu sandbox image; notscripts/…relative to Desktop — Hermesterminal.cwdis the ArozOS Desktop folder)- Local factory dev from repo root:
npm run time-block:gatherandscripts/render-time-block-excalidraw.mjs
Workflow
- `skill_view('ea-time-block')` — this file
- Date & timezone — owner local date (Hermes owner-time system message or
getOwnerTimeAnchor). Output file:Planning/time-block-YYYY-MM-DD.excalidraw - Gather inputs (deterministic script) — run once before LLM synthesis:
node /opt/joshu/scripts/gather-time-block-input.mjs \--date YYYY-MM-DD \--files-root "${JOSHU_FILES_ROOT}" \-o "${JOSHU_FILES_ROOT}/Planning/.time-block-plan-YYYY-MM-DD.json"
Local dev (repo root): npm run time-block:gather -- --stdout or -o …
The script pre-fills `blocks[]` with today's meeting blocks (live calendar API when Joshu is up, else mirror scan), `workHours` expanded to cover meetings, `yesterdayPlan`, `_gather.activeProjects`, `_gather.recentJournals`, and `_gather.planningFiles` paths. See references/calendar-api-quirks.md.
Do not glob mirror filenames by calendar date — mirrors are named by event UUID. Prefer `google_calendar_list_events` (Joshu connectors MCP; covers all calendar accounts) or Joshu GET /joshu/api/connectors/calendar/google/events?date=&timezone= when the gather script is unavailable.
- Synthesize plan (LLM) — read the gather output and fill gaps:
Planning/daily-review-YYYY-MM-DD.md— carryover checkboxes (after morning review)- Yesterday's
.time-block-plan-*.jsonif daily-review missing Planning/capture-YYYY-MM-DD.md— open Tasks/Ideas bullets_gather.activeProjects→ deep/shallow blocks withProjects/<slug>/about.mdlinks_gather.recentJournalsfor context only- Optional
gbrainfor "today priority" - Do not deep-triage mail — `ea-playbook` owns filing
- Merge into plan JSON; remove or ignore
_gatherbefore render (renderer ignores extra keys)
- Write plan JSON — update
${JOSHU_FILES_ROOT}/Planning/.time-block-plan-YYYY-MM-DD.json:
{"date": "2026-06-18","title": "Time block — Wed Jun 18","yesterdayPlan": { "date": "2026-06-17", "path": "Planning/time-block-2026-06-17.excalidraw", "label": "Jun 17" },"carryover": [{ "text": "Finish investor reply batch", "link": { "path": "Projects/foo/todo.md" }, "done": false }],"workHours": { "start": "09:00", "end": "17:00" },"taskGroups": [{"ref": "1","label": "①","items": [{ "text": "task #1", "link": { "path": "Projects/foo/todo.md" } },{ "text": "task #2", "link": null }]}],"blocks": [{"start": "09:00","end": "10:30","label": "Deep work — Joshu EA","kind": "deep_work","link": { "path": "Projects/joshu-product-development/about.md" }},{"start": "14:00","end": "15:00","label": "Tasks ①","kind": "shallow","blockRef": "1","link": { "path": "Projects/joshu-product-development/todo.md" }}],"notes": ["Shutdown ritual 5pm", "buy food (from capture)"],"noteLinks": [null, { "path": "Planning/capture-2026-06-18.md" }]}
Block kinds: meeting | deep_work | shallow | personal | break | buffer
`taskGroups` + `blockRef`: Cal Newport numbered lists — block label may include ①; blockRef matches taskGroups[].ref. Renderer draws the group in the notes column.
`yesterdayPlan` + `carryover`: After morning review, set yesterdayPlan.path to yesterday's .excalidraw; populate carryover[] from unchecked items in daily-review (see `ea-morning-review`). Renderer shows a yesterday link under the title and a From yesterday ☐ list in the notes column.
Rules:
- Minimum block 30 minutes; batch tiny tasks into one
shallowblock or ataskGroupsbatch - Calendar meetings →
kind: meetingwith link to the event mirror.md - Project focus →
kind: deep_work→Projects/<slug>/about.mdortodo.md - Email batch →
kind: shallow→ mail thread or inbox projecttodo.md - Unfiled capture items →
notes[]withnoteLinks→Planning/capture-*.md - Carryover from daily-review →
carryover[]before task groups; schedule deep/shallow blocks for them - Leave buffer between dense meetings when calendar shows back-to-back overload
- Every block gets a `link` when a canonical target exists (
joshu://path from files root) - Fill gaps intentionally — every work hour gets a job
- Render diagram — use the absolute renderer path on VPS (relative
scripts/…fails from Desktop cwd):
node /opt/joshu/scripts/render-time-block-excalidraw.mjs \"${JOSHU_FILES_ROOT}/Planning/.time-block-plan-YYYY-MM-DD.json" \-o "${JOSHU_FILES_ROOT}/Planning/time-block-YYYY-MM-DD.excalidraw"
Local dev (repo root): node scripts/render-time-block-excalidraw.mjs plan.json -o …
- Tell the user — open
Planning/time-block-YYYY-MM-DD.excalidrawin jWhiteboard (double-click from Files). Block links usejoshu://paths to threads, projects, calendar events, and capture files.
Link targets
See references/link-targets.md. Renderer emits joshu://<path-from-files-root> on each block.
References
references/cal-newport-layout.md— grid layout, replanning, shutdown note, task groups, carryoverreferences/link-targets.md— per-block link mappingreferences/calendar-api-quirks.md— live calendar vs mirrors, FreeBusy calendar IDs
Pitfalls & tips
- Mirror glob by date fails — event files are UUID-named; use gather script or live list_events.
- FreeBusy `items` omitted by default — Joshu queries, for each calendar account (personal, work, …),
primary+ personal Gmail + selected calendars; use `calendars.combined.free` for scheduling. See `calendar-api-quirks.md`. - End-of-day awareness — if owner local time is past ~6 PM, confirm whether they want tomorrow's block, not today's.
- Journal paths —
Projects/*/journal_YYYY-MM-DD.mdandProjects/_system/journal_*.md(not repo-root journals).
Do not
- Replace EA-playbook triage or ea-scheduling booking flows
- Upload diagrams to excalidraw.com unless user asks (local file is canonical)
- Invent calendar events — meetings come from live calendar / gather script; use LLM only for unscheduled blocks between fixed meetings
- Paste mail bodies into plan JSON — link to
connectors/mail/…paths only