flower
/
All briefs
complete draft note flower

Daemon check-in digest: "commits since last ping" (bounded, branch- + brief-aware)

canonical · plan

Spec

markdown

hand-off · dispatch

Dispatch

Auto-dispatch

when it reaches planned

Design-loop

design pass before build

This brief is complete — dispatch is closed.

#91 done fresh flower · flower/128-checkin-commits-digest
agent: claude 3 scratchpads
You are being dispatched from flower Brief #128: Daemon check-in digest: "commits since last ping" (bounded, branch- + brief-aware)

Recall pointer:
- Use recall_brief with id 128 for the full folder if you need provenance.

Target:
- project: flower (/Users/mikeferrara/Documents/code/flower)
- branch: flower/128-checkin-commits-digest
- worktree: not specified
- kind: fresh

Current brief spec:
## Ask
Add a bounded **"commits since your last ping"** section to the daemon check-in response so standing
daemons stay aware of movement landing elsewhere over an active session — a PR merged, a dependency
cleared — without pulling anything.

## Motivation
Daemons currently have zero visibility into what merged while they poll: a refine daemon can't tell that
a brief it refined just shipped, or that (e.g.) auto-dispatch work landed. flower already ingests commits
and parses the `Brief: #id` trailer, so the highest-value signal is cheap to surface right in the
check-in the daemon already runs.

## Scope — v1
On each `flower:daemon-checkin` (command output **and** the `daemon_checkin` MCP response), include a
**`commits_since_last_ping`** section.

### Which commits
- Commits that landed on **the branch the daemon's environment is currently checked out into** — resolve
  from the running environment / worktree; **do NOT assume `master`/`main`** (primary branch varies per
  project). (For now the daemon's checked-out branch IS the "active/merged-into" branch by convention.)
- **Own-project scope** only.
- Landed **between the daemon's previous check-in and now** (commit date after the prior check-in
  timestamp). **Zero commits → omit the section entirely.**

### Per-commit shape (lean)
- short sha · **subject (first line, truncated to ~80 chars + ellipsis** when longer) · **linked `#brief`
  id** (from the `Brief:` trailer) when present · up to **5** files touched (`+K more`).

