Maru
January 15, 2026 Β· View on GitHub
A research assistant built with Moru sandbox and Claude Agent SDK.
https://github.com/user-attachments/assets/7e99b82d-9f9f-4664-97f8-eedd833ed5f4
Features
π€ Multi-Agent Sessions
Run multiple Claude in parallel. Each agent gets its own dedicated Linux VM.
π¬ Native Message Format
Renders Claude Code's native message format. Not restricted message subset of Claude Agent SDK.
β‘ Real-time Streaming
See tool executions, thinking, and results in real-time
π Session Resume
Agents maintain session history. Resume sessions anytime
πΎ Workspace Persistence
Workspaces are saved to storage and restored on session resume. Files and Claude session persist across sessions.
π File Explorer & Editor
Browse and view files in the agent's workspace. Download files that the agent writes or edits.
Detail
- Claude Code stores each chat session locally as newline-delimited JSON.
- I reverse-engineered those JSONL message formats and turned them into JSON Schemas for reuse (see agent-schemas)
- When a user sends a message, we boot a fresh Moru VM with a clean workspace; if itβs a resume, we restore the previous workspace and session JSONL into the VM
- Inside the VM, the agent reads the message from stdin and calls the Claude Agent SDK
query()function. - The backend tails the session JSONL file for new records and streams them to the frontend in near real time.
- When the run completes, we sync the workspace to Google Cloud Storage (GCS) so it can be restored next time.
Try It
Cloud: maru.moru.io - Maru is BYOK (Bring Your Own Key), but your API key is not saved on our server.
Self-hosted: Follow the setup instructions below.
Getting Started (Self-hosted)
Prerequisites
- Node.js 22+
- PostgreSQL
- Moru API Key (for sandbox execution)
- GitHub OAuth App (for authentication)
Installation
- Clone and install dependencies:
git clone https://github.com/moru-ai/maru.git
cd maru
npm install
- Set up environment files:
cp apps/server/.env.example apps/server/.env
cp apps/frontend/.env.example apps/frontend/.env
cp packages/db/.env.template packages/db/.env
- Configure environment variables:
packages/db/.env
DATABASE_URL="postgresql://postgres:@127.0.0.1:5432/maru_dev"
DIRECT_URL="postgresql://postgres:@127.0.0.1:5432/maru_dev"
apps/server/.env
# Database
DATABASE_URL="postgresql://postgres:@127.0.0.1:5432/maru_dev"
# GitHub OAuth
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
# Moru Sandbox (required)
MORU_API_KEY=your_moru_api_key
MORU_TEMPLATE_ID=maru-agent
MORU_SANDBOX_TIMEOUT_MS=3600000
# GCS Storage (optional, for workspace persistence)
GCS_BUCKET_NAME=your-bucket-name
GCS_KEY_FILE=./gcs-key.json
apps/frontend/.env
NEXT_PUBLIC_SERVER_URL="http://localhost:4000"
BETTER_AUTH_SECRET=your_secret_here
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
DATABASE_URL="postgresql://postgres:@127.0.0.1:5432/maru_dev"
- Set up the database:
# Create database
psql -U postgres -c "CREATE DATABASE maru_dev;"
# Generate Prisma client and push schema
npm run generate
npm run db:push
- Build the agent template:
cd apps/agent
cp .env.example .env
# Add your MORU_API_KEY to .env
# Build and register the template
.venv/bin/python template.py
- Start development servers:
npm run dev
- Frontend: http://localhost:3000
- Backend: http://localhost:4000
Development Commands
# Start dev servers (frontend + backend)
npm run dev
# Type checking
npm run check-types
# Linting
npm run lint
# Database operations
npm run db:push # Push schema changes
npm run generate # Generate Prisma client
npm run db:studio # Open Prisma Studio
Rebuilding the Agent Template
After modifying any files in apps/agent/ (including Dockerfile, src/, or INSTRUCTIONS.md), you must rebuild the template:
cd apps/agent
.venv/bin/python template.py
This builds a new Docker image and registers it with Moru. The next sandbox will use the updated template.
License
MIT License