feat(control-plane): show the coding agent's logo on documents and memories - #3079
Merged
Conversation
…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
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.
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Documents retained by
hindsight-coding-agentssay which coding agent wrote them —metadata.harness = "claude-code"plus aharness:<id>tag — but the control planerendered that as just another
key=valuechip, indistinguishable fromsession_idwhile 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:
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.Harnessrow.Harnesscard 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
MetadataChipinstead of a new treatment.The convention
src/lib/harness-logo.tsis the one place the mapping lives, and it holds exactly theids that integration emits —
claude-code,codex,cursor-cli,gemini,opencode(see its
src/harness/hook-lifecycle.tsandsrc/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/intopublic/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
Harnesslabel moved to the sharedcommonnamespace now that two views use it;memoryDetailModal.sectionMetadatareuses each locale's existing translation of"Metadata" rather than inventing a second wording. All 10 locales updated.
getMemory's client type gained themetadatafield the endpoint already returned.documents-view.tsx.Testing
tests/lib/harness-logo.test.ts— resolution,harness:<id>tag fallback, metadataprecedence, normalisation, registry-matches-emitted-set, and a guard that every entry's
asset actually ships in
public/.dialogs, and the Codex mark still legible in dark mode.