Skip to content

pedrovgs/Milo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

25 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ• Milo

Milo

Milo is a desktop pet companion for Claude Code and Codex CLI. It sits as a transparent overlay in the bottom-right corner of your screen and reacts to agent activity in real time β€” barking, showing speech bubbles, and playing sounds as your coding assistant edits files, runs commands, and searches the web.

Milo in action

πŸ“¦ Installation

Quick install (one command)

git clone https://github.com/pedrogomez/milo.git
cd milo && ./scripts/install.sh

Optional provider mode:

./scripts/install.sh --provider codex
./scripts/install.sh --provider claude
./scripts/install.sh --provider both

The install script will:

  1. Verify prerequisites (Node.js >= 20, Rust, npm)
  2. Build the Milo event server
  3. Optionally install Claude hooks into ~/.claude/settings.json (when provider includes claude)
  4. Register the event server as a macOS Launch Agent (starts automatically at login)
  5. Build the Milo desktop app and copy Milo.app to /Applications (macOS)

Manual install

1. Clone the repository

git clone https://github.com/pedrogomez/milo.git
cd milo

2. Build and configure the event server

cd event-stream
npm install
npm run build
npm run install-hooks                             # required only for Claude
MILO_EVENT_PROVIDERS=both npm run install-service # claude | codex | both

3. Build and run the Milo desktop app

cd pixijs/milo
npm install
npm run tauri:build
open src-tauri/target/release/bundle/macos/Milo.app

After installation

The event server starts automatically at login β€” no terminal needed. Just open Milo:

open /Applications/Milo.app

To manage the event server service:

cd event-stream
npm run service-status      # check if the service is running
npm run uninstall-service   # stop and remove the Launch Agent
MILO_EVENT_PROVIDERS=both npm run install-service  # re-install with provider mode

Server logs are written to ~/Library/Logs/Milo/.

Move Milo anywhere on screen

Use the tray menu:

  1. Uncheck Lock position (click-through)
  2. Drag Milo to any position
  3. Check Lock position (click-through) again to keep the new position and restore click-through mode

Use Reset to bottom-right anytime to snap Milo back to the default corner.

πŸ—οΈ Architecture Overview

+--------------+  stdin/JSON  +----------+  HTTP POST  +--------------+
|  Claude Code | -----------> |  hook.js | -----------> |              |
|  (hooks)     |              |          |              |              |
+--------------+              +----------+              |  server.js   |  WebSocket  +------------------+
                                                        |  :6271       | -----------> |  Milo (Tauri +   |
+--------------+  JSONL tail   +---------------------+  |              |              |  PixiJS overlay) |
|  Codex CLI   | ------------> | ~/.codex/sessions/* |->|              |              +------------------+
|  (sessions)  |               |  (polling tailer)   |  +--------------+
+--------------+               +---------------------+

πŸ“‹ Prerequisites

  • Node.js >= 20
  • Rust stable >= 1.77.2 (rustup default stable)
  • Tauri CLI (installed as a dev dependency via npm)
  • npm

πŸš€ Getting Started

1. Install dependencies

cd pixijs/milo
npm install

2. Set up the event server

cd event-stream
npm install
npm run build

# Claude only
npm run install-hooks
MILO_EVENT_PROVIDERS=claude npm start

# Codex only
MILO_EVENT_PROVIDERS=codex npm start

# Both
# (install Claude hooks once, then run both providers)
npm run install-hooks
MILO_EVENT_PROVIDERS=both npm start

For Codex, Milo tails ~/.codex/sessions JSONL files. Codex sessions started with --ephemeral are not persisted, so they cannot be streamed via file tailing. See event-stream/README.md for full backend details.

3. Run Milo in development mode

cd pixijs/milo
npm run tauri:dev

This starts the Vite dev server (port 8080) and opens the Tauri window β€” a transparent, frameless overlay pinned to the bottom-right of your screen. Changes to the TypeScript/PixiJS code hot-reload automatically.

4. Build the production app

cd pixijs/milo
npm run tauri:build

Output:

  • pixijs/milo/src-tauri/target/release/bundle/macos/Milo.app
  • pixijs/milo/src-tauri/target/release/bundle/dmg/Milo_0.1.0_aarch64.dmg

5. Run the built app

open pixijs/milo/src-tauri/target/release/bundle/macos/Milo.app

πŸ§ͺ Testing

Run tests

cd pixijs/milo
npm test

Lint, format, and type check

cd pixijs/milo
npm run lint
npx prettier --check src/
npx tsc --noEmit

🧱 Architecture

The frontend TypeScript codebase follows a clean architecture with three layers:

pixijs/milo/src/
  domain/               # Pure business logic, no external dependencies
    types.ts            # Core types (MiloMessage, AgentEvent, configs)
    message-queue.ts    # FIFO message queue with listener support
    event-classifier.ts # Classifies provider events into Milo messages
    reminder-scheduler.ts # Reminder timing calculations and state management
    text.ts             # Text processing (markdown stripping, truncation)
  infrastructure/       # External system adapters
    agent-event-stream.ts  # WebSocket client for Milo event server
    tauri-reminders.ts  # Bridges Tauri events to the reminder manager
    bark-audio.ts       # Audio playback and mute state via Tauri events
  animations.ts         # PixiJS animation state machine (idle/bark)
  bubble.ts             # PixiJS speech bubble rendering
  main.ts               # Composition root: wires everything together
  random.ts             # No-repeat random picker utility
  session-names.ts      # Maps session IDs to funny display names
  i18n/                 # Localization (en, es, fr, de, it, pt, zh, ja)

Domain layer β€” Pure functions and classes with no dependencies on Tauri, WebSocket, or PixiJS. All domain logic is independently testable.

Infrastructure layer β€” Adapts external systems (Tauri event API, WebSocket, HTML Audio) to domain interfaces.

Composition root (main.ts) β€” Initializes PixiJS, wires domain and infrastructure together, and runs the animation/message display loop.

πŸ“‚ Project Structure

milo/
  event-stream/                  # Event stream server (Claude + Codex adapters)
    src/
      types.ts             # Canonical event types and server config
      hook.ts              # Claude hook handler β€” reads stdin, POSTs to server
      server.ts            # WebSocket + HTTP server (port 6271)
      install.ts           # Installs/uninstalls hooks in Claude settings
      providers/           # Provider adapters (claude, codex)
    bin/                   # CLI entry points
  pixijs/
    art/                   # Source animation frames
    milo/                  # Tauri v2 + PixiJS desktop app (see Architecture above)
      public/assets/       # Animation frames + sound files
      src-tauri/           # Tauri v2 Rust backend
        src/lib.rs         # Window setup (transparent, click-through)
        tauri.conf.json
  tools/
    sprite-extractor/      # Extracts animation frames from video files
  .github/workflows/ci.yml # CI pipeline (lint, format, typecheck, test, build)

βš™οΈ How It Works

  1. Claude Code emits hook events piped to hook.js, which forwards them to the server.
  2. Codex CLI writes session JSONL files in ~/.codex/sessions, and the server tails them.
  3. The event server (event-stream/) normalizes provider events, stores them in a ring buffer, and broadcasts them over WebSocket.
  4. Milo (pixijs/milo/) connects to the WebSocket stream, classifies each event, queues a message, and triggers:
    • A bark animation 🐾 (randomly chosen, no repeats)
    • A speech bubble πŸ’¬ with context about what the coding agent is doing
    • A bark sound effect πŸ”Š (randomly chosen, no repeats)
  5. Between events, Milo plays idle animations in a loop.
  6. Reminders πŸ”” fire on configurable schedules (daily or hourly intervals) and display with a bell prefix in the speech bubble to differentiate them from agent activity messages.

πŸͺŸ Tauri Window Configuration

The desktop overlay is configured as:

  • Transparent background (no visible window chrome)
  • Frameless (no title bar or decorations)
  • Always on top of other windows
  • Click-through enabled (clicks pass through transparent areas)
  • Hidden from Dock/taskbar
  • Positioned at the bottom-right corner of the screen

πŸ“œ Available Scripts

pixijs/milo/

Command Description
npm run tauri:dev Development mode with hot reload
npm run tauri:build Build the production .app bundle
npm run dev Run PixiJS frontend only (browser)
npm test Run tests
npm run lint Run ESLint
npx prettier --check src/ Check formatting
npx tsc --noEmit Type check

event-stream/

Command Description
npm start Start the event stream server
npm run install-hooks Register hooks in Claude Code settings
npm run uninstall-hooks Remove hooks from Claude Code settings
npm run install-service Register Launch Agent (auto-start at login)
npm run uninstall-service Stop and remove the Launch Agent
npm run service-status Check if the service is running
npm test Run backend adapter tests

Environment variables for npm start / service install:

  • MILO_EVENT_PROVIDERS (claude, codex, both; default claude)
  • CLAUDE_EVENT_PORT (default 6271)
  • CODEX_SESSIONS_DIR (default ~/.codex/sessions)
  • CODEX_POLL_MS (default 2000)

πŸ‘¨πŸ»β€πŸ’» Developed By

Follow me on X Add me to Linkedin
  • Does your use Milo? Just tell me if this is the case!

πŸ“„ License

Copyright 2026 Pedro Vicente GΓ³mez SΓ‘nchez

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

About

🐢 Claude code companion app so you don't feel alone while waiting for claude code!

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors