block / block/buzz

feat(search): query operators `from:` / `in:` / `before:` / `after:` (backend already supports them, client never sends them)

Open
#2,853 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

## Problem

Search accepts free text only. There is no way to narrow a query to a person,
a channel, or a date range. The `from:` / `in:` / `before:` / `after:`
operators are muscle memory for anyone coming from Slack, and a Slack-parity
gap in the sense of #2728. Today the only narrowing that exists is
programmatic: the in-channel find bar scopes by the current channel.

## What already exists (the surprising part)

The entire backend path is already built. `SearchQuery` in
`crates/buzz-search/src/query.rs` carries `authors`, `since`, `until`, `kinds`
and a channel scope, and **both** relay search paths already map those fields
from the incoming NIP-01 filter:

- WS NIP-50 path: `crates/buzz-relay/src/handlers/req.rs` (~L599)
- bridge path: `crates/buzz-relay/src/api/bridge.rs` (~L1698)

So a filter like `{"search": "deploy", "authors": [], "since": …,
"until": …, "#h": []}` filters correctly on the relay **today**. The
existing per-hit re-authorization is untouched: the relay refetches and
re-authorizes every hit, so operators cannot widen visibility ("search is
never the access boundary").

What's missing is entirely client-side: the desktop sends only
`{search, search_mode, limit, "#h"}` (`build_search_messages_filter` in
`desktop/src-tauri/src/commands/messages.rs`), and nothing anywhere parses
operator syntax.

## Proposed v1 scope

Client-only. No new event kinds, no relay changes, no schema changes.

**Syntax** (parsed out of the search input; remaining text is the FTS query):

| Operator | Maps to | Notes |
|---|---|---|
| `from:@name` | `authors` | resolved via the existing user-search / mention-candidate infra; autocomplete required, so ambiguous names are resolved at compose time |
| `in:#channel` | `"#h"` tag | resolved against the local channel list (same source `useSearchResults.ts` already filters) |
| `after:YYYY-MM-DD` | `since` | start of day, local time |
| `before:YYYY-MM-DD` | `until` | start of day, local time |

**Implementation sketch:**

1. Pure-TS operator parser in `desktop/src/features/search/lib/` (unit-tested;
invalid operator text simply stays in the FTS query).
2. Autocomplete for `from:` / `in:` in the topbar search, reusing the existing
user/channel pickers; active operators render as removable filter chips.
3. Extend the `search_messages` Tauri command with optional
`authors` / `since` / `until` params and emit them in the filter, adding a
few lines next to the existing `build_search_messages_filter` unit tests
that pin the client/relay filter contract.
4. Typeahead: operators are stripped before the prefix-mode tsquery is built,
so `search_mode: "prefix"` behavior is unchanged.

**Explicitly out of scope for v1** (each needs backend work or product
decisions, happy to file follow-ups):

- `has:link` / `has:image` / file-type filters (needs an indexed signal for
attachment presence)
- a dedicated file/attachment search surface
- natural-language dates (`before:yesterday`)
- group/thread scoping operators

## Open questions for maintainers

1. Should operators live in the ⌘K topbar search (current mixed
channel/user/message results), or is a dedicated search view planned that
this should target instead?
2. Any preference on syntax? (`from:` vs `author:`; whether `in:` should also
accept DMs.)
3. `buzz-cli` / agents already speak raw NIP-01 filters, so they get nothing
new from this. If you'd like the same operator string parsed by
`buzz-cli search` for symmetry, that could be a follow-up.

If the approach sounds right I'm happy to implement it, splitting it as
(1) parser + command plumbing and (2) autocomplete + chips UI if you prefer
two smaller PRs.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.