task-context — Intervals task → ready-to-work
Single source of truth = Intervals. Google Workspace = opt-in enricher only. Never auto-search Gmail/Drive (wastes tokens on context that may not exist).
All Intervals calls use the intervals MCP tools. Gmail/Drive use the gws CLI via the helper script.
Flow A — start a task: /task <localid> [flags]
1. Fetch
get_task(<localid>)→ core fields.get_task_notes(taskId=<localid>)→ comments (real detail usually lives here).- Decode HTML entities in
title,summary, and note bodies — both named (ó→ó,&→&) and numeric ( →newline,'→'). Notes commonly use for paragraph breaks.
2. Assess completeness (label only — no search)
If summary is empty AND notes are thin (< ~200 chars / no actionable detail), mark the brief:
⚠ thin — no actionable detail in Intervals. Run /task <localid> --enrich to pull Gmail/Drive context.
Do not search anything here. Enrich is explicit only.
3. Enrich — ONLY if --enrich was passed
Never triggered automatically. When invoked:
~/.claude/skills/task-context/scripts/gmail_search.sh "<client>" "<pm-owner>" "<keywords>"
<client>= taskclientfield;<pm-owner>= taskownersfield (the PM);<keywords>= 2–4 salient words from the title.- The script prints compact JSON (from / date / subject / snippet). Fold the relevant lines into the brief with a one-line source note.
- Optional Drive lookup for assets:
gws drive files list --params '{"q":"name contains '''<client>'''","pageSize":10,"fields":"files(id,name,mimeType,webViewLink)"}' --format json - Only the parsed summary enters context — never paste raw email bodies.
4. Classify type
From module + title/notes keywords, assign one type and its route:
| Type | Signals | Route |
|---|---|---|
translation |
i18n, "traducir", English strings | ps-translate skill (near-auto) |
image |
"imágenes", white zones, thumbnails, regen | ps-image-regen skill (near-auto) |
layout |
Disseny/design module, CSS, header/footer, product page | layout-builder agent (semi-auto) |
bug |
error, "no funciona", stacktrace | human-led, agent assists |
security |
CVE, module advisory, scan | ps-security-audit skill |
content |
text/CMS edits | semi-auto |
unknown |
fallthrough | present brief, ask |
If --type <type> was passed, use it instead.
5. Brief — print to chat AND save to engram
Print this, then mem_save it with topic_key: task/<localid>/brief, project: cinetic, capture_prompt: false. No repo file.
TASK <localid> · [<status> · P<priority> · <severity>]
<decoded title>
Client: <client> Module: <module> PM: <owners>
Time: <actual>h logged / est <estimate> Due: <datedue or —>
WHAT'S ASKED
<decoded summary + distilled notes | ⚠ thin — ... (see step 2)>
CONTEXT (enriched) ← only if --enrich ran
<gmail/drive snippets + links>
AMBIGUITIES / TO CHASE
- <missing info to ask the PM>
TYPE: <type> → route: <skill/agent>
BRANCH: <localid> (<created|switched|skipped>)
NEXT: <proposed first steps>
6. Git branch (unless --no-branch)
- Branch name =
<localid>. If it exists or is stale →<localid>-<slug>(slug = kebab of a few title words). - Create/switch in the current repo (cwd). No cross-repo logic.
- Never delete remote branches (team policy). Local hygiene only:
git fetch -p.
7. Route
Name the matching skill/agent (step 4) and offer to hand off. For deterministic types (translation, image, security) you may proceed with the skill directly; for layout/bug draft and let the user review.
Flow B — finish a task: /task done <localid>
Time only. No git. Never commit or push.
Time model — 15-minute banding, human-confirmed
Billing is booked in 15-minute bands, minimum 15 min (0.25h increments). Never auto-log from elapsed wall-clock — the session may have been paused, so elapsed is unreliable.
- Optionally show a naive elapsed figure labeled:
hint (unreliable, includes idle): ~Xh. - Round the hint up to the nearest 0.25h and present as a suggestion.
- Ask the user for the real time (accept the suggestion or a typed value).
- Ask billable? (y/n) — every time, no default.
- Resolve the worktype id (see below), then:
add_time_entry(taskId=<localid>, worktypeid=<id>, date=<today YYYY-MM-DD>, time=<confirmed decimal hours>, billable=<bool>).
Never write a time entry without the user's confirmed number.
Worktype resolution — always "Varis"/"Varios"
The Intervals API cannot list worktypes for this user group (intervals://worktypes → 403), and worktype ids are project-scoped. Resolve dynamically:
- Check the cache
~/.config/mallard/worktypes.jsonfor this task'sprojectid. - If absent, call
get_time_entries(taskId=<localid>, datebegin=..., dateend=...)(a wide range, e.g. the last year) and find an entry whoseworktypename isVarisorVarios; reuse itsworktypeid. Cache it under theprojectid. - Seed value:
256467for projectNEVEN - Tiendas Aka(projectid1380816). - If no prior entry exists in the project, ask the user for the worktype id once, then cache it.
Hard rules
- Intervals is the only source of truth. Slack/Trello/Gmail are not integrated; Gmail/Drive are opt-in enrichers via
gwsonly. - Never auto-enrich. Never auto-log time. Never touch remote branches.
- English-only content (mallard is public). No company names in code/paths.