# NousResearch/hermes-agent · Kanban completed-run metadata panel visual styling

## Open now

- Nothing open on GitHub.

These issues and PRs address the completed-run metadata panel on the Kanban dashboard rendering as an overly large, visually alarming highlighted box. The work involves toning down its appearance and adding native collapse behavior.

## TL;DR

- 3 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 1 PR(s) closed without merging.
- A fix was merged to main in PR #23268. Verify it addresses your case.
- **Recommended:** read PR #23268 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `unresolved`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.67`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #19548: Kanban completed-run metadata renders as alarming large highlighted box

## Prior & competing PRs

- **#23268: fix(kanban-dashboard): tone down completed-run metadata panel + native collapse (salvage #19980)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `plugins/kanban/dashboard/dist/index.js`, `plugins/kanban/dashboard/dist/style.css`, `tests/plugins/test_kanban_dashboard_plugin.py`
  - fix hunks:
  - `plugins/kanban/dashboard/dist/index.js`

    ```diff
    @@ -2397,9 +2397,18 @@
               r.error
                 ? h("div", { className: "hermes-kanban-run-error" }, r.error)
                 : null,
    -          r.metadata
    -            ? h("code", { className: "hermes-kanban-run-meta" },
    -                JSON.stringify(r.metadata))
    +          (r.metadata && Object.keys(r.metadata).length > 0)
    +            ? (function () {
    +                var json = JSON.stringify(r.metadata, null, 2);
    +                var collapsed = json.length > 300;
    +                return h("details", {
    +                    className: "hermes-kanban-run-meta-block",
    +                    open: !collapsed,
    +                  },
    +                  h("summary", { className: "hermes-kanban-run-meta-label" }, "Metadata"),
    +                  h("code", { className: "hermes-kanban-run-meta" }, json),
    +                );
    +              })()
                 : null,
             );
           }),
    ```
  - `plugins/kanban/dashboard/dist/style.css`

    ```diff
    @@ -863,15 +863,56 @@
       padding: 0.15rem 0 0;
       font-family: var(--font-mono, ui-monospace, monospace);
     }
    +/* Run metadata is a secondary detail panel. Render it as a clearly-labeled
    + * sub-block with a thin left rule, capped height, and muted treatment so
    + * a verbose JSON blob (e.g. changed_files + URLs from a writer task) does
    + * not visually swamp the parent run row or get mistaken for a crash dump.
    + * Uses a native <details>/<summary> pair so collapse is browser-handled
    + * (zero JS); large blobs default collapsed via the open=false attribute.
    + * See issue #19548. */
    +.hermes-kanban-run-meta-block {
    +  margin-top: 0.4rem;
    +  padding: 0.25rem 0.5rem;
    +  border-left: 2px solid var(--color-border);
    +  background: transparent;
    +}
    +.hermes-kanban-run-meta-block > summary.hermes-kanban-run-meta-label {
    +  cursor: pointer;
    +  list-style: none;
    +}
    +.hermes-kanban-run-meta-block > summary.hermes-kanban-run-meta-label::-webkit-details-marker {
    +  display: none;
    +}
    +.hermes-kanban-run-meta-block > summary.hermes-kanban-run-meta-label::before {
    +  content: "▶ ";
    +  display: inline-block;
    +  font-size: 0.6rem;
    +  margin-right: 0.25rem;
    +  transition: transform 120ms ease;
    +}
    +.hermes-kanban-run-meta-block[open] > summary.hermes-kanban-run-meta-label::before {
    +  transform: rotate(90deg);
    +}
    +.hermes-kanban-run-meta-label {
    +  font-size: 0.65rem;
    +  font-weight: 600;
    +  text-transform: uppercase;
    +  letter-spacing: 0.06em;
    +  color: var(--color-muted-foreground);
    +  padding-bottom: 0.15rem;
    +}
     .hermes-kanban-run-meta {
       display: block;
    +  max-height: 8.5rem;
    +  overflow: auto;
       font-size: 0.72rem;
       line-height: 1.5;
    -  padding: 0.15rem 0 0;
    +  padding: 0;
       color: var(--color-muted-foreground);
       white-space: pre-wrap;
       word-break: break-word;
       font-family: var(--font-mono, ui-monospace, monospace);
    +  background: transparent;
     }
     
     /* -------------------------------------------------------------------------
    ```
  - `tests/plugins/test_kanban_dashboard_plugin.py`

    ```diff
    @@ -1785,3 +1785,97 @@ def test_dashboard_lane_head_preserves_assignee_casing():
             "Lane head must not visually uppercase profile names — see #21320 "
             "and the explanatory comment in the CSS rule."
         )
    +
    +
    +# ---------------------------------------------------------------------------
    +# Built-asset regressions for the dashboard's run-history rendering
    +# (issue #19548 — completed-run metadata used to render as a large pale box
    +# that read like a crash dump). The plugin ships built-only, so we lock in
    +# the rendered shape with static assertions on dist/index.js + dist/style.css.
    +# ---------------------------------------------------------------------------
    +
    +
    +def _dashboard_dist_path(name: str) -> Path:
    +    repo_root = Path(__file__).resolve().parents[2]
    +    p = repo_root / "plugins" / "kanban" / "dashboard" / "dist" / name
    +    assert p.exists(), f"dashboard asset missing: {p}"
    +    return p
    +
    +
    +def test_run_metadata_pretty_printed_with_label():
    +    """Run-history metadata is pretty-printed JSON inside a labeled sub-block."""
    +    js = _dashboard_dist_path("index.js").read_text(encoding="utf-8")
    +    # Pretty-printed JSON (indent=2) so a writer task's changed_files +
    +    # URLs blob doesn't render as one wall-of-text monoline.
    +    assert "JSON.stringify(r.metadata, null, 2)" in js
    +    # Explicit label so the panel reads as auxiliary detail, not a crash dump.
    +    assert '"hermes-kanban-run-meta-label"' in js
    +    assert '"Metadata"' in js
    +    # Wrapped in the labelled meta block container.
    +    assert '"hermes-kanban-run-meta-block"' in js
    +
    +
    +def test_run_metadata_secondary_styling():
    +    """Metadata block is capped, transparent, and visually secondary."""
    +    css = _dashboard_dist_path("style.css").read_text(encoding="utf-8")
    +    # The label class exists with muted-foreground treatment.
    +    assert ".hermes-kanban-run-meta-label" in css
    +    # Container styling: thin left rule, no opaque highlighted fill that
    +    # could be mistaken for an error/warning panel.
    +    assert ".hermes-kanban-run-meta-block" in css
    +    block_start = css.index(".hermes-kanban-run-meta-block {")
    +    block_decl = css[block_start : block_start + 400]
    +    assert "background: transparent" in block_decl
    +    assert "border-left" in block_decl
    +    # Cap meta height so verbose JSON doesn't sprawl across the run row.
    +    meta_start = css.index(".hermes-kanban-run-meta {")
    +    meta_decl = css[meta_start : meta_start + 400]
    +    assert "max-height" in meta_decl
    +    assert "overflow: auto" in meta_decl
    +    assert "color: var(--color-muted-foreground)" in meta_decl
    +
    +
    +def test_run_metadata_uses_native_collapse():
    +    """Metadata panel uses <details>/<summary> for zero-JS collapse.
    +
    +    Native <details> means the browser handles state — no event handlers,
    +    no React-state coupling, accessible by default (keyboard navigable,
    +    screen-reader announces the disclosure state). Default-open state is
    +    decided per-render based on payload length.
    +    """
    +    js = _dashboard_dist_path("index.js").read_text(encoding="utf-8")
    +    # Element must be <details> / <summary>, not plain <div>s.
    +    assert 'h("details"' in js
    +    assert 'h("summary"' in js
    +    # The open prop is computed from json length (collapsed when verbose).
    +    assert "open: !collapsed" in js or "open:!collapsed" in js
    +    assert "json.length > 300" in js
    +
    +
    +def test_run_metadata_skips_empty_object():
    +    """Empty `{}` metadata renders nothing — no useless labeled block.
    +
    +    `r.metadata && {} && ...` would render a "Metadata" labeled block
    +    containing just `{}`, which is visual noise. The render predicate now
    +    also checks Object.keys(r.metadata).length > 0.
    +    """
    +    js = _dashboard_dist_path("index.js").read_text(encoding="utf-8")
    +    assert "Object.keys(r.metadata).length > 0" in js
    +
    +
    +def test_run_metadata_disclosure_indicator_styled():
    +    """Native disclosure marker is hidden + replaced with a CSS-only chevron.
    +
    +    Browsers render an OS-specific arrow next to <summary> by default. For a
    +    consistent look across OSes the hermes dashboard hides that marker and
    +    renders a CSS ::before chevron that rotates on [open]. Pin it so a
    +    future CSS rebuild can't silently lose it (which would put two markers
    +    side-by-side on Firefox/WebKit).
    +    """
    +    css = _dashboard_dist_path("style.css").read_text(encoding="utf-8")
    +    # Default markers suppressed.
    +    assert "list-style: none" in css
    +    assert "::-webkit-details-marker" in css
    +    # CSS-only chevron present + animates on open state.
    +    assert ".hermes-kanban-run-meta-block[open]" in css
    +    assert "rotate(90deg)" in css
    ```
- **#19980: fix(kanban-dashboard): tone down completed-run metadata panel**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `#23268`

## Fix status

- Merged to main in PR #23268 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-05-10`.
