Skip to content

feat(control-plane): show the coding agent's logo on documents and memories - #3079

Merged
nicoloboschi merged 1 commit into
mainfrom
feat/harness-logos-cp
Jul 30, 2026
Merged

feat(control-plane): show the coding agent's logo on documents and memories#3079
nicoloboschi merged 1 commit into
mainfrom
feat/harness-logos-cp

Conversation

@nicoloboschi

Copy link
Copy Markdown
Collaborator

What

Documents retained by hindsight-coding-agents say which coding agent wrote them —
metadata.harness = "claude-code" plus a harness:<id> tag — but the control plane
rendered that as just another key=value chip, indistinguishable from session_id
while scanning a column of near-identical conversation:<uuid> IDs.

This resolves the value to the agent's logo, as a convention rather than a one-off:

  • Documents table — the mark trails the "Updated …" line. It deliberately does not
    lead the ID: as a leading mark it only exists on some rows, so every ID shifted
    horizontally depending on whether its document had one. The now-redundant harness=
    metadata chip is dropped from the row (chip slots there are scarce); the
    harness:<id> tag stays, because clicking it filters the list.
  • Document dialog — logo beside the title, plus a Harness row.
  • Memory dialog — a Harness card in the Document tab, next to the document's tags.
    Memory units inherit the document's metadata at retain time, so the value is read off
    the memory itself and needs no second lookup. That tab also gained the document's
    metadata, rendered with the shared MetadataChip instead of a new treatment.

The convention

src/lib/harness-logo.ts is the one place the mapping lives, and it holds exactly the
ids that integration emits — claude-code, codex, cursor-cli, gemini, opencode
(see its src/harness/hook-lifecycle.ts and src/harness/registry.ts, added in #2522).
A test asserts the registry stays in step with that set: an id nothing writes is a logo
nothing renders. Adding an agent there means adding it here in the same change — copy its
icon from hindsight-docs/static/img/icons/ into public/img/harness/, add one entry.

An unregistered harness is not an error: no logo, and the value still shows as ordinary
metadata. Written up in CLAUDE.md.

Monochrome marks (Codex, Cursor CLI) are flagged so only they get dark:invert
inverting a multi-colour mark like Gemini would misrepresent the brand.

Notes

  • The Harness label moved to the shared common namespace now that two views use it;
    memoryDetailModal.sectionMetadata reuses each locale's existing translation of
    "Metadata" rather than inventing a second wording. All 10 locales updated.
  • getMemory's client type gained the metadata field the endpoint already returned.
  • Observations have no Document tab, so they show no harness — out of scope here.
  • Expect a textual conflict with hindsight-coding-agents: harness-pluggable long-term memory for coding agents #2522, which also touches documents-view.tsx.

Testing

  • tests/lib/harness-logo.test.ts — resolution, harness:<id> tag fallback, metadata
    precedence, normalisation, registry-matches-emitted-set, and a guard that every entry's
    asset actually ships in public/.
  • Verified in the running control plane against a real bank: logos in the table, both
    dialogs, and the Codex mark still legible in dark mode.

…mories

Documents retained by hindsight-coding-agents carry the agent that wrote them
as `metadata.harness` plus a `harness:<id>` tag, but the UI rendered that as
just another `key=value` chip — indistinguishable from `session_id` while
scanning a column of near-identical `conversation:<uuid>` IDs.

Resolve the value to a logo instead:

- documents table: the mark trails the "Updated …" line (leading the ID shifted
  every row that had no harness), and the now-redundant `harness=` metadata
  chip is dropped — the `harness:<id>` tag stays, since clicking it filters
- document dialog: logo in the title, plus a Harness row
- memory dialog: a Harness card in the Document tab, next to the document's
  tags — memory units inherit the document's metadata at retain time, so no
  second lookup is needed. That tab also gained the document's metadata,
  rendered with the shared MetadataChip

The registry holds exactly the ids that integration emits (claude-code, codex,
cursor-cli, gemini, opencode; see its src/harness/hook-lifecycle.ts) and a test
asserts it stays in step — an id nothing writes is a logo nothing renders. An
unregistered harness is not an error: no logo, value still shown as metadata.

Monochrome marks are flagged so only they get `dark:invert`; multi-colour ones
are left alone.
@nicoloboschi
nicoloboschi merged commit aa38790 into main Jul 30, 2026
93 checks passed
@nicoloboschi
nicoloboschi deleted the feat/harness-logos-cp branch July 30, 2026 14:54
nicoloboschi added a commit that referenced this pull request Jul 31, 2026
)

#3079 resolved `metadata.harness` to a logo, but registered only the five ids
hindsight-coding-agents emitted at the time. That integration (#2522) now ships
ten, so the majority of harnesses fell back to a raw `harness=<id>` metadata chip
— the exact thing the logo was introduced to replace.

Register the full emitted set, taken from both places that define an id:
`src/harness/hook-lifecycle.ts` (one HookSpec per hook-driven agent) and the
persistent-plugin entrypoints in `src/harness/registry.ts`, whose id is their
`createPluginEntry(...)` argument. New: `antigravity-cli`, `cline-cli`,
`copilot-cli`, `devin-cli`, `grok-build`, `kilo`.

Icons come from `hindsight-docs/static/img/icons/` where the docs site already
carries the brand (Cline, GitHub Copilot, Devin, Grok). It carries none for
Antigravity or Kilo, so those are the vendors' own marks; the registry comment
and CLAUDE.md now say that is allowed rather than implying the docs dir is the
only source.

`gemini` stays registered even though the integration replaced that harness with
`antigravity-cli` and nothing emits it any more: documents retained while it did
are still in people's banks and should keep their logo. The test that pins the
registry to the emitted set now carries that as an explicit RETIRED list, so a
speculative id still can't sneak in.

Monochrome dark-on-transparent marks (Cline, Copilot, Devin) get `dark:invert`.
Grok deliberately does not — it is a filled black tile with a white glyph, so it
reads on dark already and inverting would burn a white square into the row.
Verified all eleven at 16px against both themes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant