{"id":50775739,"url":"https://github.com/parolkar/zuzu","last_synced_at":"2026-06-11T23:30:32.388Z","repository":{"id":342507364,"uuid":"1174191875","full_name":"parolkar/zuzu","owner":"parolkar","description":"JRuby framework for AI-native desktop apps — local LLM, single .jar/.dmg/.exe/.deb distribution, Claude Code-ready scaffolding. SQLite-backed AgentFS as a sandboxed virtual filesystem for the agent. Ships as a JRE bundled for native installers (.dmg/.deb/.exe). No cloud required. No extra java installation needed.","archived":false,"fork":false,"pushed_at":"2026-03-07T00:47:42.000Z","size":3129,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-07T21:04:52.966Z","etag":null,"topics":["ai-agents","app","application","builder","claude-code","desktop-application","jar","jruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/parolkar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-06T06:58:43.000Z","updated_at":"2026-03-07T00:47:45.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/parolkar/zuzu","commit_stats":null,"previous_names":["parolkar/zuzu"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/parolkar/zuzu","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parolkar%2Fzuzu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parolkar%2Fzuzu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parolkar%2Fzuzu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parolkar%2Fzuzu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/parolkar","download_url":"https://codeload.github.com/parolkar/zuzu/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parolkar%2Fzuzu/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34222709,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","app","application","builder","claude-code","desktop-application","jar","jruby"],"created_at":"2026-06-11T23:30:31.700Z","updated_at":"2026-06-11T23:30:32.383Z","avatar_url":"https://github.com/parolkar.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Zuzu\n\n**Build AI-native desktop apps that run entirely on the user's machine.**\n\nEvery application you install on an operating system does the same fundamental thing: it translates human intent into OS system calls. A text editor writes bytes to disk. A browser opens network connections. At its core, every installed app is an orchestrator of operating system capabilities.\n\nLLMs are simply a more expressive interface for exactly that orchestration. Zuzu is a framework built on this premise — for developers who want to ship installable, AI-native desktop apps where the intelligence runs on the user's hardware, not in a data center.\n\n**Why does this matter?**\n\n- **Privacy by architecture.** The agent operates inside AgentFS — a sandboxed virtual filesystem backed by a single SQLite file. It cannot touch the host OS unless you explicitly open that door. There is no network call to make, no token to rotate, no terms of service that changes next quarter.\n\n- **Deployable like software, not like a service.** Package your app as a single `.jar` — or go further with `zuzu package` and produce a native installer (`.dmg`/`.app` on macOS, `.deb` on Linux, `.exe` on Windows) that bundles a minimal JRE via jlink. Users download, double-click, and run. No Java pre-installed. No Docker. No cloud subscription. No infrastructure to maintain.\n\n- **Built for regulated environments.** A therapist keeping session notes, an auditor running confidential analysis, a corporate team in a restricted environment — these are exactly the users who benefit most from powerful AI but are currently blocked by cloud dependency. A bundled LLM in a self-contained Java application needs no external approval to run.\n\n- **Developer experience that matches how software is actually built today.** `zuzu new my_app` scaffolds a project pre-wired for Claude Code: CLAUDE.md, skills for `/setup`, `/add-tool`, `/customize`, and `/debug` — all enforcing Zuzu's patterns. Open the folder, start your coding agent, describe what you want to build.\n\n→ [Why Zuzu exists](docs/why.md) · [Quick Demo](https://raw.githubusercontent.com/parolkar/zuzu/refs/heads/main/docs/demo/zuzu_quick_demo_01.mp4)\n\n\u003cvideo src=\"https://raw.githubusercontent.com/parolkar/zuzu/refs/heads/main/docs/demo/zuzu_quick_demo_01.mp4\" controls width=\"100%\"\u003e\u003c/video\u003e\n[Quick Demo](https://raw.githubusercontent.com/parolkar/zuzu/refs/heads/main/docs/demo/zuzu_quick_demo_01.mp4)\n\n| Component | Technology |\n|-----------|------------|\n| Runtime | JRuby 10.0.3.0 (Java 21+) |\n| GUI | Glimmer DSL for SWT |\n| Database | SQLite via JDBC |\n| LLM | llamafile (local inference) |\n| Packaging | Warbler (.jar / .war) |\n\n## Quick Start\n\n### Prerequisites\n\n- **macOS** or **Linux** (Windows support is planned)\n- **Java 21+**\n- **rbenv** (recommended) or any JRuby version manager\n\n### One-Command Setup\n\n```bash\ngit clone https://github.com/parolkar/zuzu.git\ncd zuzu\nbin/setup\n```\n\n`bin/setup` installs Java 21, JRuby 10.0.3.0, and all gem dependencies\nautomatically. If you prefer manual setup, see [Manual Setup](#manual-setup)\nbelow.\n\n### Create Your First App\n\nWhen you run `bin/zuzu new` from the source tree, it automatically detects\ndev mode and points the scaffolded app's Gemfile at your local checkout\n(no published gem needed).\n\n```bash\nbin/zuzu new my_assistant\ncd my_assistant\nbundle install\n```\n\nDownload a llamafile model:\n\n```bash\nmkdir -p models\ncurl -L -o models/llava-v1.5-7b-q4.llamafile \\\n  https://huggingface.co/Mozilla/llava-v1.5-7b-llamafile/resolve/main/llava-v1.5-7b-q4.llamafile\nchmod +x models/llava-v1.5-7b-q4.llamafile\n```\n\nEdit `app.rb` to point at your model:\n\n```ruby\nZuzu.configure do |c|\n  c.app_name = 'My Assistant'\n  # Works both when run directly and from a packaged .jar\n  base = __dir__.to_s.start_with?('uri:classloader:') ? Dir.pwd : __dir__\n  c.llamafile_path = File.join(base, 'models', 'llava-v1.5-7b-q4.llamafile')\n  c.db_path        = File.join(base, '.zuzu', 'zuzu.db')\n  c.port           = 8080\nend\n```\n\nLaunch:\n\n```bash\nbundle exec zuzu start\n```\n\nYou'll see a native desktop chat window. The llamafile model starts automatically\nin the background. Click **Admin Panel** to browse the AgentFS virtual filesystem.\n\n---\n\n## Manual Setup\n\nIf `bin/setup` doesn't suit your workflow, follow these steps.\n\n### 1. Install Java 21+\n\n**macOS (Homebrew — recommended):**\n\n```bash\nbrew install --cask temurin@21\n```\n\nTemurin is the Eclipse/Adoptium OpenJDK distribution. The cask sets up\n`JAVA_HOME` automatically — no manual PATH changes needed.\n\n**macOS (SDKMAN):**\n\n```bash\ncurl -s https://get.sdkman.io | bash\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk install java 21-tem\n```\n\n**Ubuntu / Debian:**\n\n```bash\nsudo apt-get update\nsudo apt-get install openjdk-21-jdk\n```\n\nVerify:\n\n```bash\njava -version\n# → openjdk version \"21.x.x\" ...\n```\n\n### 2. Install JRuby 10.0.3.0 via rbenv\n\n```bash\n# Install rbenv if needed\nbrew install rbenv ruby-build   # macOS\n# or: https://github.com/rbenv/rbenv#installation\n\nrbenv install jruby-10.0.3.0\nrbenv local jruby-10.0.3.0\nruby -v\n# → jruby 10.0.3.0 (ruby 3.x.x) ...\n```\n\n### 3. Install Gems\n\n```bash\ngem install bundler\nbundle install\n```\n\n---\n\n## Architecture\n\n```\n┌────────────────────────────────────────────────────┐\n│                   Zuzu App (SWT)                   │\n│  ┌──────────┐  ┌──────────────────────────────┐    │\n│  │ AgentFS  │  │       Chat Interface         │    │\n│  │  (files) │  │                              │    │\n│  │          │  │  User: How do I ...          │    │\n│  │  + docs/ │  │  Zuzu: Let me check ...      │    │\n│  │    a.txt │  │                              │    │\n│  └──────────┘  └──────────────────────────────┘    │\n│                ┌──────────────────────────────┐    │\n│                │ [  Type a message...  ] [Send]│    │\n│                └──────────────────────────────┘    │\n└──────────────────────────┬─────────────────────────┘\n                           │\n              ┌────────────▼────────────┐\n              │      Agent (ReAct)      │\n              │   ┌─────┐ ┌─────────┐  │\n              │   │Tools│ │ Memory  │  │\n              │   └──┬──┘ └────┬────┘  │\n              └──────┼─────────┼───────┘\n                     │         │\n              ┌──────▼─────────▼───────┐\n              │    SQLite (JDBC)       │\n              │  - fs_inodes/dentries  │\n              │  - messages            │\n              │  - kv_store            │\n              │  - tool_calls          │\n              └────────────────────────┘\n                           │\n              ┌────────────▼────────────┐\n              │   llamafile (local LLM) │\n              │   OpenAI-compat API     │\n              │   http://127.0.0.1:8080 │\n              └─────────────────────────┘\n```\n\n### Project Structure\n\n```\nzuzu/\n├── lib/zuzu/\n│   ├── config.rb             # Zuzu.configure { |c| ... }\n│   ├── store.rb              # JDBC SQLite — single connection wrapper\n│   ├── agent_fs.rb           # Virtual filesystem + KV store + audit log\n│   ├── memory.rb             # Conversation history\n│   ├── llm_client.rb         # HTTP client for llamafile\n│   ├── llamafile_manager.rb  # Subprocess lifecycle\n│   ├── tool_registry.rb      # Register / execute agent tools\n│   ├── agent.rb              # ReAct loop (think → act → observe)\n│   ├── app.rb                # Glimmer SWT desktop shell\n│   ├── tools/\n│   │   ├── file_tool.rb      # read_file, write_file, list_directory\n│   │   ├── shell_tool.rb     # run_command (allowlisted)\n│   │   └── web_tool.rb       # http_get\n│   └── channels/\n│       ├── base.rb           # Abstract channel interface\n│       ├── in_app.rb         # Desktop GUI (default)\n│       └── whatsapp.rb       # WhatsApp Cloud API webhook\n├── bin/\n│   ├── zuzu                  # CLI: new / start / console / version\n│   └── setup                 # One-command bootstrap\n├── templates/\n│   └── app.rb                # Scaffold template for `zuzu new`\n├── models/                   # Place llamafile models here\n├── Gemfile\n├── zuzu.gemspec\n├── Rakefile\n├── warble.rb                 # Warbler config for .jar packaging\n└── app.rb                    # Phase 1 standalone reference\n```\n\n---\n\n## Usage Guide\n\n### Custom Tools\n\nRegister tools that the agent can call during conversations:\n\n```ruby\nZuzu::ToolRegistry.register(\n  'lookup_weather',\n  'Get current weather for a city.',\n  {\n    type: 'object',\n    properties: { city: { type: 'string' } },\n    required: ['city']\n  }\n) do |args, agent_fs|\n  # Your logic here — call an API, read a file, etc.\n  \"Weather in #{args['city']}: 22°C, sunny\"\nend\n```\n\nThe agent's ReAct loop will automatically discover and call your tools when\nrelevant to the user's question.\n\n### WhatsApp Channel\n\nEnable WhatsApp so users can chat with your agent via their phone:\n\n```ruby\nZuzu.configure do |c|\n  c.channels = ['whatsapp']\nend\n```\n\nSet environment variables:\n\n```bash\nexport WHATSAPP_TOKEN=\"your_cloud_api_token\"\nexport WHATSAPP_PHONE_ID=\"your_phone_number_id\"\nexport WHATSAPP_PORT=9292   # optional, defaults to 9292\n```\n\nThe WhatsApp channel starts a WEBrick webhook server that receives messages\nfrom the WhatsApp Cloud API and replies using the same agent.\n\n### Virtual Filesystem (AgentFS)\n\nThe agent operates in a sandboxed SQLite-backed filesystem:\n\n```ruby\nstore = Zuzu::Store.new\nfs    = Zuzu::AgentFS.new(store)\n\nfs.write_file('/notes/todo.txt', 'Buy groceries')\nfs.read_file('/notes/todo.txt')    # → \"Buy groceries\"\nfs.list_dir('/notes')              # → [\"todo.txt\"]\nfs.mkdir('/docs')\nfs.exists?('/notes/todo.txt')      # → true\n\n# Key-value store\nfs.kv_set('last_query', 'weather in Tokyo')\nfs.kv_get('last_query')            # → \"weather in Tokyo\"\n```\n\n### Packaging as .jar\n\nPackage your app as a standalone Java archive with a single command:\n\n```bash\nbundle exec zuzu package\n```\n\nThis auto-installs Warbler if needed, generates the necessary launcher, and\nproduces a `.jar` named after your app directory. Run it with:\n\n```bash\njava -XstartOnFirstThread -jar my_app.jar   # macOS\njava -jar my_app.jar                        # Linux / Windows\n```\n\n\u003e **Note:** Place your llamafile model in a `models/` directory alongside the\n\u003e `.jar` — models are not bundled into the archive.\n\n### Packaging as a native installer (no Java required for users)\n\nAfter building the JAR, `zuzu package` asks if you want to go further:\n\n```\nBundle into a self-contained native executable? (no Java required for users) [y/N]:\n```\n\nType `y` and Zuzu uses **jpackage** (bundled with JDK 21+) to produce a native\ninstaller that includes a minimal JRE — users never need to install Java:\n\n| Platform | Output |\n|----------|--------|\n| macOS | `.dmg` with a drag-to-Applications `.app` |\n| Linux | `.deb` package |\n| Windows | `.exe` installer |\n\nThe model file is not bundled (it can be gigabytes). After installing, users\nplace it in the platform user-data directory that Zuzu prints at build time:\n\n```\nmacOS:   ~/Library/Application Support/\u003cAppName\u003e/models/\u003cmodel\u003e.llamafile\nLinux:   ~/.local/share/\u003cAppName\u003e/models/\u003cmodel\u003e.llamafile\nWindows: %APPDATA%\\\u003cAppName\u003e\\models\\\u003cmodel\u003e.llamafile\n```\n\n---\n\n## Configuration Reference\n\n```ruby\nZuzu.configure do |c|\n  c.app_name       = 'My Agent'           # Window title\n  c.llamafile_path = 'models/llava-v1.5-7b-q4.llamafile'   # Path to llamafile binary\n  c.db_path        = '.zuzu/zuzu.db'      # SQLite database location\n  c.port           = 8080                  # llamafile API port\n  c.model          = 'LLaMA_CPP'          # Model identifier\n  c.channels       = ['whatsapp']          # Extra channels to enable\n  c.log_level      = :info                 # :debug, :info, :warn, :error\n  c.window_width   = 860                   # Window width in pixels\n  c.window_height  = 620                   # Window height in pixels\nend\n```\n\n---\n\n## CLI Reference\n\n```\nzuzu new APP_NAME    Scaffold a new Zuzu application\nzuzu start           Launch the Zuzu app in the current directory\nzuzu package         Package the app as a standalone .jar\nzuzu console         Open an IRB session with Zuzu loaded\nzuzu version         Print the Zuzu version\nzuzu help            Show this message\n```\n\n---\n\n## Troubleshooting\n\n### macOS: \"SWT main thread\" error\n\nSWT on macOS requires the main thread. Always launch with:\n\n```bash\nJRUBY_OPTS=\"-J-XstartOnFirstThread -J--enable-native-access=ALL-UNNAMED\" bundle exec ruby app.rb\n```\n\n### llamafile won't start\n\n- Ensure the file is executable: `chmod +x models/your-model.llamafile`\n- Check `models/llama.log` for errors.\n- Verify port 8080 isn't already in use: `lsof -i :8080`\n\n### \"java.lang.ClassNotFoundException: org.sqlite.JDBC\"\n\nRun `bundle install` to ensure `jdbc-sqlite3` is installed. The gem must be\nloaded before any database access.\n\n\n---\n\n## Philosophy\n\n- **Local-first.** Your data never leaves your machine.\n- **Minimal code.** The entire framework is ~800 lines of Ruby.\n- **No Docker.** Just Java, JRuby, and a single SQLite file.\n- **Channels built in.** Every app gets in-app chat and optional WhatsApp.\n- **Tools are Ruby blocks.** No YAML configs, no DSL ceremonies.\n\n---\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n\n## Author(s)\n\n**Abhishek Parolkar**\n- GitHub: [@parolkar](https://github.com/parolkar)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparolkar%2Fzuzu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fparolkar%2Fzuzu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparolkar%2Fzuzu/lists"}