Skip to content

/daily, Two Months Later: One Board, No Launcher, and a Question Widget

What changed in my /daily Claude Code skill since July: foreman is gone, reconciliation comes first, and a generic copy you can drop into your own setup.

• Matt Dennis

In July I wrote about two Claude Code skills that kept my Salesforce work from evaporating between sessions: /daily for sprint state, /foreman for agent dispatch. Two months later /foreman is gone, the terminal workspace manager it ran on is uninstalled, and /daily does the part of both that was worth keeping.


This post covers what changed and why. At the end there’s a generic copy of the skill with the work-specific parts stripped out, which you can drop into your own setup.


What Died: The Launcher


It went in three steps. In early August I added a second act to /daily: after the plan, it writes a paste-ready brief for anything that should move today and records where the work went. It doesn’t launch anything. In September I deleted /foreman. A newer dispatch skill had replaced it, and the status-bar focus file it maintained hadn’t changed since July. A few days later I uninstalled the terminal workspace manager both of them ran on, and the newer skill went with it, because nothing was left for it to launch into.


What survived is the brief-only half. /daily writes the brief and records where the work went. I do the click that starts the agent. The runtime is a field on the map row, not an API:


## In Progress
- **ABC-57 (vendor import)** — mapping file and dry-run results in a draft PR
  - Where: PR:`#118` (draft) | branch:`abc-57-vendor-import`
  - Brief: `plans/abc-57-vendor-import-dispatch.md`
  - Next: check the dry run, then import

Nothing in /daily can launch the wrong agent, because nothing in /daily launches agents. If I want a delegating orchestrator again, the note I left myself says to build it on git worktree add and background jobs, not to bring the old one back.


Reconcile Before Asking


The July version already flagged contradictions. The current one leans on that harder: it checks the tools before it asks anything. A single gather.sh script dumps everything in one pass: assigned tickets, the map, the latest diary, open PRs, merges to main, bot-authored commits, and a section I added after getting burned, my own branch pushes from the last three days.


The skill then cross-checks all of that against the map and leads the interview with contradictions:


  • The map says In Progress, but a matching commit merged → “looks shipped, mark done?”
  • A draft PR is open that the map doesn’t mention → surface it
  • I pushed a branch the map has no row for → “what was that?”

Today’s run caught three of these. A deliverable the map still listed as due Monday had actually gone out that morning. The chat search found the message with both links. And two draft PRs were sitting open for tickets the map had never heard of. None of that needed my memory. It needed the tools and the map in the same context window.


One Writer for the Board, Many Writers for the Evidence


The biggest structural change is where catch-up data comes from. In July, the evidence was Jira, git, and whatever I remembered. Now every agent session, whatever it’s working on, leaves two kinds of evidence behind:


  • A session diary entry. Three to eight bullets of Did/Next, appended to ~/.claude/diary/YYYY-MM-DD.md when a milestone lands.
  • An effort README. Multi-day work gets a home directory with a README whose first three lines are **Status:**, **Next:**, and **Where:**, plus an append-only ## Log.

Only /daily writes the map. Everything else writes evidence, and gather.sh pulls in every diary entry and every changed README since the last run. When a README’s Status disagrees with the map row, the newer one wins, and the interview confirms it.


This fixed the failure mode I described in July, where a decision lived only in one session’s transcript. A session doesn’t need to know the map exists. It needs to write one diary line.


The Promise Scan


I say “I’ll look into it” in Slack constantly, and almost none of it made the map. Step 1b searches my own sent messages since the last run for forward-looking commitments (“I’ll send,” “let me get back to you on,” “I can put together”). It drops acks and small talk, and anything the map already covers. Whatever’s left becomes an interview question: is this tracked, does it need a map row, does it need a ticket?


Two rules keep it from becoming noise. It never writes to the map on its own, and it never replies in chat. Today it found two promises. One went into an existing ticket’s data fix. The other became a Needs Ticket row, because the right next step is an investigation, not a reply.


The Question Widget Beat Dictation


In July the interview was built for dictation. It rendered lettered options as text, I talked through my answers, and a hard confirm-back caught mis-hearings. It worked, but it depended on me catching my own mis-transcriptions in the confirm-back.


As of today, every batch goes through Claude Code’s AskUserQuestion widget: up to four questions per call, two to four options each. Clicking is faster, and the free-text field still takes typing or dictation when none of the options fit. That free text turned out to matter most. In today’s run I answered two questions with neither option: “deferred until next week, sales is on their retreat” and “ran that investigation for someone else, ignore.” The skill now says it outright: free-text answers override the options, so follow what they say.


The confirm-back survived. It just rides along now. The previous batch’s “here’s what I heard, correct?” is the first question of the next widget call, so confirming and moving on costs one click.


It Ranks the Day Itself


After the interview, /daily doesn’t ask me what to work on. It recommends an order with one line of reasoning per item, ranked by deadline pressure, then whether it’s unblocked, then whether an agent can safely do it, then quick wins. Blocked work goes on its own “holding” line. I push back or say “good, go.” Then comes the board question: want a brief for any of these?


Get the Generic Version


The skill I run is full of paths, ticket prefixes, and CLI flags that only make sense at my job. This copy has all of that pulled out:



Setup:


Put the exports in your shell profile so Claude Code inherits them, or edit the defaults at the top of gather.sh:


mkdir -p ~/.claude/skills/daily ~/worklog/diary
curl -so ~/.claude/skills/daily/SKILL.md https://www.mattdennis.dev/code/daily/SKILL.md
curl -so ~/worklog/gather.sh https://www.mattdennis.dev/code/daily/gather.sh
curl -so ~/worklog/map.md https://www.mattdennis.dev/code/daily/map-template.md

# In ~/.zshrc or ~/.bashrc. All optional; each section skips if unset
export DAILY_HOME=~/worklog
export DAILY_REPO=~/code/your-repo
export DAILY_TICKETS_CMD='gh issue list --assignee @me'
export DAILY_MRS_CMD='gh pr list --author @me'

Then run /daily. With no map yet, it builds one from your tickets and asks you to fill in the rest. The promise scan only runs if your session has a chat-search tool connected. Otherwise it skips and says so.


What’s Still Rough


gather.sh output keeps growing. Today’s run hit 60KB and got truncated mid-section, so the skill had to fetch the tail in a second pass. The fix is probably per-section size caps, not a smarter script. The script stays dumb on purpose.


The map is also getting long. Done This Sprint carries two months of rows, and the Decisions Log is well past a hundred entries. The skill says to archive it “when it gets too big,” which in practice means never. That needs a real rule, like rolling Done rows older than a sprint into a dated archive file.


And the board question is easy to skip. If I answer the plan and not the board question, nothing gets briefed, and that’s the right call. But it means the Act 2 half runs less often than it should. I haven’t decided whether that’s a bug.