### Bloat guards (hard — this is the whole point of keeping it lean)
- Cap at **~15 newest** commits; if more, append **`+N more since HH:MM`**.
- **Group by brief** where possible (commits sharing a `Brief: #id` collapse under it, e.g. "#117 — 3
  commits"), so long lists read as movement, not noise.
- Subject truncation (above) + 5-file cap + omit-when-empty.
- Respect #106's checkin-payload discipline (this is an *additive* bounded section; keep it small).

## Why the brief link is the payoff
The `Brief: #id` trailer turns raw commits into actionable awareness: a daemon instantly learns "a brief I
touched merged" or "a dependency cleared" and can react on its next tick instead of staying stale for a
poll interval (up to 120 min when dormant).

## Related / future (NOT v1)
- **Project-level "primary branch" config** — a per-project setting for the primary/deployed branch,
  defaulted from the checked-out branch at import or inferred from worktrees, instead of env-inferring it.
  Would make this feature (and others) branch-explicit. **Candidate for its own brief** (operator was
  "wondering" about it; env-inferred is fine for v1).
- The same "since last ping" digest could later carry other movement (newly-`planned` briefs,
  dependency-clears, roster changes) — v1 is commits only.
- **Cross-project awareness** for a daemon working across projects — parked as a future brainstorm
  (operator: not now).
- **Sibling of #106** (daemon-runtime context-efficiency review): #106 *trims* the checkin payload, this
  *adds* a bounded one — together they make the check-in response a lean "while you were away" briefing.

## Acceptance
- `flower:daemon-checkin` (+ MCP response) returns a bounded `commits_since_last_ping` for the daemon's
  checked-out branch + own project since the prior check-in: short sha / truncated subject / linked
  `#brief` / ≤5 files, capped ~15 + "+N more since HH:MM", grouped by brief, omitted when empty.
- No unbounded growth across a long dormant gap.
- `php artisan test` green + pint. `Brief: #128` trailer.

## Provenance
Operator idea (2026-07-03), refined with the operator: branch = env-checked-out (not master/main);
own-project; cap ~15 + group by brief; subject truncation; brief-link included. Speced by flower-refine.
Related: #106.

Recent/key trace events:
[1] participant_joined flower-refine: (no body)
[2] note_added flower-refine: Operator idea, refined with operator (2026-07-03). Add a bounded "commits since last ping" section to the daemon check-in response so standing daemons stay aware of what landed while they polled (e.g. a PR merged, a dependency cleared). Decisions: report commits on the daemon's CURRENT CHECKED-OUT branch in its env (do NOT assume master/main); own-project scope; per-commit = short sha + truncated subject + linked #brief (Brief: trailer) + ≤5 files; cap ~15 newest + "+N more since HH:MM", grouped by brief; omit when empty. Sibling to #106. Full spec via brief_update_spec.
[3] plan_proposed flower-refine: ## Ask
Add a bounded **"commits since your last ping"** section to the daemon check-in response so standing
daemons stay aware of movement landing elsewhere over an active session — a PR merged, a dependency
cleared — without pulling anything.

## Motivation
Daemons currently have zero visibility into what merged while they poll: a refine daemon can't tell that
a brief it refined just shipped, or that (e.g.) auto-dispatch work landed. flower already ingests commits
and parses the `Brief: #id` trailer, so the highest-value signal is cheap to surface right in the
check-in the daemon already runs.

## Scope — v1
On each `flower:daemon-checkin` (command output **and** the `daemon_checkin` MCP response), include a
**`commits_since_last_ping`** section.

### Which commits
- Commits that landed on **the branch the daemon's environment is currently checked out into** — resolve
  from the running environment / worktree; **do NOT assume `master`/`main`** (primary branch varies per
  project). (For now the daemon's checked-out branch IS the "active/merged-into" branch by convention.)
- **Own-project scope** only.
- Landed **between the daemon's previous check-in and now** (commit date after the prior check-in
  timestamp). **Zero commits → omit the section entirely.**

### Per-commit shape (lean)
- short sha · **subject (first line, truncated to ~80 chars + ellipsis** when longer) · **linked `#brief`
  id** (from the `Brief:` trailer) when present · up to **5** files touched (`+K more`).

### Bloat guards (hard — this is the whole point of keeping it lean)
- Cap at **~15 newest** commits; if more, append **`+N more since HH:MM`**.
- **Group by brief** where possible (commits sharing a `Brief: #id` collapse under it, e.g. "#117 — 3
  commits"), so long lists read as movement, not noise.
- Subject truncation (above) + 5-file cap + omit-when-empty.
- Respect #106's checkin-payload discipline (this is an *additive* bounded section; keep it small).

## Why the brief link is the payoff
The `Brief: #id` trailer turns raw commits into actionable awareness: a daemon instantly learns "a brief I
touched merged" or "a dependency cleared" and can react on its next tick instead of staying stale for a
poll interval (up to 120 min when dormant).

## Related / future (NOT v1)
- **Project-level "primary branch" config** — a per-project setting for the primary/deployed branch,
  defaulted from the checked-out branch at import or inferred from worktrees, instead of env-inferring it.
  Would make this feature (and others) branch-explicit. **Candidate for its own brief** (operator was
  "wondering" about it; env-inferred is fine for v1).
- The same "since last ping" digest could later carry other movement (newly-`planned` briefs,
  dependency-clears, roster changes) — v1 is commits only.
- **Cross-project awareness** for a daemon working across projects — parked as a future brainstorm
  (operator: not now).
- **Sibling of #106** (daemon-runtime context-efficiency review): #106 *trims* the checkin payload, this
  *adds* a bounded one — together they make the check-in response a lean "while you were away" briefing.

## Acceptance
- `flower:daemon-checkin` (+ MCP response) returns a bounded `commits_since_last_ping` for the daemon's
  checked-out branch + own project since the prior check-in: short sha / truncated subject / linked
  `#brief` / ≤5 files, capped ~15 + "+N more since HH:MM", grouped by brief, omitted when empty.
- No unbounded growth across a long dormant gap.
- `php artisan test` green + pint. `Brief: #128` trailer.

## Provenance
Operator idea (2026-07-03), refined with the operator: branch = env-checked-out (not master/main);
own-project; cap ~15 + group by brief; subject truncation; brief-link included. Speced by flower-refine.
Related: #106.
[4] status_change flower-refine: (no body)
[5] link_added flower-refine: (no body)
[6] link_added flower-refine: (no body)
[7] link_added flower-refine: (no body)

Recommended linked context:
{
    "todos": [],
    "scratchpads": [
        {
            "id": 364,
            "solo_scratchpad_id": "1055",
            "name": "flower-refine — reset handoff (2026-07-03)",
            "archived": false,
            "revision": 1
        },
        {
            "id": 375,
            "solo_scratchpad_id": "1067",
            "name": "flower-refine — reset handoff (2026-07-03 #2)",
            "archived": false,
            "revision": 2
        },
        {
            "id": 378,
            "solo_scratchpad_id": "1070",
            "name": "flower-refine — reset handoff (2026-07-04)",
            "archived": false,
            "revision": 2
        }
    ]
}

Execution notes:
- Treat the brief as the source of truth.
- Keep work scoped to this dispatch request.
- Use brief_append / brief_update_status when reporting material progress; as your final dispatched-worker step, call brief_dispatch_complete with dispatch_request_id (or brief_id) and actor_ref.
- Codex workers should verify mutating Flower tools with tool_search query `brief_append brief_dispatch_complete flower_feedback` (limit 20) when tool availability is in doubt; report raw SEE/LOAD vs NOT visible instead of silently using local fallbacks.
- Add a git commit trailer `Brief: #128` to every commit for this brief so flower can exact-link commits back to the brief.

provenance · append-only

Trace

live
or paste a screenshot uploading…
  1. link added 1d ago
    agent · system:commit-trailer
  2. link added 1d ago
    agent · system:commit-trailer
  3. participant joined 1d ago
    system · system:commit-trailer
  4. merged 1d ago

    Merged to master by flower-orchestrator (daemon 29). Merge commit 65d0b5a (worker commit c135af3, branch flower/128-checkin-commits-digest, base incl. #160). New CheckinCommitDigestService: bounded "commits since your last ping" digest — own-project + since-previous-ping window (authored_at > prior check-in), newest-first, capped ~15 (+N more), grouped by Brief: trailer (commit.meta.brief_refs), subjects ~80 chars, files capped 5; omits on no-project / first-ping / empty window; branch-aware via git ancestry, degrades gracefully. DaemonRosterService::checkin() captures pre-overwrite last_checkin_at → transient DaemonAgent::$previousCheckinAt (#160 parked auto-unpark untouched, test-guarded). Rendered by flower:daemon-checkin (branch from getcwd) + daemon_checkin MCP tool (commits_since_last_ping section). BEST-EFFORT everywhere — a git/query hiccup never fails a heartbeat. config caps (flower.daemons.checkin_digest.*). Clean merge (isolated to check-in files). Full suite green on MAIN: 1007 tests / 1005 passed / 2 skipped / 0 failed.

    agent · flower-orchestrator
  5. status change 1d ago
    agent · flower-128-checkin-digest-worker
  6. dispatched 1d ago

    Dispatch request #91 marked done.

    agent · flower-128-checkin-digest-worker
  7. note added 1d ago

    Built the bounded "commits since your last ping" digest. Branch: flower/128-checkin-commits-digest (from master@d707d36, which includes the #160 parked-state auto-unpark). Commit: c135af3f9c1756ac47f591597bd54b8c5bd0624f. WHAT CHANGED (8 files): - NEW app/Services/Daemons/CheckinCommitDigestService.php — forDaemon($daemon, $previousCheckin, $branch, $repoPath): own-project + since-previous-ping window (authored_at > prior check-in), newest-first, capped at ~15 with "+N more since HH:MM"; grouped by the Brief: trailer (from commit meta.brief_refs, parsed by CommitBriefRefParser); subjects truncated (~80, ellipsis), files capped at 5 (+K more). Omits entirely when no project, no prior ping (first check-in → no dump), or empty window. Branch-aware: filters to commits reachable from the branch tip via GitInspector::branchContainsCommit when a repo path resolves + is a git repo; degrades to own-project (branch_filtered=false) otherwise. Caps live in config/flower.php flower.daemons.checkin_digest.* (version-controlled defaults, env-overridable). Class is non-final with a protected git-ancestry seam so the branch filter is stubbable in tests. - app/Services/DaemonRosterService.php checkin() — captures the pre-overwrite last_checkin_at inside the txn and rides it out as a transient (non-persisted, declared property) DaemonAgent::$previousCheckinAt. #160 auto-unpark path untouched. - app/Models/DaemonAgent.php — declared public ?CarbonInterface $previousCheckinAt (never an attribute → never persisted/serialized). - app/Console/Commands/DaemonCheckin.php — renders the digest after reportOutcome; branch/repoPath from the CLI's own getcwd() checkout (authoritative, so git filtering works). Best-effort (try/catch → warn, never fails the heartbeat). - app/Mcp/Tools/DaemonCheckinTool.php — adds commits_since_last_ping to the structured response, omitted when null. Branch from the linked Session.external_session_id git_branch (falls back to project primaryBranch()); repoPath from project root_path. Best-effort. - config/flower.php — flower.daemons.checkin_digest {max_commits=15, scan_limit=60, subject_limit=80, file_limit=5}. TESTS (all green; full suite 982 passed / 1 pre-existing skip; pint clean): - NEW tests/Feature/Daemons/CheckinCommitDigestServiceTest.php (11 cases): omit-no-prior-ping, omit-empty-window, since-last-ping window, own-project scope, cap + "+N more since HH:MM", brief grouping (collapse + newest-first group order + ungrouped null group), subject truncation + file cap, branch-aware filter (stubbed ancestry), degrade-without-repo, global-daemon-no-project, and checkin() exposes previousCheckinAt while preserving #160 auto-unpark. - tests/Feature/Mcp/DaemonRosterToolsTest.php: +1 end-to-end wiring case — first check-in omits the section, a commit lands (Brief: #128 trailer), second check-in's MCP structured response carries commits_since_last_ping with total/since/brief-grouped commit. NOTES for the merge point: my branch base (master@d707d36) is behind the current master tip (2115bec) — unrelated work (AttentionSignal/DecisionService/decisions/search-console/rooms) merged after I branched. My changes are isolated to the daemon-checkin files and don't touch any of it, so the merge should be clean. Did NOT merge (orchestrator owns that). v1 intentionally env-infers the branch (no project primary-branch config) per the spec's parked follow-up.

    agent · flower-128-checkin-digest-worker
  8. participant joined 1d ago
    system · flower-128-checkin-digest-worker
  9. comment 1d ago

    Target branch flower/128-checkin-commits-digest is merged to the default branch; suggest marking the brief complete.

    system · system:brief-autolink
  10. participant joined 1d ago
    system · system:brief-autolink
  11. dispatched 1d ago

    Dispatch request #91 queued for flower.

    agent · flower-orchestrator
  12. status change 1d ago
    agent · flower-orchestrator
  13. participant joined 1d ago
    system · flower-orchestrator
  14. link added 1d ago
    agent · flower-refine
  15. link added 2d ago
    agent · flower-refine
  16. link added 2d ago
    agent · flower-refine
  17. status change 2d ago
    agent · flower-refine
  18. plan proposed 2d ago

    ## Ask Add a bounded **"commits since your last ping"** section to the daemon check-in response so standing daemons stay aware of movement landing elsewhere over an active session — a PR merged, a dependency cleared — without pulling anything. ## Motivation Daemons currently have zero visibility into what merged while they poll: a refine daemon can't tell that a brief it refined just shipped, or that (e.g.) auto-dispatch work landed. flower already ingests commits and parses the `Brief: #id` trailer, so the highest-value signal is cheap to surface right in the check-in the daemon already runs. ## Scope — v1 On each `flower:daemon-checkin` (command output **and** the `daemon_checkin` MCP response), include a **`commits_since_last_ping`** section. ### Which commits - Commits that landed on **the branch the daemon's environment is currently checked out into** — resolve from the running environment / worktree; **do NOT assume `master`/`main`** (primary branch varies per project). (For now the daemon's checked-out branch IS the "active/merged-into" branch by convention.) - **Own-project scope** only. - Landed **between the daemon's previous check-in and now** (commit date after the prior check-in timestamp). **Zero commits → omit the section entirely.** ### Per-commit shape (lean) - short sha · **subject (first line, truncated to ~80 chars + ellipsis** when longer) · **linked `#brief` id** (from the `Brief:` trailer) when present · up to **5** files touched (`+K more`). ### Bloat guards (hard — this is the whole point of keeping it lean) - Cap at **~15 newest** commits; if more, append **`+N more since HH:MM`**. - **Group by brief** where possible (commits sharing a `Brief: #id` collapse under it, e.g. "#117 — 3 commits"), so long lists read as movement, not noise. - Subject truncation (above) + 5-file cap + omit-when-empty. - Respect #106's checkin-payload discipline (this is an *additive* bounded section; keep it small). ## Why the brief link is the payoff The `Brief: #id` trailer turns raw commits into actionable awareness: a daemon instantly learns "a brief I touched merged" or "a dependency cleared" and can react on its next tick instead of staying stale for a poll interval (up to 120 min when dormant). ## Related / future (NOT v1) - **Project-level "primary branch" config** — a per-project setting for the primary/deployed branch, defaulted from the checked-out branch at import or inferred from worktrees, instead of env-inferring it. Would make this feature (and others) branch-explicit. **Candidate for its own brief** (operator was "wondering" about it; env-inferred is fine for v1). - The same "since last ping" digest could later carry other movement (newly-`planned` briefs, dependency-clears, roster changes) — v1 is commits only. - **Cross-project awareness** for a daemon working across projects — parked as a future brainstorm (operator: not now). - **Sibling of #106** (daemon-runtime context-efficiency review): #106 *trims* the checkin payload, this *adds* a bounded one — together they make the check-in response a lean "while you were away" briefing. ## Acceptance - `flower:daemon-checkin` (+ MCP response) returns a bounded `commits_since_last_ping` for the daemon's checked-out branch + own project since the prior check-in: short sha / truncated subject / linked `#brief` / ≤5 files, capped ~15 + "+N more since HH:MM", grouped by brief, omitted when empty. - No unbounded growth across a long dormant gap. - `php artisan test` green + pint. `Brief: #128` trailer. ## Provenance Operator idea (2026-07-03), refined with the operator: branch = env-checked-out (not master/main); own-project; cap ~15 + group by brief; subject truncation; brief-link included. Speced by flower-refine. Related: #106.

    agent · flower-refine
  19. note added 2d ago

    Operator idea, refined with operator (2026-07-03). Add a bounded "commits since last ping" section to the daemon check-in response so standing daemons stay aware of what landed while they polled (e.g. a PR merged, a dependency cleared). Decisions: report commits on the daemon's CURRENT CHECKED-OUT branch in its env (do NOT assume master/main); own-project scope; per-commit = short sha + truncated subject + linked #brief (Brief: trailer) + ≤5 files; cap ~15 newest + "+N more since HH:MM", grouped by brief; omit when empty. Sibling to #106. Full spec via brief_update_spec.

    agent · flower-refine
  20. participant joined 2d ago
    system · flower-refine

epic · dependencies

Relationships

epic parent

depends on

No dependencies — dispatchable once planned.

agents · waves

Participants

  • flower-refine participant · active
  • flower-orchestrator participant · active
  • system:brief-autolink participant · active
  • flower-128-checkin-digest-worker participant · active
  • system:commit-trailer participant · active

trace · graph

Links

  • Commit #3988 execution
  • Commit #3989 execution
  • Scratchpad #378 execution
  • Scratchpad #375 execution
  • Scratchpad #364 execution

scope

Projects

  • flower · primary

dogfood · read-only

Agent’s-eye view

The literal recall_brief payload an agent gets — same service path as the MCP tool.