Skip to content

karansinghgit/robin

Repository files navigation

Robin

Robin is a mac-first menu bar sidekick built with Electron. V1 focuses on two workflows:

  • Search: BYOK Perplexity-powered web-grounded answers
  • Local: Ollama-backed local chat

Stack

  • Electron 41.0.2
  • Electron Forge 7.10.2
  • React + TypeScript
  • Tailwind CSS

Setup

  1. Install Node.js 22+. If you do not use Homebrew or nvm, you can bootstrap a local copy:
bash ./scripts/bootstrap-node.sh
  1. Install dependencies:
npm install
  1. Start the app:
npm start
  1. Typecheck before packaging:
npm run typecheck

Common Commands

make help
make setup
make dev
make test
make package
make install
make clean-dev
make create-release VERSION=0.1.0

If you prefer npm directly:

npm run setup
npm run dev
npm run test
npm run package:mac
npm run make:mac
npm run install:mac

make dev now auto-stops stale Robin dev processes and picks free Forge ports, so reruns are safe even after interrupted sessions. In dev mode, Robin runs as a menu bar app by default: dock icon hidden, tray title fallback enabled, and panel hide-on-blur on. If the panel disappears after clicking away, open it again from the Robin menu bar item or use CommandOrControl+Shift+Space.

Live updates in dev

  • Keep make dev running while editing.
  • Renderer changes (React/CSS/assets) update live.
  • If you change main/preload code, type rs in the dev terminal to restart the Electron main process.

Icon assets

Replace brand files in assets:

UI action icons now come from Hugeicons (@hugeicons/react + @hugeicons/core-free-icons).

Node is pinned in .nvmrc and .node-version. After bootstrap, the repo-level wrappers scripts/nodew and scripts/npmw will use the local runtime automatically.

Testing

Robin currently has a strong smoke-test workflow rather than a full automated test suite.

  1. Run npm install
  2. Run npm run test
  3. Run npm run dev
  4. Verify manually:
    • Tray icon appears
    • CommandOrControl+Shift+Space toggles the panel
    • Esc hides the panel
    • Onboarding allows Perplexity key entry
    • Ollama detection reports the correct state
    • Search mode streams a response after you configure a valid Perplexity key
    • Local mode streams a response when Ollama is running with a pulled model
    • Quit and relaunch the app; conversations should still be there

For a true clean-room retest on macOS:

make clean-dev
make dev

Product Notes

  • macOS is the primary UX target in v1.
  • No hosted inference subsidy is included.
  • The app stores conversations in local JSON files under Electron's user data directory.
  • API keys are encrypted with Electron safeStorage.

Packaging

make make

This creates distributable artifacts in out/.

Releasing

Robin now has a SpeakType-style release flow:

  1. Export Apple signing env vars:
export APPLE_SIGN_IDENTITY="Developer ID Application: Your Name (TEAMID)"
export APPLE_ID="you@example.com"
export APPLE_APP_SPECIFIC_PASSWORD="xxxx-xxxx-xxxx-xxxx"
export APPLE_TEAM_ID="TEAMID"

You can also copy values from .env.release.example.

  1. Prepare the release locally:
make create-release VERSION=0.1.0
  1. Publish it to GitHub Releases:
make deploy-release VERSION=0.1.0
  1. Or do both:
make release VERSION=0.1.0

For the full checklist, see RELEASING.md.

Technical Architecture

Electron main/renderer split

Robin uses the standard Electron architecture with a main process (Node.js) handling system integration (tray, global shortcuts, IPC) and a renderer process (React) for the UI. Communication is via a typed RobinBridge exposed through contextBridge in the preload script — the renderer never accesses Node APIs directly.

Local-first persistence

All data is stored as JSON files in Electron's userData directory:

  • settings.json — app config, provider preferences, model selections
  • threads.json — full conversation history with messages and attachments
  • todos.json — todo items with ordering

API keys are encrypted at rest using Electron's safeStorage API (macOS Keychain / Windows DPAPI).

Multi-provider abstraction

Robin supports multiple AI providers through a uniform streaming interface:

  • OpenAI — GPT models with mode support (chat/responses)
  • Anthropic — Claude models
  • Google — Gemini models with native image support
  • Perplexity — Search-grounded answers with citations
  • OpenRouter — Proxy to any model via user-provided model IDs
  • Ollama — Local models with automatic detection and management

Each provider implements streamReply() with delta callbacks. The ProviderService orchestrates thread management, model resolution, and provider dispatch.

Context management

Before sending messages to any provider, Robin optimises the payload:

  1. Image stripping — only the most recent user message retains image attachments. Older images remain in the thread for display but are excluded from API calls to avoid payload bloat.
  2. Context truncation — if total message content exceeds ~100K characters (~25K tokens), the oldest messages are dropped while preserving at least the last 4 messages (2 turns).
  3. Model-agnostic threads — threads store raw messages without model metadata. The model selection is applied at call time, so you can switch providers mid-conversation.

Assistant hub design

The sidebar uses a 2x2 navigation grid (Chats, Todos, Notes, Calendar) that switches the sidebar content panel. This pattern supports adding new assistant features without changing the core chat architecture. Todos are fully functional with drag-and-drop reordering; Notes and Calendar are placeholder tiles for future development.

Next Steps

  • Add real renderer/main-process automated tests
  • Add a richer settings surface for provider management
  • Add update distribution after the first beta

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors