Search
⌘K, or Ctrl-K, from anywhere in the application.
It was the application's first keyboard shortcut, back when there were none at all — which for a tool people live in all day is less a missing feature than a missing posture. There are now a handful more: press ? for the list, or see Keyboard.
What it searches
| Issues | Identifier, title, description — not comments, see below |
| Projects | Name, description |
| Agents | Name |
| Skills | Name, description |
| Knowledge | Article title, and the words inside the document |
| Pages | Dashboard, Issues, Projects, Inbox, Gantt, Cycles, Timesheets, Knowledge, Whiteboard, Reports, Agents, Settings |
Five of each kind at most — enough to recognise, few enough to scan.
An article's body is matched through search_text, a plain-text copy of the
document kept beside the row. The prose itself is a file, and SQL cannot grep a
filesystem.
Somebody else's draft never appears. Finding half a page through search is worse than not finding it, because whoever found it will act on it.
Typing an issue key goes straight there
ACM-231, acm 231, acm231, or just 231. Somebody who types an identifier
has already decided where they are going, and making them read a list of
near-matches first is a worse outcome than any ranking, so an exact match is
always first and labelled Jump to.
A prefix that is not this workspace's is ignored. ACM-1 and DAC-1 are both
"issue 1", and guessing which one was meant is worse than not guessing.
It also goes places
Most of what somebody wants from a palette is to be somewhere else, so the pages are in it and are offered before anything is typed. A palette that does nothing until you type is a search field with extra steps.
Keys
⌘K / Ctrl-K |
Open, or close if it is open |
↑ ↓ |
Move — it wraps, because stopping at the end is a dead end nobody expects |
↵ |
Open the highlighted result |
esc |
Close |
The shortcut is registered on the window rather than on an input, because the whole point of it is to work when nothing is focused.
What it will not find
Anything in another workspace. Every query is scoped before it runs.
Somebody else's private agent. Through the same visibility rule as the assignee picker — a search that ignored it would be a way to enumerate what you cannot see.
Comment bodies. Deliberately, here. A palette that searches every comment finds the same issue eleven times and stops being a way to get anywhere.
The Search issues box on the board does search them, and the difference is what each one is for: the palette is a way to get somewhere, and a board search is a way to narrow a list you are already looking at. See the board's search.
Whiteboards
The words on a sticky note, and board names. A board is where a decision was argued before anybody wrote it down, so it is often the only place a rejected option is recorded at all.
A result opens the board with the viewport centred on the note. This is the part that makes it work rather than appear to: a board has no edges, so landing on one without moving the viewport leaves somebody looking at an empty grid four thousand pixels from the thing they searched for.
The zoom is left alone. Somebody who searched wants the note in the context it was drawn in, and a jump to 100% throws away the scale the board was built at.
The note is ringed and pulses for a couple of seconds, because centring is not finding: on a board with forty yellow notes, the one in the middle looks like the six around it.
Board names are listed separately from note text. Somebody looking for "Retro" wants the board, not whichever note happens to mention the word.
A private board is not searched, by anybody but its author. Hearing about a surface is reading it, and a search result is hearing about it.
What matched, not just what
Every article result carries the passage that matched, with the term marked.
It used to show the opening of the document, which is a preview rather than a reason — and a preview of an article that matched on page four says nothing about why it is in the list. Five plausible titles meant five documents somebody opened.
The window is cut around the match and marked with ellipses where it cut, and it keeps the document's own casing: echoing the search term back makes the snippet look like something the search wrote rather than something the document says.
When the search was typed wrong
A second pass, and only when the exact search found nothing.
That restriction is what makes it safe. Mixed into every query, fuzzy matching makes precise searches worse: "deploy" starts returning "display", and somebody who typed the right word is reading results they did not ask for. As a fallback on zero results it cannot degrade a search that already worked.
Results appear under Did you mean, labelled. A result that arrived because the search was wrong has to say so, or the next thing somebody does is assume it was an exact match and act on it.
What counts as a typo:
| Up to two edits | A transposition plus a missing letter. Three starts matching different words — "deploy" and "display" are three apart, and offering one for the other is worse than nothing because somebody will believe it |
| Four characters minimum | Below that a typo and a different word are the same thing. "cat" and "cut" |
| Word by word | "rate limting" against "Operations and rate limiting" is twenty edits as strings and one on the word that matters |
| Every word must land | Otherwise "login zzzzz" matches anything containing "login", and the second word was the one narrowing it |
| Prefixes are free | Somebody stopped typing. It ranks above a genuine misspelling |
| Accents folded | levenshtein counts bytes, so an accented character costs two. Folding also means "mote" finds "møte", which is what somebody without a Norwegian keyboard has typed |
Pages are matched too, and first: a misspelled destination is the most common typo there is — somebody typing fast on the way somewhere rather than searching for a record.
No index and no dependency. levenshtein is in PHP's core and the candidate set is
capped, which is affordable precisely because this only runs on a query that found
nothing.
Not there yet
LIKE '%term%', which cannot use an index. Fine at the sizes this is built for, and honest about being the first thing to change when it is not — a full-text index would be MySQL-only and would make the test suite and production disagree, which this project has been bitten by before.- Fuzzy matching is titles and names only. Bodies are where the volume is, and walking four hundred documents in PHP to rescue a misspelling is a worse trade than saying nothing.
- No recent or frequent items. The list does not learn.
- No search inside a meeting's notes or minutes. Meetings are reachable from their own list.
- No search on the API.
GET /issues?q=filters titles and descriptions, which is the same query, but the palette's ranking is not exposed.