Open-source AI coworker, with memory https://www.rowboatlabs.com
Find a file
PRAKHAR PANDEY 2274369383
Feat/model selector (#770)
* feat(x): add useModels hook — shared model-catalog store

One module-level store behind useSyncExternalStore: N mounted consumers
share one snapshot and one in-flight fetch (models:list + models.json +
oauth state + llm:getDefaultModel). Re-fetches on models-config-changed,
oauth:didConnect and chatgpt:statusChanged; newest-wins seq guard ports
the composer's epoch race protection. Extracted verbatim from the chat
composer's loadModelConfig for the ModelSelector consolidation (Phase 1).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(x): add ModelSelector extracted from the chat composer

Controlled picker ({provider, model} value + onChange, persistence stays
with the caller) rendering the composer's exact UI: provider-grouped
catalog + live groups via useProviderModels, search filter, standalone
default row, locked-model display, and the reasoning-effort control
(shown only for catalog-flagged reasoning models, '' reported up when
the model loses reasoning support). Catalog comes from useModels().

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(x): migrate chat composer to useModels + ModelSelector

Deletes the composer's inline copies of the catalog loader (oauth state,
llm:getDefaultModel, models:list, models.json parsing, event listeners)
and the picker/effort dropdown JSX in favor of the shared hook and
component. Behavior preserved: picks persist globally via
models:updateConfig({defaultSelection}) + models-config-changed dispatch,
locked-model display, per-turn unpersisted reasoning effort, and the
tab-activation re-fetch. SelectedModel/ReasoningEffortLevel exports stay
for existing consumers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(x): ModelSelector settings modes — sentinel, field trigger, provider scoping, custom ids

defaultOption pins a top entry that selects null ('Rowboat default' /
'Same as assistant'); variant='field' renders a SelectTrigger-style
full-width box; providerFilter scopes to one provider's group, falling
back to the raw models:list catalog (newly exposed on the useModels
snapshot as catalogByProvider) for providers mid-setup; allowCustom
offers a Use-"<text>" row when the search matches nothing. onChange
widens to ModelRef | null — the composer guards the (unreachable
without defaultOption) null and is otherwise untouched. Still zero
persistence inside the component.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(x): signed-in Settings Models section on ModelSelector

The four hybrid dropdowns (Assistant / Knowledge graph / Background
agents / Permission checks) become field-variant ModelSelectors with a
'Rowboat default' sentinel, sourcing the shared store's groups — BYOK
providers without a static catalog (e.g. OpenRouter) now live-fetch
their full list inside the open dropdown instead of showing only the
saved model (user-reported bug). State is ModelRef | null; the
provider::model hybridKey round-trip, options collector, and local
providerDisplayNames map are gone. Persistence unchanged: nothing
writes until Save's single models:updateConfig + models-config-changed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(x): BYOK per-provider category fields on ModelSelector

Knowledge graph / Meeting notes / Track block / Auto-permission become
provider-scoped field-variant ModelSelectors (providerFilter=active
card, allowCustom, 'Same as assistant' sentinel), replacing the static
catalog Select + free-text Input pair. Values still persist as bare
model-id strings inside providers[flavor] through the existing save
path — the ModelRef ↔ string adapter lives at the call site. Deletes
the section's own models:list loader (modelsCatalog/modelsLoading/
showModelInput/LlmModelOption); scoped pickers fall back to the store's
catalogByProvider for providers mid-setup, and configured providers now
live-fetch full lists (OpenRouter bug fix on the BYOK side too).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(x): assert defaultModel refreshes on models-config-changed

Covers the settings-Save → event → store refetch leg that updates a
fresh composer tab's trigger label.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(x): ModelSelector inheritance mode + un-scoped custom ids

inheritDefault?: {label} is defaultOption with placeholder styling —
one sentinel code path, the trigger renders the label muted when
nothing overrides. allowCustom no longer requires providerFilter: an
un-scoped custom entry splits 'provider/model' on the first slash
(OpenRouter-style ids must be typed provider-qualified) and pairs
slash-less text with the global default's provider, matching how the
runtime resolves a provider-less override. Adds modelOverrideToRef /
refToModelOverride adapters for the two-optional-strings persistence
shape shared by BackgroundTask and LiveNote.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(x): bg-task model/provider override on ModelSelector

The Advanced section's two free-text Inputs become one inheritance-mode
picker ('(global default)' sentinel, allowCustom for arbitrary ids).
Same draft state and bg-task:patch save path; a task with model set but
no provider round-trips untouched via the shared override adapters.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(x): live-note model/provider override on ModelSelector

Same inheritance-mode picker as bg-tasks (the section was a copy-paste
of it), same shared adapters, unchanged live-note:set save path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(x): EnableAgentsDialog model picker on ModelSelector

Replaces the flat models:list-flattening <select> with an
inheritance-mode picker pre-seeded from the pinned agent's bg-task
model/provider. '(default)' (null) still enables with an active-only
patch so agents keep their pinned model; a picked model still patches
each bundled agent once. Drops the dialog's private catalog fetch —
the shared store already has the data.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(x): ModelSelector staticOptions mode for caller-supplied lists

When staticOptions is set the picker renders ONLY those rows (+ the
defaultOption sentinel) — no catalog groups, no live fetches. Entries
are opaque engine ids carried in ref.model with provider '', so
call-site adapters stay one-liners ('default' ↔ null, id ↔ string).
Rows whose label differs from their id show the id as secondary text,
disambiguating Claude's colliding 'Opus' labels (alias + concrete id).
Adds toSelectorOptions() in code-agent-options to split an engine list
into sentinel label + rows, and a triggerTitle prop for header tooltips.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(x): new-session dialog on ModelSelector

Deletes loadModelOptions() — the admitted composer-mirror duplicate —
in favor of the shared store: the Rowboat-mode picker (still rendered
only for rowboat mode, gated on configured providers) is a field
ModelSelector whose null sentinel keeps 'default → omit model/provider'
create-payload semantics. The agent-model select becomes a
staticOptions picker fed by toSelectorOptions(fetchCodeAgentOptions),
preserving per-agent reload/reset and the 'default → omit agentModel'
payload rule. The effort select stays a plain Select on purpose — a
caller-supplied axis, not model selection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(x): code session header agent-model picker on ModelSelector

The header's model DropdownMenu becomes a pill ModelSelector with
staticOptions (search + Opus id disambiguation for free); the effort
dropdown stays untouched. codeSession:update payload semantics
unchanged — the sentinel still sends the literal 'default'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore(x): delete dead onboarding-modal.tsx

Nothing imports it — App.tsx renders OnboardingModal from
components/onboarding/index.tsx (the steps-based flow). Its rich
four-category model picker was superseded by the silent auto-resolve
in use-onboarding-state; the only other mention was a stale comment in
useConnectors, updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 10:59:35 +05:30
.github/workflows ci(x): typecheck test files — the gap vitest and the build tsconfigs both miss 2026-07-10 16:30:26 +05:30
apps Feat/model selector (#770) 2026-07-22 10:59:35 +05:30
assets fix brain image 2026-07-10 10:16:50 +05:30
.env.example Run mongodb in docker 2025-04-07 13:30:27 +05:30
.gitattributes Mega UI revamp 2025-04-03 17:56:31 +05:30
.gitignore chore: remove meeting-prep PLAN.md from repo (keep local-only) (#652) 2026-07-02 00:44:28 +05:30
build-electron.sh wip-electron 2026-01-16 12:05:33 +05:30
CLAUDE.md ci(x): typecheck test files — the gap vitest and the build tsconfigs both miss 2026-07-10 16:30:26 +05:30
docker-compose.yml merge job workers 2025-08-17 11:06:53 +05:30
Dockerfile.qdrant improve embedding index docs and setup 2025-05-09 09:38:09 +05:30
google-setup.md Small cleanup in rowboat 2026-07-12 21:14:14 +03:00
LICENSE Fill license placeholder 2025-01-31 16:29:39 +05:30
README.md Fix typos in README.md (#766) 2026-07-20 17:20:58 +05:30
start.sh Revert auth related changes to start.sh 2025-09-16 16:55:29 +04:00

rowboat-github-2

Rowboat

A desktop AI coworker with a memory of your work and built-in surfaces to act on it.

rowboatlabs/rowboat | Trendshift

Website Discord Twitter Y Combinator

Rowboat indexes your work into a living knowledge graph and uses that to get work done on your machine. It includes work surfaces for collaborating with AI: email client, notes, browser, code mode, meeting note taker, and workspaces for different projects.

Download latest for Mac/Windows/Linux: Download

Rowboat Apps to Code demo

Demo - apps to code · Demo - knowledge graph

If you find Rowboat useful, please star the repo. It helps more people find it.


Overview

Brain

Rowboat indexes email, meetings, slack and assistant conversations into a living Obsidian-style backlinked knowledge graph.
Brain graph screenshot

Email

The built-in email client sorts emails into important and everything else. Rowboat automatically drafts responses for important email using all the work context.
Email screenshot

Background agents

You can set up background agents that run on events like new email or on schedule like every day at 8am. They can connect to tools, search the web, use the browser and write code using Claude Code or Codex.
Background agents screenshot

Built-in Browser

Rowboat includes a browser that lets you and assistant collaborate on web tasks. Because it's isolated from your main browser, you can log in only to the accounts that want the assistant to access.
Browser screenshot

Meeting Notes

A local meeting note-taker that taps into mic & speaker, produces live transcript and summarizes the meeting in a markdown file and updates the knowledge graph.
Meeting notes screenshot

Code Mode

Code mode lets you spin up parallel coding agents with Claude Code or Codex, and have Rowboat drive them with all the work context where needed.
Code mode screenshot

Apps

You can build your own work surfaces inside Rowboat — they get access to all the tools and integrations, and you can share them with other people.
Apps screenshot

Integrations

Includes one-click integrations to most popular products.
Integrations screenshot

Installation

Download latest for Mac/Windows/Linux: Download

All release files: https://github.com/rowboatlabs/rowboat/releases/latest

Google setup

To connect Google services (Gmail, Calendar, and Drive), follow Google setup.

Voice input

To enable voice input and voice notes (optional), add a Deepgram API key in ~/.rowboat/config/deepgram.json

Voice output

To enable voice output (optional), add an ElevenLabs API key in ~/.rowboat/config/elevenlabs.json

To use Exa research search (optional), add the Exa API key in ~/.rowboat/config/exa-search.json

External tools

To enable external tools (optional), you can add any MCP server or use Composio tools by adding an API key in ~/.rowboat/config/composio.json

All API key files use the same format:

{
  "apiKey": "<key>"
}

How its different

Most AI tools reconstruct context on demand by searching transcripts or documents.

Rowboat maintains long-lived knowledge instead:

  • context accumulates over time
  • relationships are explicit and inspectable
  • notes are editable by you, not hidden inside a model
  • everything lives on your machine as plain Markdown

The result is memory that compounds, rather than retrieval that starts cold every time.

Bring your own model

Rowboat works with the model setup you prefer:

  • Local models via Ollama or LM Studio
  • Hosted models (bring your own API key/provider)
  • Swap models anytime — your data stays in your local Markdown vault

Extend Rowboat with tools (MCP)

Rowboat can connect to external tools and services via Model Context Protocol (MCP). That means you can plug in (for example) search, databases, CRMs, support tools, and automations - or your own internal tools.

Examples: Exa (web search), Twitter/X, ElevenLabs (voice), Slack, Linear/Jira, GitHub, and more.

Local-first by design

  • All data is stored locally as plain Markdown
  • No proprietary formats or hosted lock-in
  • You can inspect, edit, back up, or delete everything at any time