Skip to content

feat(kanban): surface task_runs.summary on dashboard cards + kanban show#20251

Closed
Brecht-H wants to merge 1 commit into
NousResearch:mainfrom
Brecht-H:fix/kanban-surface-task-runs-summary-2026-05-05
Closed

feat(kanban): surface task_runs.summary on dashboard cards + kanban show#20251
Brecht-H wants to merge 1 commit into
NousResearch:mainfrom
Brecht-H:fix/kanban-surface-task-runs-summary-2026-05-05

Conversation

@Brecht-H

@Brecht-H Brecht-H commented May 5, 2026

Copy link
Copy Markdown
Contributor

Summary

The kanban-worker skill (built into the gateway dispatcher's spawn prompt) instructs every worker to hand off via kanban_complete(summary=..., metadata=...). That writes the summary onto the closing task_runs row, not onto tasks.result — the latter is left NULL unless the caller explicitly passes result=.

A glance at the dashboard or hermes kanban show <id> then shows a blank "Result:" section even when the worker did real work. On a multi-lane host this caused a 2026-05-05 false-alarm ("Hermes did nothing") on a task whose run carried a 10-line completion summary.

This PR surfaces the latest non-null run summary as latest_summary so the worker's actual handoff lands in front of operators.

Changes

  • New helpers kanban_db.latest_summary(conn, task_id) and kanban_db.latest_summaries(conn, task_ids). The batch variant uses a single window-function SELECT so the dashboard board endpoint doesn't pay N+1 on multi-hundred-task boards.
  • CLI hermes kanban show <id> prints a Latest summary: block when tasks.result is empty but a run has produced a summary. The existing Result: section still wins when populated, so any hand-edited results path is untouched. JSON output gains a top-level latest_summary field.
  • Dashboard /board and /tasks/{id} now include a latest_summary field on every task. Cards on /board carry a 200-character preview; the drawer/detail endpoint returns the full summary.
  • Five new tests cover: empty-runs case, post-complete surface, newest-of-multiple selection, empty-string skip, batch with missing tasks + empty input.

Test plan

  • 5/5 new latest_summary* unit tests pass.
  • Full kanban suite — 255/255 in tests/hermes_cli/test_kanban_* + 91/91 in tests/plugins/test_kanban_dashboard_plugin.py + tests/tools/test_kanban_tools.py.
  • Smoke-tested against the live profile DB on the three acceptance targets (t_f08fef91, t_007b7f1c, t_05746fa4) — all return populated summaries via both helpers.
  • Reviewer: open the dashboard on a populated DB, confirm done-status cards now display a non-blank latest_summary preview.
  • Reviewer: run hermes kanban show <id> on a task whose worker called kanban_complete(summary=...) (e.g. one of the three above) and verify the new Latest summary: block.

Back-compat

  • Tasks where tasks.result IS populated (manual completion via hermes kanban complete <id> --result \"...\") keep the existing Result: section — latest_summary is only used as a fallback when tasks.result is empty.
  • _task_dict adds latest_summary as a new keyword argument with a None default, so existing callers (create-task / update-task responses) work unchanged and emit latest_summary: null in their payloads.

🤖 Generated with Claude Code

… show``

The kanban-worker skill (built into the gateway dispatcher's spawn
prompt) instructs every worker to hand off via
``kanban_complete(summary=..., metadata=...)``. That writes the summary
onto the closing ``task_runs`` row, NOT onto ``tasks.result`` — the
latter is left NULL unless the caller passes ``result=`` explicitly.

Result: a glance at the dashboard or ``hermes kanban show <id>`` shows
a blank "Result:" section even when the worker did real work, which
on 2026-05-05 caused a Mac false-alarm ("Hermes did nothing") on a
task that had a 10-line completion summary on its run.

This patch surfaces the latest non-null run summary as
``latest_summary`` so the worker's actual handoff lands in front of
operators.

* New helpers ``kanban_db.latest_summary(conn, task_id)`` and
  ``kanban_db.latest_summaries(conn, task_ids)``. The batch variant
  uses a single window-function SELECT so the dashboard board endpoint
  doesn't pay an N+1 cost on multi-hundred-task boards.
* CLI ``hermes kanban show <id>`` prints a "Latest summary:" block
  when ``tasks.result`` is empty but a run has produced a summary
  (the existing "Result:" section still wins when populated, so the
  back-compat path for hand-edited results is untouched). JSON output
  gains a top-level ``latest_summary`` field.
* Dashboard ``/board`` and ``/tasks/{id}`` now include a
  ``latest_summary`` field on every task. Cards on /board carry a
  200-character preview (cheap to render, plenty for "what did this
  worker do?" at a glance); the drawer/detail endpoint returns the
  full summary.
* Five new tests cover: empty-runs case, post-complete surface,
  newest-of-multiple selection, empty-string skip, batch with
  missing tasks + empty input.

Smoke-tested locally against the live profile DB on the three
acceptance-criterion targets (t_f08fef91 cron-hygiene-audit,
t_007b7f1c EMA-analysis, t_05746fa4 self-assessment) — all three now
return their populated summaries via both ``latest_summary`` and
``latest_summaries``.

Test plan: 255/255 kanban tests pass + 91/91 dashboard plugin tests
pass. No regression on tasks where ``tasks.result`` is explicitly
populated (the existing "Result:" branch is preserved).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 5, 2026 14:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR makes kanban task run handoffs visible to operators by surfacing the latest non-empty task_runs.summary as latest_summary in both the dashboard API and the CLI kanban show output, avoiding blank “Result” sections when workers complete via kanban_complete(summary=...).

Changes:

  • Add kanban_db.latest_summary() and batch kanban_db.latest_summaries() helpers to fetch the latest non-empty run summary (batch via a single window-function query).
  • Extend dashboard /board (preview-truncated) and /tasks/{id} (full text) responses to include latest_summary per task.
  • Update hermes kanban show <id> to print a Latest summary: block (and include latest_summary in JSON output) when tasks.result is empty.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
hermes_cli/kanban_db.py Adds single-task and batch DB helpers to retrieve latest non-empty run summaries.
plugins/kanban/dashboard/plugin_api.py Attaches latest_summary to task payloads for board cards (preview) and task detail (full).
hermes_cli/kanban.py Enhances kanban show to surface the run summary when task.result is empty; JSON includes latest_summary.
tests/hermes_cli/test_kanban_db.py Adds unit tests covering latest_summary/latest_summaries behavior and edge cases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +813 to +820
# row to exist with a later ended_at.
conn.execute(
"UPDATE tasks SET status='ready', completed_at=NULL WHERE id=?",
(t,),
)
# Sleep 1s so the second run's ended_at is provably later than
# the first (complete_task uses int(time.time())).
time.sleep(1.05)
Comment thread hermes_cli/kanban_db.py
Comment on lines +3497 to +3504
Picks the most recent run by ``ended_at`` (falling back to ``id``
for ties or unfinished rows). Returns None if no run has a summary.
"""
row = conn.execute(
"SELECT summary FROM task_runs "
"WHERE task_id = ? AND summary IS NOT NULL AND summary != '' "
"ORDER BY COALESCE(ended_at, started_at) DESC, id DESC LIMIT 1",
(task_id,),
Comment thread hermes_cli/kanban_db.py
Comment on lines +3526 to +3542
placeholders = ",".join("?" for _ in ids)
rows = conn.execute(
f"""
SELECT task_id, summary FROM (
SELECT task_id, summary,
ROW_NUMBER() OVER (
PARTITION BY task_id
ORDER BY COALESCE(ended_at, started_at) DESC, id DESC
) AS rn
FROM task_runs
WHERE task_id IN ({placeholders})
AND summary IS NOT NULL AND summary != ''
) WHERE rn = 1
""",
ids,
).fetchall()
return {r["task_id"]: r["summary"] for r in rows}
@teknium1

teknium1 commented May 6, 2026

Copy link
Copy Markdown
Contributor

Merged via PR #20448 (rebase-merge, commit 141f6b1d). Your commit is on main with authorship preserved (re-written from hermes@orion.local to Brecht-H@users.noreply.github.com to pass CI's attribution check, same pattern as earlier PRs). The latest_summary surface is a real operator-UX win — cards were blank for tasks where workers handed off via task_runs.summary. Both the window-function batch helper and the CLI integration are clean.

#20448

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants