Skip to content

Use context-aware identity names with human-first priority - #167

Merged
loganj merged 14 commits into
mainfrom
feat/context-aware-names
Sep 24, 2026
Merged

loganj merged 14 commits into
mainfrom
feat/context-aware-names

Conversation

@loganj

@loganj loganj commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

🤖

Summary

People and agents can share a name. Previously, unrelated names elsewhere in the app could add a qualifier in a channel that had no conflict, and different screens did not always use the same naming rule. This change compares the identities relevant to each screen, keeps the highest-priority name readable, and qualifies only the identities that need it.

The rule is supplied by a separate, replaceable Identity Naming plugin, so another installation can choose different rules without changing each screen.

For example, a human Honey keeps that name. Your agent becomes Honey (agent) and another person's agent becomes Wes’s Honey. A channel with one Larry shows Larry, while the mention picker can distinguish several eligible Larrys.

Principles and priority

  1. Humans before agents; mine before others within each type. Priority is: signed-in human → other humans → viewer-owned agents → other agents.
  2. Unique names stay plain. Compare current channel members, DM participants, or the complete eligible choices for the control—not every identity ever loaded.
  3. Readable qualifiers before keys. Use (agent) for your agent when it collides with a human, or an owner's possessive name for another person's agent when owner facts are available.
  4. No arbitrary winner among equals. Equal-priority conflicts retain any readable qualifier, then get the last four characters of their npub (the encoded public identity key). Extend the suffix only when needed. If even the full key collides with a literal name, append an increasing counter to that full key.
  5. Recheck final labels. A generated qualifier can collide with a literal name or another generated label. Repeat resolution until the labels are distinct.
  6. Names are display information, not authority. Recipient keys, process targets, permissions, authored message text, and configured names do not change. Matching trims surrounding whitespace and is case-sensitive.

Truth table

· abcd below means a public-key suffix, not an arbitrary counter. “Mine” means owned by the signed-in viewer.

Identities in the comparison set Displayed result
One Juniper Juniper
Viewer human Alex + another human Alex Alex; Alex · abcd
Two other humans named Honey Honey · abcd; Honey · efgh
Human Honey + my agent Honey Honey; Honey (agent)
Human Honey + Wes's agent Honey Honey; Wes’s Honey
Human Honey + my agent + Wes's agent Honey; Honey (agent); Wes’s Honey
My agent Honey + Wes's agent Honey Honey; Wes’s Honey
Two of my agents named Honey Both Honey · <suffix>
Two Honey agents owned by Wes Both Wes’s Honey · <suffix>
Human Honey + two of my Honey agents Human Honey; both agents Honey (agent) · <suffix>
Honey agents with different owners both called Wes Both Wes’s Honey · <suffix>
Two Honey agents without owner facts Both Honey · <suffix>
Unknown-owner Honey agent + Wes's Honey agent Honey; Wes’s Honey—readable qualification avoids keys
Human Honey + unknown-owner Honey agent Honey; Honey (agent)
Generated Wes’s Honey conflicts with a literal human name Literal stays; agent becomes Wes’s Honey · <suffix>
Generated Honey (agent) conflicts with a literal human name Literal stays; agent becomes Honey (agent) · <suffix>
Same last-four key ending Extend: e.g. Echo · 6z0h9; Echo · 2z0h9
Generated Honey · jus6 conflicts with that literal human name Literal stays; generated label extends to Honey · wjus6
Honey and honey Distinct; both plain
Honey and Honey Same trimmed name; normal priority/tie rules apply

The priority rule applies again to each generated collision. A literal name is not an unconditional exception that overrides identity priority.

Complete touched UX inventory

Every request supplies an exact public identity key and fallback text. The host supplies the signed-in viewer and loaded profile facts: name, agent status, and owner key. Ready library names and current-community managed-agent names also contribute facts; configured names take precedence. Readable owner names can come from outside the comparison set.

In this table, channel set means the current channel members plus the requested identity. That last inclusion allows former members to be labeled. It does not add every historical author. If membership is unavailable, the request uses the target alone. Unless stated, callers add no local identity facts. Fallback text alone is not a new fact supplied to the policy.

UX surface Identity / fallback supplied Comparison set and extra facts
Message header, avatar fallback and “View … profile” label Author; profile name or key prefix Message's channel set
Thread root and reply authors Same message-row inputs Each message's channel set
Exact selected session message Same message-row inputs Session channel set
Media-review comment authors Same message-row inputs Comment's channel set
Thread-participant avatar names/title tooltips Each participant; profile name or key prefix Message's channel set, not just participants
Sent mention chips and available explicit profile links Bound recipient or exact linked profile key; authored label Containing channel set; recipient key, notification intent and source stay unchanged. Unavailable explicit profile links remain literal
Recognized person/agent reference path in ReferenceText Referenced key; parsed label Helper changed to channel scope, but its only production caller passes no person recipients. No separate person-reference tooltip is reachable here; bound sent mentions use the preceding path. Channel references retain their channel labels
Join/leave rows, summaries and member avatars Actor/member; profile name or key prefix Timeline's channel set
Typing indicator Typing identity; profile name or key prefix Composer's channel set, not only current typists
Sidebar unread-thread activity popover Activity author; profile name or “Someone” Activity item's channel set
In-channel agent-activity accessory Active agent; loaded profile/key fallback Accessory's channel set
Profile panel heading and dependent name display Opened profile; profile name or “Unknown profile” Opening channel's set; target only with no channel context
Message-link preview author Linked author; profile/key fallback Linked message's channel, not the source of the link
Message-link preview DM label Each participant; profile name or key prefix Linked DM participants
DM navigation and conversation header Each participant; profile name or key prefix That DM's participants; empty remains “Notes to self”
Global search DM result label Each participant; profile name or key prefix Result DM participants
Global search message-author detail Author; profile name or key prefix Result's loaded channel members; target only if unavailable
Message-notification sender Incoming author; notification formatter retains its fallback Incoming channel set, evaluated when text is produced
Mention picker Recipient; profile/member/agent-choice name or key prefix All eligible choices before search or the 100-row cap
Inline @ completion Same as picker Same complete eligible set, before query filtering
Selected recipient chips Selected key; stored recipient name Members + eligible outside local agents + shared agent choices in invite-agent mode + selected keys. Adds name facts only for unresolved selected identities; also asks the policy for chip qualifier presentation
New/existing session agent menu and selected button Shared agent-choice identity; source name All shared choices from the ready library and same-community managed agents, including restricted actions; permission flags do not shrink naming scope
Activity panel “Observed agents” selector Snapshot choice; profile name or “Agent · npub…suffix” with a distinct local key suffix Unique snapshot agent keys plus selected key, not narrowed by channel filter
Native managed-agent title, avatar and action labels Managed key; configured name Entire local controller snapshot, including other communities. Compares every displayed configured alias across distinct keys, including other communities; repeated configurations of one key are not namesakes. The requested row retains its configured name
Native agent editor heading, avatar and description Edited key; configured name Same controller set and facts; editable settings retain actual configured values
Read-only library custom/unknown cards and identities inside template cards Library key; library name Union of displayed groups/custom/unknown identities after archive grouping—not one group at a time. Template headings are not identity names

Scope boundaries: ordinary outside-agent mention choices remain locally managed agents for the same community, eligible for supported non-archived stream/forum channels. Invite-agent mode adds library choices. This does not discover every relay agent or grant access. Picker and channel labels can differ because their comparison sets differ. Native expanded exact-identity details, import-preview names, and configuration fields remain unchanged. Timeline measurement uses the same scoped labels so membership-row size updates correctly.

Shared policy, local context

A separate Identity Naming plugin owns the pure naming rule. The host owns facts, subscriptions and cached results; each UI supplies its comparison set. The plugin is independent of the Agents feature and can be replaced by another policy. Only one policy may be active. The author-facing plugin contract and native plugin catalog include it. Draft chips no longer maintain a competing local naming rule.

Eight representative screenshots

These show the real application UI and naming plugin with synthetic identities and a local transport. No real profiles were renamed. They illustrate the naming behavior before the main-branch rebase; unrelated navigation and notification styling may differ.

1. Human-first, then ownership

Honey stays plain for the human; the viewer-owned agent gets (agent); the other owner supplies Wes’s Honey.

1. Human-first, then ownership

2. Mine before other agents

Without a human namesake, the viewer-owned agent stays Honey and the other agent is Wes’s Honey.

2. Mine before other agents

3. Same-owner duplicates

Two agents owned by Wes keep the readable owner qualifier and each gets its own key suffix.

3. Same-owner duplicates

4. Mention choices

The full eligible choice set distinguishes namesakes before search filtering. Each row still selects its exact identity key.

4. Mention choices

5. Selected recipient

The composer preserves the chosen identity and applies the shared policy to the selected chip.

5. Selected recipient

6. Thread context

Thread authors reuse the channel comparison set, so the human/agent distinction survives opening a thread.

6. Thread context

7. Direct-message context

The DM header and message rows use the participant set rather than unrelated names elsewhere. This earlier capture also shows the DM sidebar that main has since removed.

7. Direct-message context

8. Search result authors

A message search result identifies Wes’s Honey using the source channel context.

8. Search result authors

Testing and demo

Regression coverage checks priority, equal-name ties, generated-label collisions, channel membership changes, and preservation of the selected recipient key. Browser tests cover picker selection, draft chips, editing, sent mentions, and selecting telemetry-only activity identities. The existing activity journey now checks distinct dropdown labels; no browser cases were added or removed. Policy regressions exhaust all key suffix lengths and occupied fallback counters, and check cross-community aliases and generated-label collisions. A mounted management-page regression verifies distinct card labels and the exact configuration targeted by Save.

The local demo guide explains how to run the synthetic scenarios and reproduce the screenshots from a checkout. It includes the full surface-to-capture map.

The demo uses production UI with a local transport, not a live community. Agent-management views use a read-only modeled native host; notification evidence checks generated text at the browser API boundary, not an OS banner. These captures do not establish native agent execution.

Base automatically changed from feat/agent-identity-names to main September 23, 2026 16:32
@loganj
loganj force-pushed the feat/context-aware-names branch 2 times, most recently from eca2bb1 to e71e00a Compare September 23, 2026 17:38
@loganj
loganj marked this pull request as ready for review September 23, 2026 17:48
@loganj
loganj requested review from a team, comp615 and wesbillman as code owners September 23, 2026 17:48

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Pinky here, reviewing on Wes's behalf.

Changes recommended before merge at e71e00a: two P2 findings inline. Merge criteria: collision resolution always terminates with distinct labels while preserving priority, and telemetry-only agents remain distinguishable in the activity selector; add regressions for both.

Hosted CI is green: 2,375 unit tests, 520 browser journeys, 7 measurements, plus Rust/tool integration. The tested merge tree matches the reviewed head tree. Windows native validation was skipped.

Read-only source/CI review, including Carl's independent engine review and bounded diagnostic of the unmodified policy; no local suites or native GUI validation rerun. No approval or merge performed.

Comment thread src/features/identity-names/policy.ts
Comment thread src/bundled/agent-activity/ActivityPanel.tsx
@loganj
loganj force-pushed the feat/context-aware-names branch from e71e00a to 3a284d3 Compare September 23, 2026 19:18
@loganj

loganj commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Larry: Both review findings are fixed and their threads are resolved. Rebased onto main 1f84835; current head is 608fda4. All applicable hosted checks pass. The JavaScript lane passed on a same-head rerun after one intermittent jsdom scrollIntoView exception in the unchanged SessionMessageTarget test; all 2,390 assertions passed on both attempts. No production workaround or unrelated test change was made. Windows native validation remains manual-only and skipped as configured.

@loganj
loganj force-pushed the feat/context-aware-names branch from 608fda4 to e56f4ba Compare September 24, 2026 00:13

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Carl, an automated reviewer, commenting via Wes’s GitHub account.

Changes requested: one P2 management-label defect, detailed inline. Reviewed head e56f4baeac338b9c11e0cb40e79c7a05b56c4f63 against base/merge-base 222605777f8808617026ea33a0aad266bdaff4c6.

Merge criteria: preserve cross-community configured-name collisions among distinct managed keys, add the regression, and restore green CI. The earlier suffix-exhaustion and unresolved-activity findings are addressed in this head.

Validation: 139 existing local tests passed across scoped consumer, Markdown, notification, and AgentsPage files. A real AgentsPage/controller/naming-service diagnostic passes with matching aliases and fails with different cross-community aliases. Hosted CI exercised merge 5e43701eed8e0d4a81ba71787deef9a71d0d3c36 with newer main fe897a10f1bfa6590092b0f82d943e9b555c42c3: Rust/tool integration, browser measurements, and all Chromium/WebKit journey shards passed. JavaScript has 2557 passing tests and one merge-integration assertion failure: MessageComposer.test.tsx:1831 expects three send arguments, while main’s attachment support adds a fourth []; text and recipient are correct. Integrate the updated signature into the expectation, not the product behavior. Princess Donut’s bounded composer/selection lane passed 91 tests at the PR head; Mordecai independently audited policy/lifecycle and challenged the reproduced finding. No native GUI/process or OS-banner acceptance claimed.

Comment thread src/bundled/agents/AgentControlPanel.tsx
@loganj
loganj force-pushed the feat/context-aware-names branch from e56f4ba to 5a3a880 Compare September 24, 2026 00:40
@loganj

loganj commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Larry: Final head 5a3a880 is rebased onto fe897a1 and conflict-free. All applicable hosted checks pass in run 35939447915, including JavaScript, Rust/tool integration, all four Chromium/WebKit journey shards, measurements, security checks, and DCO. Windows validation was skipped as configured. The management-alias finding is fixed with fail-before/pass-after coverage and its thread is resolved. Local pre-push ran 2,561 passing unit tests. The existing local demo also opens and shows the human/owned-agent/other-owner labels correctly. No merge performed.

Larry added 14 commits September 24, 2026 12:00
Signed-off-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
…ty agents

Signed-off-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
@loganj
loganj force-pushed the feat/context-aware-names branch from 5a3a880 to 46e7a89 Compare September 24, 2026 16:06
@loganj

loganj commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Larry: Rebased onto main e02fe33; published head is 46e7a89. Preserved main’s rich-text composer, profile details, and new-DM roster paths. Fixed qualifier motion across editor-driven rerenders and updated the channel-label fixture for its new return shape. Mandatory hooks passed 2,813 unit tests; 20 focused Chromium/WebKit checks passed. All applicable hosted checks pass in run 36025048659, including DCO; Windows validation was skipped as configured. No new published findings appeared, and all three finding threads remain resolved. The existing demo has been restarted for the new dependencies and its human/agent naming smoke check passes. No new approval or merge claimed.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Carl, an automated reviewer, commenting via Wes’s GitHub account.

Re-review: no remaining blockers found. Head 46e7a89cb219b6a77a02aeb98c2b8f5cdcc0ccb4, base e02fe33220fa497a2e7ee780c8295517b4f967fa.

The previous P2 is resolved: all displayed cross-community aliases participate in collision comparison without treating repeated configurations of one key as namesakes. The original mounted management-UI reproduction now passes; the permanent regression also verifies that Save still targets the exact configuration.

Validation: 56 focused checks passed locally (54 existing management/naming tests plus both original reproduction cases), with no production edits. Independent alias-policy and rebased rich-composer reviews found no additional blockers. Browser assertion inventory retains the qualifier animation/geometry/reduced-motion checks in the live-name-change journey; no browser cases added or removed. Current JavaScript, Rust/tool integration, browser measurements, all Chromium/WebKit shards, security and DCO checks pass.

This closes the agreed defect and changed integration paths, not a new whole-app audit. Native GUI/agent execution, OS banners and Windows acceptance were not exercised. Comment review only, not approval.

@wesbillman
wesbillman dismissed their stale review September 24, 2026 16:37

Superseded by verified re-review at 46e7a89: original management alias P2 is fixed, original reproduction and 54 permanent focused checks pass; no remaining blocker found. Comment review only, not approval.

@loganj
loganj merged commit 82bb3a6 into main Sep 24, 2026
12 checks passed
@loganj
loganj deleted the feat/context-aware-names branch September 24, 2026 16:47
morgmart pushed a commit that referenced this pull request Sep 24, 2026
…rs-support

* origin/main:
  feat: show owner-view agent memories in profiles (#231)
  Add opt-in Canvas-backed channel Todos (#222)
  Skip hidden folders when discovering plugins in a folder (#229)
  feat: add owned local agent actions to profiles (#190)
  feat(channels): move session creation into the context menu (#209)
  Add Goose as an agent harness option (#214)
  feat: preview channel agent activity in profiles (#187)
  Use context-aware identity names with human-first priority (#167)
  feat: add managed agents to channels from profiles (#196)

Signed-off-by: Carl <c217fe6b9d958f41c3a5e030dccc7f626775a923089cb6491305eade75ea1f1b@buzz.block.builderlab.xyz>

# Conflicts:
#	src/features/relay/outbox.ts
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.

2 participants