Skip to content

CalamooseLabs/robomoose

Repository files navigation

Calamoose Labs Presents

Logo

R O B O M O O S E

Robomoose 🫎 is a self-hosted, personal AI orchestration assistant. It runs as a NixOS systemd service alongside antlers' vibe-server, giving you a persistent chat companion (desktop + mobile web UI) that you brainstorm and delegate with. Robomoose answers via one-shot claude -p calls streamed token-by-token, spawns and monitors vibe sessions (Claude Code instances) through vibe-server's API, and keeps a durable memory of your todos, theories, and outstanding tasks.

It is a coordinator and memory layer, not a remote keyboard: it spawns the right session, tells you exactly what to say to it from claude.ai / the Claude mobile app, tracks the task as outstanding, and watches session state live.

Built on Deno with zero external imports — only Deno.* and Web-platform globals — so the deno compile step needs no network and builds reproducibly in the sandbox (a cold build fetches only the pinned denort runtime).


Features

  • Streaming web chat — a persistent SSE connection streams robomoose's reply token-by-token; user messages right, robomoose left with a 🫎 avatar.
  • Session orchestration — robomoose emits <dispatch> blocks to spawn / kill vibe sessions; each spawn drops an inline "open in claude.ai →" card and records an outstanding task.
  • Persistent memory — todos (checkable inline), theories, and outstanding tasks, stored as flat JSON with serialized, corruption-safe writes. Robomoose updates them itself via <memory> blocks.
  • Live monitoring — a background poller reflects session status/state/token changes in the sidebar within 5s, reconciles finished tasks, and shows an "unreachable" indicator (recovering automatically) when vibe-server is down.
  • Plan-usage panel — a colour-coded usage bar; robomoose proactively warns you when usage crosses 80%.
  • Log tail — click a session to stream its live log in a panel.
  • Installable PWA — dark theme, mobile bottom-sheet layout, manifest + icons (installable from localhost or behind TLS).
  • Shared-password auth — an HMAC-signed cookie (or fully passwordless on a trusted host).

Architecture

Browser ──SSE / POST──▶ robomoose (Deno.serve :8421)
                          ├─ brain   : `claude -p` per turn, history in the prompt
                          ├─ memory  : todos / theories / outstanding JSON + ROBOMOOSE.md
                          ├─ monitor : polls sessions (5s) + usage (60s)
                          └─ VibeClient ──HTTP──▶ vibe-server (:8420)
                               GET  /api/presets · GET /api/sessions
                               POST /api/sessions {preset} · DELETE /api/sessions/:id
                               GET  /api/sessions/:id/logs (SSE) · GET /api/usage

The two services share one host, the vibe user, and one CLAUDE_CONFIG_DIR (the subscription OAuth login), so robomoose's claude -p calls and vibe-server's sessions bill the same plan.

SSE event protocol (GET /api/chat)

One persistent EventSource per browser tab carries every async event:

Event Payload Meaning
token {text} a streamed chunk of robomoose's reply
done {dispatches} the turn finished; render dispatch chips
vibe_spawned {preset, sessionId, name, directories} a session was spawned
vibe_update {sessionId, name, state, tokens, status} a session changed
state {todos, theories, outstanding, presets, sessions, usage, vibeReachable} full sidebar refresh
error {message} a turn or dispatch failed

NixOS setup

Add both flakes as inputs and import their modules. Run robomoose next to vibe-server, sharing the vibe user and the Claude config dir:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    antlers.url = "github:CalamooseLabs/antlers";
    robomoose.url = "github:CalamooseLabs/robomoose";
  };

  outputs = { nixpkgs, antlers, robomoose, ... }: {
    nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        antlers.nixosModules.vibe          # programs.vibe — the launcher + presets
        antlers.nixosModules.vibe-server   # services.vibe-server
        robomoose.nixosModules.robomoose   # services.robomoose
        ./configuration.nix
      ];
    };
  };
}
# configuration.nix
{
  # The vibe launcher: define presets robomoose can route work to.
  programs.vibe.presets.api = {
    directories = [ "/srv/api" ];
    branch = "main";
  };

  services.vibe-server = {
    enable = true;
    passwordFile = "/run/secrets/vibe-password";
    claudeConfigDir = "/var/lib/vibe/claude";   # the shared subscription login
  };

  services.robomoose = {
    enable = true;
    passwordFile = "/run/secrets/robomoose-password";
    vibeServerPasswordFile = "/run/secrets/vibe-password";  # same file vibe-server uses
    claudeConfigDir = "/var/lib/vibe/claude";               # share one login
    # openFirewall = true; localNetworkOnly = true;         # LAN access
  };
}

Authenticate the vibe user to Claude once so both services share the login. Easiest is vibe-server's "Log in to Claude" banner (it targets the shared config dir). To do it from a shell, point CLAUDE_CONFIG_DIR at that same dir:

sudo -u vibe env CLAUDE_CONFIG_DIR=/var/lib/vibe/claude claude   # then /login

Then browse to http://myhost:8421.

Key options (services.robomoose)

Option Default Purpose
port / hostname 8421 / 0.0.0.0 listen address
passwordFile null shared login password (null ⇒ passwordless)
vibeServerUrl http://127.0.0.1:8420 vibe-server API base
vibeServerPasswordFile null vibe-server login password
model claude-opus-4 model for robomoose's own replies
claudeConfigDir <stateDir>/.claude Claude OAuth login dir (share with vibe-server)
stateDir / memoryDir /var/lib/robomoose / …/memory runtime state
user / group vibe / vibe service identity (shared, auto-created)
openFirewall / localNetworkOnly false firewall exposure
requireVibeServer false hard-couple to vibe-server (off — robomoose survives it being down)
enableNixLd true needed for the compiled Deno ELF

The vibe user, CLAUDE_CONFIG_DIR passthrough, and a hardened systemd sandbox (ProtectSystem=strict, NoNewPrivileges, PrivateTmp, scoped ReadWritePaths) are configured for you. Edit ROBOMOOSE.md in the memory dir to give robomoose your infrastructure knowledge and routing rules.


Development

This repo doubles as a vibe-shell dev environment. direnv allow (or nix develop) puts deno, vibe, git, gh, and the commit/wiki helpers on PATH.

deno task dev       # run with --watch (defaults when $ROBOMOOSE_CONFIG is unset)
deno task test      # the full unit + integration suite
deno task compile   # deno compile → ./robomoose

nix build .#robomoose   # the packaged binary
nix flake check         # builds the package + runs deno test + evaluates the module

Commits here are cryptographically signed by a human key — see CLAUDE.md for the gcommit workflow.

License

Robomoose is open-source software licensed under the MIT License.



© 2024 Calamoose Labs, Inc.   Calamoose Labs Logo

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors