Two Claude Code Skills That Keep My Salesforce Work From Evaporating
How /daily and /foreman split Jira sync from agent dispatch, and why a single gitignored map.md file is the only thing that survives between sessions.
I run a lot of Claude Code sessions against one Salesforce org. Apex fixes, flow changes, picklist migrations, data backfills, MR reviews — often three or four of these in flight at once, spread across separate terminal panes and git worktrees. The problem was never getting an agent to do the work. It was that every session started from zero, and nothing tied the sessions together.
A session would fix a validation rule gate, ship it, and end. The next morning I’d open a fresh Claude Code window with no memory of any of it. I’d re-explain the ticket, re-discover a decision that had already been made three days earlier, or worse, not discover it and re-litigate it. Multiply that by cloud agents running unattended in the background — those come back with a branch and a commit and zero context for whoever finds it later — and I was losing real decisions to session boundaries. Not “forgot a detail” losses. “A stakeholder’s status summary said a feature was built, and it wasn’t, and nobody caught it for two days” losses.
So I built two skills that live entirely on disk, not in any session’s context window: /daily and /foreman.
The Split: Sprint State vs. Agent Dispatch
/daily owns Jira and the sprint. It syncs ticket state, diffs it against what I last wrote down, and runs a catch-up interview when something’s drifted. /foreman owns Herdr — my terminal workspace manager — and agent dispatch. It surveys what’s running, sweeps for work cloud agents did without telling anyone, and launches new task agents into isolated worktrees.
They don’t overlap because they’re not solving the same problem. /daily answers “what should I be doing today, and did Jira lie to me.” /foreman answers “what is currently running, what did it produce, and what’s the next thing worth pointing an agent at.”
One File the Whole System Reads Cold: map.md
The actual source of truth is a single file, scripts/local/worklog/map.md, gitignored, living at a fixed path so every future session — mine, a background agent’s, a cloud agent’s — reads the same thing. It’s organized as a status board, not a log:
## In Progress
- **SFDC-1406 (upsell first win)** — MR !3033 merging to main (7/21). Backfill of
32 existing First Win Upsell rows still held — needs explicit RevOps OK
+ timing coordination before running.
- **SFDC-1495 (Account Match: log async failures to Log__c)** — first slice
shipped to main; more work still in flight; Jira status
(In Progress) not yet updated to reflect the shipped slice
## Blocked / Waiting
- **SFDC-1451 (normalize LOB field)** — staying in current state; write-up read
but more business context needed; need to book a meeting first
That distinction — Jira says “In Progress” but the actual state is “one slice shipped, more coming, Jira just hasn’t caught up” — is exactly the kind of thing that gets lost if the only record is a chat transcript. The map also carries a Needs Ticket section for real work that hasn’t been formalized in Jira yet, and an append-only Decisions Log, so a decision made in one session survives into every session after it without me having to remember to repeat it.
The real test of the map came from a feature called Account Match. A stakeholder summarized a status meeting by saying a multi-account feature had shipped. My own tracking said that was decided — a UI direction chosen, written to a punch list — but not implemented. Without the map, that’s a coin flip on who’s right two weeks later. With it, /daily just flags the contradiction and asks me to reconcile it on the spot. That line is still sitting in the Decisions Log:
- 2026-07-20 · Account Match: created Epic SFDC-1511 + 3 child tickets — SFDC-1512
(Territory Mapping Automation), SFDC-1513 (Multi-Apply), SFDC-1514 (Search
Modal/Field-Mapping/Industry/Opportunity-Owner fixes bundle).
The Diary: Today’s Scratchpad, Not a Duplicate of the Map
Where the map is indefinite and status-board shaped, the diary (scripts/local/worklog/diary/YYYY-MM-DD.md) is one file per day, append-only, and disposable after it’s served its purpose. It’s where the texture lives — the stuff that would clutter the map but matters for a day or two:
- Account Match (feedback item 4 — "Sarah Murphy use case"): unqualified/
Stage 0 Opportunities created via import shouldn't get Owner set — leave as
default (running user). Open question whether Owner should be touched on
Opportunity update either. Needs a run-level toggle: "don't set Owner on
Opportunities" (11:03)
That’s a real design decision from a real feedback session, timestamped, attributable, and not something I’d reliably recall a week later without re-reading the meeting notes. /daily writes these as the day happens and rolls the durable ones — ticket state changes, real decisions — up into the map before the day closes. The diary can be sloppy because it’s disposable; the map can’t be, because it’s permanent.
The design principle behind both files, stated directly in the skill itself: “Every session starts cold from the files on disk — that’s the design. Short sessions, fresh context, disk is the memory.” I don’t try to keep sessions alive longer or stuff more context into a single window. I just make sure disk state is good enough that starting cold doesn’t cost anything.
Foreman: Survey, Sweep, Dispatch
/foreman runs in a dedicated Herdr workspace and does four things in order: survey every other workspace for agent status, sweep for cloud agent output nobody’s tracked, cross-reference against the map, then recommend a single “main thing” to focus on.
The cloud agent sweep is the part that earns its keep. Cloud agents run unattended and leave a branch, sometimes a doc, with no ceremony. Foreman just diffs remote branches against known naming conventions and greps recent commits for bot authorship:
git branch -r --sort=-committerdate \
| grep -vE 'gs-pipeline|HEAD|main|staging|qa' \
| head -30
git log --oneline --all --since="3 days ago" --author="bot" 2>/dev/null | head -20
That’s how a closed-won carrier sync fix ended up on the map at all — a cursor agent had already built a flow fix on one branch, and the research doc was sitting on a completely different branch than the fix. Nobody would have gone looking for both without the sweep flagging “here’s a branch and a doc the map doesn’t know about, want me to add them?”
Foreman also owns a tiny mechanism that’s easy to undersell: a one-line file at ~/.claude/foreman-focus that my terminal status bar reads directly.
echo "1406 backfill — run the 32 rows" > ~/.claude/foreman-focus
Four to six words, action-oriented, updated every time the “main thing” changes. It means I don’t have to re-ask Claude what I’m supposed to be doing when I glance at a terminal between other work — it’s just always visible. Small, but it’s the piece that made the map actually useful in day-to-day working memory rather than just an artifact I check at the start of a session.
Herdr Topology: One Workspace per Ticket, Worktrees for Code
Foreman never edits code itself — it delegates. The Herdr layout underneath it is fixed: a foreman workspace is home base and never does implementation. Every active ticket gets its own task workspace, named XXXX ticket-slug. Code work specifically gets a git worktree so parallel agents aren’t fighting over branch state:
herdr worktree create --branch sfdc-1519-carrier-sync --base main \
--label "1519 carrier sync" --no-focus --json
That returns a workspace with a pane already sitting at the worktree path, nested under foreman in the sidebar — intentionally, so everything rolls up to one place even though the actual git checkouts are isolated. When an agent finishes, it signals completion by committing to docs/investigations/ (research) or docs/plans/ (a plan or handoff), and foreman detects that via git log on the branch rather than polling the pane directly. It’s a deliberately dumb signal — commit to a known directory — but it means foreman doesn’t need to parse an agent’s chat output to know something landed.
What’s Still Rough
The cloud agent sweep produces false negatives if the GitLab CLI auth is flaky — I’ve got a standing note in the map that’s been sitting there for a few days because I haven’t gotten around to fixing the token. The dictation-based catch-up interview in /daily is genuinely useful when I’m talking through status out loud, but it depends on me correctly hearing my own mis-transcriptions back before they get written to the map. I added a hard confirm-back step specifically because early on I let a mis-heard “no change” get written silently and had to catch it later.
The bigger unsolved thing is upstream of both skills entirely: an idea for AI-specific data governance, sitting in Open Questions with no ticket and no owner. The concern is that agents like this one can make bulk edits to business-process fields with no gate beyond me reviewing the diff. Right now that gate is just me. The map and diary make my own work traceable after the fact; they don’t yet do anything to stop an ungoverned bulk edit before it happens. That’s the next thing worth building, not this one.