Let a coworker be pinned to the top of the Agents screen - #650
Open
asasemahmed wants to merge 1 commit into
Open
asasemahmed wants to merge 1 commit into
asasemahmed wants to merge 1 commit into
Conversation
A coworker's Manage tab has a Pin button beside Hide, and pinned coworkers move into a Pinned section at the top of /agents. Pinning is personal, like hiding: it is a pinned_at column next to hidden_at in agent_preferences, and each write sets only its own column, so pinning a hidden coworker keeps it hidden and it comes back pinned when it is unhidden. POST /api/agents/:id/pin and /unpin record bot.pinned and bot.unpinned on the trail, as hiding does. Refs CopilotKit#323
asasemahmed
requested review from
MikeRyanDev,
davidmckayv,
guidovizoso,
mxmzb and
tylerslaton
as code owners
September 28, 2026 06:11
This branch has not been deployed
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 this changes
The other half of #323, after #647. A coworker's Manage tab has a Pin button beside Hide, and
pinned coworkers move into a Pinned section at the top of
/agents. With this, the three things#323 asks for (pin, hide, duplicate) all exist.
It mirrors hiding exactly:
pinned_atcolumn besidehidden_atinagent_preferences(migration0047_agent_pinning, oneADD COLUMN). The row is per person and per coworker, so pinningchanges nothing for anyone else.
setPinnedhas the same shape assetHidden: the same accessibility check, then an upsert thatsets only its own column. Pinning a hidden coworker keeps it hidden, and it comes back pinned
when it is unhidden.
POST /api/agents/:id/pinand/unpinrecordbot.pinned/bot.unpinned, besidebot.hidden/bot.unhidden.pinned: booleannext tohidden.On the screen, a pinned coworker appears once, in Pinned, rather than also in its roster. When
pinning empties a roster, that roster says "Your agents are all pinned above." instead of "You
don't have any agents created.", which would be false. The Pinned section renders nothing while
loading, on failure, or when nothing is pinned, so the existing loading and error states are
unchanged.
Not included: the limit on pinned coworkers the issue suggests. Nothing here needs one, and it is
easy to add if you want it.
Where it runs
agent_preferences.pinned_at, in Postgres.replica answers; nothing is held in process.
the
(user_id, agent_id)primary key: the upsert makes the second an update of the firstrather than a conflict. Each statement sets only its own column, so a pin and a hide racing
each other both survive.
agentKeys.all, as Hidedoes.
Boundary and audit
same kind of personal list preference as hiding.
bot.pinned/bot.unpinnedon success. A refused pin (a coworker the caller cannot see) writes nothing,as a refused hide does, and answers 404.
see before anything is written.
Changelog
CHANGELOG.mdunderUnreleased, andpinadded to the/agentsrow in theREADME.
Proof
agent-profile-store.integration.test.tsgains "stores pinning per user, independentlyof hiding" (pin, hide while pinned, re-pin while hidden, unhide, unpin; both columns end null)
and "refuses to pin a coworker the caller cannot see". The file passes against Postgres: 25 pass.
agent-routes.test.ts(the lifecycle and DTO tests now include pin andunpin) and
bot-lifecycle-audit.test.ts(bot.pinned,bot.unpinned).agent-api-path.test.tsdrives the new mutation through the real routes for every awkwardid, and
agent-roster-error.test.tsxgains three tests for the Pinned section, including the"all pinned" sentence. The other agent-list fixtures gain
pinned: false.bunx drizzle-kit checkpasses, and the drift probe (drizzle-kit generate) writes nothing.bun run typecheck,biome lint,biome format: clean. 119 tests pass across the five filesabove.
button turned to Unpin,
/agentsread Pinned, Your agents, Explore agents with Knowledge onlyunder Pinned, and the trail held
bot.pinnedforknowledge. Unpinning it removed the sectionand put it back under Explore agents.