Skip to content

gorajing/roro

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

309 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Roro

Animated Roro pixel cat preview: local-first coding companion

A local-first desktop coding companion that works in your repo and remembers how you work.

Roro turns a typed task into a real coding-agent run against the project you choose: it recalls your local preferences, asks a local Ollama brain to plan the turn, streams Codex or Claude through one action timeline, and keeps useful lessons for next time. The pixel cat makes the loop visible, but the job is coding help with continuity.

The v0 promise is intentionally narrow: local-first coding help that gets better because it remembers how you work.

ask -> recall memory (local) -> think on local Ollama -> run Codex or Claude -> remember the result (local)

Privacy promise: Roro's default brain, recall, embeddings, and memory run on your machine with local Ollama and local storage. Memory contents are encrypted at rest by default with the OS keychain, and Roro fails loud instead of silently saving plaintext if that keychain is unavailable. Roro itself does not require accounts, app-owned telemetry, or a cloud-model key. Coding turns still run through your own local executor CLI: install and sign in to Codex or Claude outside Roro first, or point Roro at the binary with RORO_CODEX_BIN / RORO_CLAUDE_BIN.

See FOUNDING.md for the identity, locked invariants, and strategy of record (read it first), PUBLIC.md for the path to public readiness, and HANDOFF.md for current engineering truth.

Why This Exists

Most coding agents still feel like command-line tools with better autocomplete. Roro makes the agent loop visible and social:

  • the cat changes posture when the system is listening, thinking, working, done, or stuck
  • the brain's decide phase appears as the "thinking" layer
  • executor output becomes a normalized action timeline
  • local memory recall is surfaced as a visible memory beat
  • optional screen reads show a visible "Taking one screen snapshot." beat before capture
  • the same character layer can run inside the full app or as a transparent floating desktop agent

The intended demo is simple: ask the character to fix a bug, watch it plan, watch it run the coding agent, then ask what it remembers from the earlier turn.

The Cat

The default character is a procedural 16-bit tuxedo cat drawn with PixiJS in src/renderer/character/avatar.ts. It does not need image assets or model files.

The base cat uses a tight four-color palette: black body, white tuxedo and paws, yellow eyes, and gray inner ears. State effects deliberately expand that palette: cyan for listening and talking, gold for thinking, blue for work motion, green and gold for success, and red/orange for errors.

State Behavior
idle breathes, blinks, twitches ears; floating mode slowly cycles stand/sit/walk
listening perks up and shows signal pixels
thinking sits, looks upward, shows thought pixels
working walks with a leg cycle and turns before reversing direction
done shows success sparkles
error flattens ears and shows alert pixels
talking layer opens the mouth and adds signal pixels while speech is active

The renderer talks to a character-agnostic CharacterDriver (setState, setMouthOpen, setTalking, speak), so a different character implementation can be mounted later behind the same interface.

How It Works

flowchart LR
  user["User task<br/>text by default"] --> renderer["Renderer<br/>cat, captions, controls"]
  renderer --> main["Electron main<br/>typed IPC"]
  main --> memoryRecall["memory2 recall<br/>local index over encrypted files"]
  memoryRecall --> brain["Local Ollama brain<br/>qwen2.5 decision"]
  brain --> executor["Executor adapter<br/>Codex or Claude"]
  executor --> events["Canonical action events"]
  events --> renderer
  events --> memoryWrite["memory2 remember (local)"]
  brain --> vision["Local vision<br/>optional screen read"]
Loading
Subsystem Role Source
Electron shell windowing, IPC, macOS permission checks, floating mode src/main/
Character pixel cat, state machine, lip sync facade src/renderer/character/
Brain local Ollama reasoning/vision/embeddings src/core/brain/
Memory encrypted files-as-truth + in-memory vector index (local, owner-scoped) src/core/memory2/
Executor Codex and Claude stream adapters src/core/executor/
Voice internal on-device VAD + STT + TTS seam (Silero / whisper / Kokoro), hidden behind dev flags and cut from v0 src/renderer/voice/
Shared contracts typed IPC, action events, avatar states src/shared/

The important boundary is the canonical action-event vocabulary in src/shared/events.ts. The renderer does not parse raw Codex or Claude output; it only reacts to normalized events like command, file_change, message, run.completed, and run.failed.

Quick Start

# 1. Start the local brain (Ollama) and pull the core models:
ollama serve
ollama pull qwen2.5:3b        # reasoning
ollama pull nomic-embed-text  # embeddings (768-dim)
# Optional later, for screen understanding:
ollama pull qwen2.5vl:7b      # vision

# 2. Run the app:
npm install
npm start

In a packaged build, Roro asks you to choose the project folder it should work on, stores that choice in userData/config.json, and reuses it after relaunch. The working repo resolves from the persisted in-app choice first, then the RORO_WORKDIR env var, then the explicit RORO_ALLOW_CWD=1 cwd fallback (dev). If Roro says no working repo is set, choose a project in Settings or relaunch with RORO_WORKDIR=/absolute/path/to/repo npm start; blank or stale paths are treated as unset so the executor never runs against a guessed directory.

On boot Roro runs a non-blocking brain preflight; if Ollama is down or a model is missing, the window still opens and a clear diagnostic appears (it never silently falls back to the cloud). See docs/WS1-OLLAMA-INTEGRATION-TEST.md.

Roro launches as the floating desktop agent by default:

npm start

The floating mode opens a transparent, frameless 360x420 click-through window with the cat resting bottom-left — the empty area passes clicks straight through to whatever is underneath. At rest it is just the cat: the input, the working chip, and error cards are transient reactions tethered beside the cat, summoned by ⌘⇧Space or a hover-revealed handle. Setup banners appear only when action is needed. Tap or hold the cat to pet it; drag to move it. (The on-device voice stack — including the mute/M/right-click path — now lives in packages/voice; there is no mute control in the current app, and a future voice reintegration restores it.) The cat's body carries only affection + move — talk and tasking live off the body (see the current interaction contract at docs/INTERACTION.md). The floating window stays above normal windows and across macOS Spaces, including full-screen apps. The summoned input bubble is the compact task surface; set RORO_FLOATING_WINDOW=0 npm start for the legacy full dev window with the full prompt, controls, captions, memory panel, and action timeline visible.

Configuration

Roro's default brain and memory paths need no app-owned cloud/model keys: Ollama runs locally, memory is a local encrypted files-as-truth store, and packaged builds store the chosen working repo in userData/config.json. A local .env (see .env.example) is for development overrides, model tuning, and optional cloud/executor paths:

# Brain provider: 'ollama' is the only supported value (local-first; anything else fails loud).
BRAIN_PROVIDER=ollama
OLLAMA_HOST=http://127.0.0.1:11434
OLLAMA_MODEL=qwen2.5:3b
OLLAMA_VISION_MODEL=qwen2.5vl:7b
OLLAMA_EMBED_MODEL=nomic-embed-text
OLLAMA_EMBED_DIM=768            # set this if OLLAMA_EMBED_MODEL is not 768-dim

# Optional dev fallback (a project saved in-app wins over this). Packaged
# first-run uses the native Choose Project flow.
RORO_WORKDIR=/absolute/path/to/scratch-git-repo
ANTHROPIC_API_KEY=...           # optional, only for the Claude executor

Memory is a local encrypted files-as-truth store under the app's userData dir (RORO_DB_DIR to override) — no external database. See RUN.md for the on-device voice dev flags, macOS permissions, and the full live-run checklist.

Migrating from an older checkout: the internal env prefix was renamed COMPANION_*RORO_* (and VITE_COMPANION_FLOATING_WINDOWVITE_RORO_FLOATING_WINDOW). The old names still work for now (a deprecation warning is logged); update your .env/scripts at your convenience.

Development

npx tsc --noEmit -p tsconfig.json
npx vitest run --no-file-parallelism
npm run verify:floating          # on-screen smoke for the floating Ask (needs a display)
npm run verify:floating-geometry # default transparent 360x420 click-through shell, cat bottom-left
npm run release:doctor           # CI-safe release/signing doctor for the unsigned/ad-hoc path
npm run package
npm run verify:release-artifact  # after npm run package, verifies the packaged .app shape
npm run package:release
npm run verify:release-channel   # release-channel build refuses deferred-v0 flags
npm run verify:packaged-memory   # packaged memory write -> quit -> relaunch -> recall smoke
npm run verify:packaged-memory-health # packaged Keychain/memory-paused UX stays non-blocking
npm run verify:packaged-live-memory-turn  # packaged relaunch -> live Ollama turn uses recalled memory
npm run verify:packaged-natural-memory-turn # packaged natural-language teach -> relaunch -> recall turn
npm run verify:packaged-onboarding
npm run verify:packaged-model-setup # packaged Ollama-down/Recheck -> one-click local model pull
npm run verify:packaged-first-task # packaged persisted project -> first typed coding task writes a file
npm run verify:packaged-real-codex # opt-in: same packaged path with your real Codex CLI
npm run verify:memory-steered # opt-in proof that recalled memory reaches DECIDE and args.task

# Developer-ID release path, after exporting APPLE_ID/APPLE_PASSWORD/APPLE_TEAM_ID:
npm run verify:signing-readiness # strict Developer-ID env/cert/tool doctor before npm run make
npm run verify:signing-auth      # checks Apple credential auth with notarytool history
npm run make
npm run verify:release-artifact:dmg # after npm run make, verifies the mounted DMG contains Roro.app
npm run verify:release-artifact:signed # after Developer-ID npm run make

Status

What is working:

  • Electron app builds and packages
  • typed IPC between renderer and main
  • procedural pixel cat, transparent floating mode, and state effects
  • packaged workdir onboarding: native project picker, persisted userData/config.json, and typed/floating Ask gates
  • packaged same-build memory persistence smoke: a real packaged app writes and recalls an observation across relaunch
  • packaged live-memory turn smoke: with local Ollama ready, a real packaged turn narrates a recalled value after relaunch
  • packaged natural-memory turn smoke: with local Ollama ready, a real packaged turn learns a stated preference, relaunches, and uses it
  • packaged model-setup smoke: a real packaged app guides Ollama-down Recheck into missing local models, then through the public Download button and flips ready
  • packaged first-task smoke: a real packaged app with persisted project config verifies the public executor-readiness bridge, then runs a typed coding task through public turnRun and Codex event handling
  • packaged real-Codex smoke: the packaged first-task path can discover and run the user's authenticated Codex CLI without the fake executor override
  • release/signing doctor: CI checks the unsigned path, and a strict local doctor fails loud before Developer-ID make
  • signing auth doctor: with Apple env set, verifies notarytool credentials before uploading a build
  • DMG release artifact: macOS CI builds a versioned .dmg and verifies it mounts with Roro.app
  • local Ollama brain (decide/vision/embeddings) — verified end-to-end against a live daemon
  • local encrypted files-as-truth memory (owner-scoped, survives restarts)
  • Codex and Claude executor adapters behind one event stream
  • typed text path + the on-device voice control core/seam hidden behind dev flags

What needs extra setup or a real device:

  • on-device voice (Silero VAD + whisper STT + Kokoro TTS) behind internal RORO_*_VOICE dev flags + microphone permission — fully local, no cloud/model keys
  • screen capture permission for vision (the 7B vision model needs substantial RAM)

Project Shape

src/main/                 Electron main process and orchestration
src/renderer/             UI, character, voice, captions, event wiring
src/core/brain/                local Ollama decision, vision, embeddings
src/core/memory2/         local encrypted files-as-truth + in-memory vector index
src/core/executor/        Codex and Claude adapters
src/shared/               IPC, event, memory, avatar, env contracts
RUN.md                    live setup and integration guide

About

Roro — a local-first desktop coding companion that drives your coding agent and remembers how you work.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors