---
name: daily
description: Daily work tracker and board. Act 1 orients (gather state, reconcile tracker/git/chat against the map, catch-up interview, ranked plan). Act 2 boards work (paste-ready briefs, runtime choice, Where stubs) without launching agents. Use for "what are we doing today", "daily plan", "catch me up", "board this", "where's this living?".
---

# Daily Work Tracker

Goal: orient fast, catch up on what changed, leave the map current, and (when useful) write paste-ready briefs so another agent can pick up work. Every session starts cold from files on disk. That's the design: short sessions, fresh context, disk is the memory.

**Two acts, one skill:**
- **Act 1: Orient** (Steps 1–6, 8): gather, promise scan, reconcile, interview, write map + diary, ranked plan.
- **Act 2: Board** (Step 7): for work that should move today, write done-looks-like, a brief, a runtime choice, and a `Where` stub on the map. **Never launches** background jobs or other agents. The user owns the click; daily writes down where the work went.

`/daily` is the only writer of `map.md` and the worklog diary. Other sessions record state in their own places (see *Other sessions*), and daily folds it in.

## Setup

Everything lives under one directory (default `~/worklog`). To move it, set this in your shell profile so the agent's shell inherits it:

```bash
export DAILY_HOME="$HOME/worklog"     # map.md, diary/, gather.sh, chat-scan.stamp
```

```
$DAILY_HOME/map.md            ← the persistent board
$DAILY_HOME/diary/            ← one file per day, YYYY-MM-DD.md
$DAILY_HOME/gather.sh         ← one-shot dump of everything Step 1 needs
$DAILY_HOME/chat-scan.stamp   ← ISO timestamp of the last promise scan
```

Optional sources `gather.sh` reads if they exist (all configurable at the top of the script):
- **Ticket tracker:** `DAILY_TICKETS_CMD` (e.g. `jira issue list -a$(jira me) -s"In Progress" --plain`, `gh issue list --assignee @me`, `linear issue list --mine`)
- **Open PRs/MRs:** `DAILY_MRS_CMD` (e.g. `gh pr list --author @me`, `glab mr list --author=@me`)
- **Repo:** `DAILY_REPO`, used for recent merges, your branch pushes, bot commits, and uncommitted state
- **Session diary:** `DAILY_SESSION_DIARY` (default `~/.claude/diary`). Every agent session appends a short Did/Next entry here. It's the main catch-up source.
- **Effort homes:** `DAILY_EFFORTS` (a directory of `<slug>/README.md` files, each with `**Status:**`, `**Next:**`, `**Where:**` lines at the top and a `## Log`). Multi-day work keeps its state here; the map row just points at it.

Keep the map and diary at one fixed path. If they live in a repo, gitignore them, and **never run this skill from a git worktree**: `git worktree add` doesn't copy gitignored files, so writes land in an orphaned copy no future session reads.

---

## Procedure

### Step 1: Gather current state (one script, not ad-hoc bash)

```bash
bash "${DAILY_HOME:-$HOME/worklog}/gather.sh"
```

Sections, in order: assigned tickets · map · latest worklog diary · session diary since the last `/daily` · effort READMEs changed since the last `/daily` · open PRs/MRs · recent merges to main · your branch pushes (non-main tip commits by you, 3 days) · bot-authored commits · uncommitted state.

The script is dumb on purpose. It dumps; you judge. All reconciliation happens in your head, not in the script.

**Reconcile before asking.** Cross-check everything against the map *before* the interview, and lead with contradictions instead of open questions:
- Map says In Progress, but a matching commit merged to main → "looks shipped, mark done?"
- Map says in flight, but nothing touched it (no diary entry, no push, no PR) → "still active, or parked?"
- An open PR the map doesn't mention → surface it.
- A branch push with no map entry → "you pushed X to `branch`, what was that?" Check every row, not just the interesting ones.
- A session-diary Did/Next or effort README Status that disagrees with the map → trust the newer one, confirm in the interview.
- Real work with no ticket id → "this needs a ticket, want me to create one?"

This is where the value lives: the tools show what happened, so the interview only spends the user's time on genuine unknowns.

### Step 1b: Promise scan (optional, needs a chat-search tool)

People type "I'll look into it" in chat and never write it down. If a Slack/Teams/etc. search tool is available:

1. Read `${DAILY_HOME:-$HOME/worklog}/chat-scan.stamp` (default: 24 hours ago).
2. Search the user's own sent messages since the stamp. One `from:me after:<date>` query, not a per-channel loop.
3. Keep genuine forward commitments ("I'll send…", "let me get back to you on…", "I can put together…"). Drop acks, small talk, and thread closers.
4. Drop anything the map already covers. Hold the rest for the interview: "You told #channel (MM/DD) you'd do X. Tracked? Needs a map entry? Needs a ticket?"
5. Never write to the map or create a ticket from this step alone. Never reply in chat.
6. After the interview, bump the stamp: `date -u +%Y-%m-%dT%H:%M:%SZ > "${DAILY_HOME:-$HOME/worklog}/chat-scan.stamp"`

No chat tool this session? Skip the step and say so once in the digest.

### Step 2: Detect mode

- **New day** (no diary for today): fuller catch-up, create today's diary, update the map.
- **Same-day rerun**: lighter. Ask only about items marked pending or actively in flight. Append to today's diary.
- **No map yet**: build one from the tracker and the latest diary first.

### Step 3: Map format

The map is a status board, not a journal. Markdown only. No database.

```markdown
# Work Map

Last updated: YYYY-MM-DD HH:MM

## Must Not Forget
<!-- date within 3 days → deadline warning in the digest -->
- **[item]** — why + deadline date

## In Progress
- **ABC-123 (short slug)** — what's happening right now
  - Home: `efforts/<slug>/` (omit if none)
  - Where: agent-bg:`<job>` | chat:`<title or url>` | cloud:`<url>` | branch:`…` | PR:`#N` | human:`waiting on X`
  - Brief: path or "none yet"
  - Next: the next concrete action

## Ready to Launch
<!-- briefed, waiting on the user's click -->
- **ABC-123 (slug)** — done-looks-like in one clause
  - Runtime: agent-bg | chat-local | cloud | human | undecided
  - Brief: path
  - Next: paste brief → confirm landing

## Up Next
- **ABC-123 (slug)** — one line on what to do

## Blocked / Waiting
- **ABC-123 (slug)** — waiting on [who/what]

## Needs Ticket
- (slug) — real, scoped work with no ticket id yet

## Shelved
- **ABC-123 (slug)** — why parked, and until when

## Done This Sprint
- **ABC-123 (slug)** — shipped YYYY-MM-DD, outcome

## Open Questions
- [question] — owner, urgency

## Decisions Log
<!-- append-only, newest first -->
- YYYY-MM-DD · ABC-123: what was decided (who)
```

`Where` is required once work has started anywhere. Keep map rows short. Detail lives in the effort README.

### Step 4: Catch-up interview (question widget)

**Use the `AskUserQuestion` widget** (or your harness's equivalent) for every batch: up to 4 questions per call, 2–4 options each, a short header chip per question. The user clicks, or types/dictates into the free-text field.

**Read the free-text answers carefully.** They often override the options: "deferred until next week," "ignore, that was for someone else," "fire off a cloud agent instead." Follow what they say, not the nearest option.

| Situation | Mode |
|---|---|
| Default | Widget batch |
| One ticket is stale or ambiguous | Deep interview: one ticket, one question at a time |
| User asks for a list to dictate against | Text batch (numbered questions, lettered options) |

**Slug rule:** every ticket reference carries a 2–3 word slug. `ABC-123 (login timeout)`, never bare `ABC-123`.

**Batching:** lead with Step 1 contradictions, then in-flight work, then new tickets, open questions, deadlines within 3 days, Needs Ticket items, and promise-scan candidates. Always offer a fast "no change."

**Confirm-back before any write (do not skip).** The map is read cold by every future session, so a mis-click or mis-heard answer does lasting damage. Echo what you heard and wait for a yes. Fold the confirm into the first question of the next widget call ("Batch 1 as I heard it: … Correct?" → "Yes, write it" / "Needs a fix") so confirm and the next batch cost one round-trip.

**Decisions:** when a confirmed answer contains a decision, write it to the map's Decisions Log and today's diary.

### Step 5: Write to disk

1. **Map:** update states, append decisions, clear resolved questions, bump "Last updated." Back it up first (`cp map.md /tmp/map.md.bak-$(date +%F)`), then edit with exact-match replacements so a stale anchor fails loudly instead of silently mangling the board.
2. **Diary:** create today's file or append a timestamped block.

```markdown
# YYYY-MM-DD

## State
### In Progress
### Up Next
### Blocked
### Needs Ticket
### Done Today
### Deadline items

---

## Decisions & Notes
- ABC-123: decision (HH:MM)
```

### Step 5b: Create missing tickets (opt-in, confirm-gated)

All real work gets a ticket. Daily never creates one on its own; it surfaces the gap and offers. Before creating one, ask: current sprint or backlog? Assign to you? Then create it, move the row out of Needs Ticket, and log it in both files. "Not now" leaves the row in Needs Ticket. Don't drop it, and don't create it.

### Step 6: Plan of attack (recommend, don't just ask)

Rank the day yourself, one line of reasoning per item. Signals, in order: deadline pressure → unblocked → safe to hand to an agent → quick win. Blocked items go on a separate "holding" line. Confirm with one widget question ("Good, go" / "Reorder"). Keep the refine loop to a couple of turns.

### Step 7: Act 2 Board (briefs + Where stubs, no auto-launch)

After the plan, ask once: "Board any of these?" Per ticket:

1. **Done looks like:** one paragraph.
2. **Brief:** a paste-ready file an agent can run cold (Goal / Context / Scope in+out / Runtime / First steps). Real ticket id required. Update an existing brief instead of duplicating it.
3. **Runtime:** recommend one of `agent-bg`, `chat-local`, `cloud`, `human`, `already-in-flight`, `undecided`. The user confirms.
4. **Map stub:** briefed → Ready to Launch; started → In Progress with Where/Brief/Next. Confirm-back first.
5. **Stop.** Print the brief path and where to paste it. Don't launch anything. When the user says it landed, set `Where` right away.

Runtime is a field on the row, not a launcher API. That's deliberate: one "dispatch anywhere" abstraction is where these systems rot.

### Step 8: Terminal digest

```
=== Daily · DATE ===
⚠ DEADLINE (if within 3 days)

TODAY (confirmed order)
IN PROGRESS      id  slug  →  what's happening   (Where: …)
READY TO LAUNCH  id  slug  →  runtime, brief
UP NEXT / BLOCKED / NEEDS TICKET / OPEN QUESTIONS / OPEN PRs

Map:   $DAILY_HOME/map.md
Diary: $DAILY_HOME/diary/DATE.md
```

---

## `status` mode

`/daily status`: read-only. Cat the map and today's diary (skip `gather.sh`), diff open PRs against In Progress, print the digest. No questions and no writes, except a one-line warning for any deadline within 24 hours.

## `note` mode

`/daily note ABC-123: decided X`: append to today's diary, add it to the Decisions Log if it names a ticket, bump "Last updated."

## Other sessions

Other sessions don't write the map. They write:
- one Did/Next entry in the session diary (`$DAILY_SESSION_DIARY/YYYY-MM-DD.md`, append-only), and
- the effort README's Status/Next/Where and `## Log`, when the work has an effort home.

The next `/daily` picks both up through `gather.sh` and copies decisions into the map after the confirm-back. One writer for the board, many writers for the evidence.
