🤖 rename nix-moltbot surfaces to moltbot

What:
- rename Clawdbot modules/packages/scripts/docs to Moltbot naming
- update yolo updater + config generation for Moltbot schema
- keep Clawdbot app asset names + env exports for upstream compatibility

Why:
- align Nix packaging with moltbot org rename
- fix hourly pin update failures after schema rename

Tests:
- not run (blocked on updated nix-moltbot remote for full nixos-config build)
This commit is contained in:
DJTBOT 2026-01-28 12:21:06 +01:00
parent 474ee38945
commit f0482a8a0c
39 changed files with 460 additions and 459 deletions

View File

@ -24,6 +24,6 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git config user.name "clawdbot-ci"
git config user.email "ci@clawdbot.local"
git config user.name "moltbot-ci"
git config user.email "ci@moltbot.local"
scripts/update-pins.sh

View File

@ -1,4 +1,4 @@
# AGENTS.md — nix-clawdbot
# AGENTS.md — nix-moltbot
Single source of truth for product direction: `README.md`.
@ -16,22 +16,22 @@ Defaults:
- NEVER send any message (iMessage, email, SMS, etc.) without explicit user confirmation:
- Always show the full message text and ask: “Im going to send this: <message>. Send? (y/n)”
Clawdbot packaging:
Moltbot packaging:
- The gateway package must include Control UI assets (run `pnpm ui:build` in the Nix build).
Golden path for pins (yolo + manual bumps):
- Hourly GitHub Action **Yolo Update Pins** runs `scripts/update-pins.sh`, which:
- Picks latest upstream clawdbot SHA with green non-Windows checks
- Picks latest upstream moltbot SHA with green non-Windows checks
- Rebuilds gateway to refresh `pnpmDepsHash`
- Regenerates `nix/generated/clawdbot-config-options.nix` from upstream schema
- Regenerates `nix/generated/moltbot-config-options.nix` from upstream schema
- Updates app pin/hash, commits, rebases, pushes to `main`
- Manual bump (rare): `GH_TOKEN=... scripts/update-pins.sh` (same steps as above). Use only if yolo is blocked.
- To verify freshness: `git pull --ff-only` and check `nix/sources/clawdbot-source.nix` vs `git ls-remote https://github.com/clawdbot/clawdbot.git refs/heads/main`.
- To verify freshness: `git pull --ff-only` and check `nix/sources/moltbot-source.nix` vs `git ls-remote https://github.com/moltbot/moltbot.git refs/heads/main`.
- If upstream is moving fast and tighter freshness is needed, trigger yolo manually: `gh workflow run "Yolo Update Pins"`.
Philosophy:
The Zen of ~~Python~~ Clawdbot, ~~by~~ shamelessly stolen from Tim Peters
The Zen of ~~Python~~ Moltbot, ~~by~~ shamelessly stolen from Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.

160
README.md
View File

@ -1,10 +1,10 @@
# nix-clawdbot
# nix-moltbot
> Declarative Clawdbot. Bulletproof by default.
> Declarative Moltbot. Bulletproof by default.
>
> macOS + Linux (headless). Windows is out of scope for now.
>
> <sub>Questions? Join the Clawdbot Discord and ask in **#golden-path-deployments**: https://discord.com/channels/1456350064065904867/1457003026412736537</sub>
> <sub>Questions? Join the Moltbot Discord and ask in **#golden-path-deployments**: https://discord.com/channels/1456350064065904867/1457003026412736537</sub>
## Table of Contents
@ -103,20 +103,20 @@ Nix is a **declarative package manager**. Instead of running commands to install
Copy this entire block and paste it to Claude, Cursor, or your preferred AI assistant:
```text
I want to set up nix-clawdbot on my machine (macOS or Linux).
I want to set up nix-moltbot on my machine (macOS or Linux).
Repository: github:clawdbot/nix-clawdbot
Repository: github:moltbot/nix-moltbot
What nix-clawdbot is:
- Batteries-included Nix package for Clawdbot (AI assistant gateway)
What nix-moltbot is:
- Batteries-included Nix package for Moltbot (AI assistant gateway)
- Installs gateway + tools everywhere; macOS app only on macOS
- Runs as a launchd service on macOS, systemd user service on Linux
What I need you to do:
1. Check if Determinate Nix is installed (if not, install it)
2. Create a local flake at ~/code/clawdbot-local using templates/agent-first/flake.nix
3. Create a docs dir next to the config (e.g., ~/code/clawdbot-local/documents) with AGENTS.md, SOUL.md, TOOLS.md
- If ~/.clawdbot/workspace already has these files, adopt them into the documents dir first
2. Create a local flake at ~/code/moltbot-local using templates/agent-first/flake.nix
3. Create a docs dir next to the config (e.g., ~/code/moltbot-local/documents) with AGENTS.md, SOUL.md, TOOLS.md
- If ~/.moltbot/workspace already has these files, adopt them into the documents dir first
4. Help me create a Telegram bot (@BotFather) and get my chat ID (@userinfobot)
5. Set up secrets (bot token, Anthropic key) - plain files at ~/.secrets/ is fine
6. Fill in the template placeholders and run home-manager switch
@ -131,12 +131,12 @@ My setup:
Reference the README and templates/agent-first/flake.nix in the repo for the module options.
```
Your agent will install Nix, create your config, and get Clawdbot running. You just answer its questions.
Your agent will install Nix, create your config, and get Moltbot running. You just answer its questions.
**What happens next:**
1. Your agent sets everything up and runs `home-manager switch`
2. You message your Telegram bot for the first time
3. Clawdbot runs its **bootstrap ritual** - it asks you playful questions: *"Who am I? What am I? Who are you?"* - to learn its identity and yours
3. Moltbot runs its **bootstrap ritual** - it asks you playful questions: *"Who am I? What am I? Who are you?"* - to learn its identity and yours
4. Once you've named it and introduced yourself, the bootstrap is done. You're up and running.
<details>
@ -147,13 +147,13 @@ Your agent will install Nix, create your config, and get Clawdbot running. You j
1. Install Determinate Nix.
2. Create a local config:
```bash
mkdir -p ~/code/clawdbot-local && cd ~/code/clawdbot-local
nix flake init -t github:clawdbot/nix-clawdbot#agent-first
mkdir -p ~/code/moltbot-local && cd ~/code/moltbot-local
nix flake init -t github:moltbot/nix-moltbot#agent-first
```
3. Edit `flake.nix` placeholders:
- `system` = `aarch64-darwin` (Apple Silicon) or `x86_64-darwin` (Intel)
- `home.username` and `home.homeDirectory`
- `programs.clawdbot.documents` with `AGENTS.md`, `SOUL.md`, `TOOLS.md`
- `programs.moltbot.documents` with `AGENTS.md`, `SOUL.md`, `TOOLS.md`
- Provider secrets (Telegram/Discord tokens, Anthropic API key)
4. Apply:
```bash
@ -161,7 +161,7 @@ Your agent will install Nix, create your config, and get Clawdbot running. You j
```
5. Verify:
```bash
launchctl print gui/$UID/com.steipete.clawdbot.gateway | grep state
launchctl print gui/$UID/com.steipete.moltbot.gateway | grep state
```
### Linux (headless + systemd user service)
@ -169,13 +169,13 @@ Your agent will install Nix, create your config, and get Clawdbot running. You j
1. Install Determinate Nix.
2. Create a local config:
```bash
mkdir -p ~/code/clawdbot-local && cd ~/code/clawdbot-local
nix flake init -t github:clawdbot/nix-clawdbot#agent-first
mkdir -p ~/code/moltbot-local && cd ~/code/moltbot-local
nix flake init -t github:moltbot/nix-moltbot#agent-first
```
3. Edit `flake.nix` placeholders:
- `system` = `x86_64-linux`
- `home.username` and `home.homeDirectory` (e.g., `/home/<user>`)
- `programs.clawdbot.documents` with `AGENTS.md`, `SOUL.md`, `TOOLS.md`
- `programs.moltbot.documents` with `AGENTS.md`, `SOUL.md`, `TOOLS.md`
- Provider secrets (Telegram/Discord tokens, Anthropic API key)
4. Apply:
```bash
@ -183,8 +183,8 @@ Your agent will install Nix, create your config, and get Clawdbot running. You j
```
5. Verify:
```bash
systemctl --user status clawdbot-gateway
journalctl --user -u clawdbot-gateway -f
systemctl --user status moltbot-gateway
journalctl --user -u moltbot-gateway -f
```
</details>
@ -203,7 +203,7 @@ You (Telegram/Discord) --> Gateway --> Tools --> Your machine does things
1. **CLI tools** - actual programs that do stuff (take screenshots, control Spotify, transcribe audio)
2. **Skills** - markdown files that teach the AI *how* to use those tools
When you enable a plugin, Nix installs the tools and wires up the skills to Clawdbot automatically - the gateway learns what it can do.
When you enable a plugin, Nix installs the tools and wires up the skills to Moltbot automatically - the gateway learns what it can do.
**Skills**: Instructions for the AI. A skill file says "when the user wants X, run this command." The AI reads these to know what it can do.
@ -213,15 +213,15 @@ When you enable a plugin, Nix installs the tools and wires up the skills to Claw
When you run `home-manager switch`:
1. Nix reads your `flake.nix` and resolves all plugin sources (GitHub repos, local paths)
2. For each plugin, Nix looks for a `clawdbotPlugin` output that declares:
2. For each plugin, Nix looks for a `moltbotPlugin` output that declares:
- What CLI packages to install
- What skill files to copy
- What environment variables it needs
3. Tools go on your PATH, skills get symlinked to `~/.clawdbot/workspace/skills/`
3. Tools go on your PATH, skills get symlinked to `~/.moltbot/workspace/skills/`
4. A launchd (macOS) or systemd user service (Linux) is created/updated to run the gateway
5. The gateway starts, loads skills, connects to your providers
All state lives in `~/.clawdbot/`. Logs at `/tmp/clawdbot/clawdbot-gateway.log`.
All state lives in `~/.moltbot/`. Logs at `/tmp/moltbot/moltbot-gateway.log`.
</details>
@ -229,16 +229,16 @@ All state lives in `~/.clawdbot/`. Logs at `/tmp/clawdbot/clawdbot-gateway.log`.
## Plugins
> **Note:** Complete the [Quick Start](#quick-start) first to get Clawdbot running. Then come back here to add plugins.
> **Note:** Complete the [Quick Start](#quick-start) first to get Moltbot running. Then come back here to add plugins.
Plugins extend what Clawdbot can do. Each plugin bundles tools and teaches the AI how to use them.
Plugins extend what Moltbot can do. Each plugin bundles tools and teaches the AI how to use them.
### First-party plugins
These ship with nix-clawdbot. Toggle them in your config:
These ship with nix-moltbot. Toggle them in your config:
```nix
programs.clawdbot.firstParty = {
programs.moltbot.firstParty = {
summarize.enable = true; # Summarize web pages, PDFs, videos
peekaboo.enable = true; # Take screenshots
oracle.enable = false; # Web search
@ -307,7 +307,7 @@ plugins = [
<details>
<summary><strong>For plugin developers</strong></summary>
Want to make your tool available as a Clawdbot plugin? Here's the contract.
Want to make your tool available as a Moltbot plugin? Here's the contract.
**Minimum structure:**
@ -319,7 +319,7 @@ your-plugin/
SKILL.md # Instructions for the AI
```
**Your `flake.nix` must export `clawdbotPlugin`:**
**Your `flake.nix` must export `moltbotPlugin`:**
```nix
{
@ -327,7 +327,7 @@ your-plugin/
let
pkgs = import nixpkgs { system = builtins.currentSystem; };
in {
clawdbotPlugin = {
moltbotPlugin = {
name = "hello-world";
skills = [ ./skills/hello-world ];
packages = [ pkgs.hello ]; # CLI tools to install
@ -355,20 +355,20 @@ See `examples/hello-world-plugin` for a complete working example.
---
**Full plugin authoring prompt** - paste this to your AI agent to make any repo nix-clawdbot-native:
**Full plugin authoring prompt** - paste this to your AI agent to make any repo nix-moltbot-native:
```text
Goal: Make this repo a nix-clawdbot-native plugin with the standard contract.
Goal: Make this repo a nix-moltbot-native plugin with the standard contract.
Contract to implement:
1) Add clawdbotPlugin output in flake.nix:
1) Add moltbotPlugin output in flake.nix:
- name
- skills (paths to SKILL.md dirs)
- packages (CLI packages to put on PATH)
- needs (stateDirs + requiredEnv)
Example:
clawdbotPlugin = {
moltbotPlugin = {
name = "my-plugin";
skills = [ ./skills/my-plugin ];
packages = [ self.packages.${system}.default ];
@ -429,7 +429,7 @@ Deliverables: flake output, env overrides, AGENTS.md, skill update.
> **Note:** You probably don't need to write this yourself. Your AI agent handles this when you use the [Quick Start](#quick-start) copypasta. These examples are here for reference.
### What Clawdbot needs (minimum)
### What Moltbot needs (minimum)
1. **Telegram bot token** - create via [@BotFather](https://t.me/BotFather), save to a file
2. **Your Telegram user ID** - get from [@userinfobot](https://t.me/userinfobot)
@ -443,7 +443,7 @@ The simplest setup:
```nix
{
programs.clawdbot = {
programs.moltbot = {
enable = true;
providers.telegram = {
enable = true;
@ -456,7 +456,7 @@ The simplest setup:
# Built-ins (tools + skills) shipped via nix-steipete-tools.
plugins = [
{ source = "github:clawdbot/nix-steipete-tools?dir=tools/summarize"; }
{ source = "github:moltbot/nix-steipete-tools?dir=tools/summarize"; }
];
};
}
@ -466,17 +466,17 @@ Then: `home-manager switch --flake .#youruser`
### Sensible defaults config
Uses `instances.default` to unlock per-group mention rules. If `instances` is set, you don't need `programs.clawdbot.enable`.
Uses `instances.default` to unlock per-group mention rules. If `instances` is set, you don't need `programs.moltbot.enable`.
```nix
{
programs.clawdbot = {
programs.moltbot = {
documents = ./documents;
instances.default = {
enable = true;
package = pkgs.clawdbot; # batteries-included
stateDir = "~/.clawdbot";
workspaceDir = "~/.clawdbot/workspace";
package = pkgs.moltbot; # batteries-included
stateDir = "~/.moltbot";
workspaceDir = "~/.moltbot/workspace";
providers.telegram = {
enable = true;
@ -500,8 +500,8 @@ Uses `instances.default` to unlock per-group mention rules. If `instances` is se
# Plugins (prod: pinned GitHub). Built-ins are via nix-steipete-tools.
# MVP target: repo pointers resolve to tools + skills automatically.
plugins = [
{ source = "github:clawdbot/nix-steipete-tools?dir=tools/oracle"; }
{ source = "github:clawdbot/nix-steipete-tools?dir=tools/peekaboo"; }
{ source = "github:moltbot/nix-steipete-tools?dir=tools/oracle"; }
{ source = "github:moltbot/nix-steipete-tools?dir=tools/peekaboo"; }
{ source = "github:joshp123/xuezh"; }
{
source = "github:joshp123/padel-cli";
@ -540,14 +540,14 @@ Use a shared base config and override only what's different. After changing loca
```nix
# flake inputs (pin prod + app)
inputs = {
nix-clawdbot.url = "github:clawdbot/nix-clawdbot?ref=v0.1.0"; # pins macOS app + gateway bundle
nix-moltbot.url = "github:moltbot/nix-moltbot?ref=v0.1.0"; # pins macOS app + gateway bundle
};
let
prod = {
enable = true;
# Prod gateway pin (comes from nix-clawdbot input @ v0.1.0 above).
package = inputs.nix-clawdbot.packages.${pkgs.system}.clawdbot-gateway;
# Prod gateway pin (comes from nix-moltbot input @ v0.1.0 above).
package = inputs.nix-moltbot.packages.${pkgs.system}.moltbot-gateway;
providers.telegram.enable = true;
providers.telegram.botTokenFile = "/run/agenix/telegram-prod";
providers.telegram.allowFrom = [ 12345678 ];
@ -555,19 +555,19 @@ let
plugins = [ { source = "github:owner/your-plugin"; } ];
};
in {
# Pinned macOS app (POC: no local app builds, uses nix-clawdbot @ v0.1.0 above).
programs.clawdbot.appPackage =
inputs.nix-clawdbot.packages.${pkgs.system}.clawdbot-app;
programs.clawdbot.documents = ./documents;
programs.clawdbot.instances = {
# Pinned macOS app (POC: no local app builds, uses nix-moltbot @ v0.1.0 above).
programs.moltbot.appPackage =
inputs.nix-moltbot.packages.${pkgs.system}.moltbot-app;
programs.moltbot.documents = ./documents;
programs.moltbot.instances = {
prod = prod;
dev = prod // {
# Dev uses the same pinned macOS app (from nix-clawdbot input),
# Dev uses the same pinned macOS app (from nix-moltbot input),
# but overrides the gateway package to a local checkout.
providers.telegram.botTokenFile = "/run/agenix/telegram-dev";
gatewayPort = 18790;
# Local gateway checkout (path). App stays pinned.
gatewayPath = "/Users/you/code/clawdbot";
gatewayPath = "/Users/you/code/moltbot";
# Local plugin overrides prod if names collide (last wins).
plugins = prod.plugins ++ [
{ source = "path:/Users/you/code/your-plugin"; }
@ -600,22 +600,22 @@ Home Manager auto-excludes `git` when `programs.git.enable = true`.
Drop built-in tools that you already install elsewhere:
```nix
programs.clawdbot.excludeTools = [ "git" "jq" "ripgrep" ];
programs.moltbot.excludeTools = [ "git" "jq" "ripgrep" ];
```
Or provide a custom list:
```nix
programs.clawdbot.toolNames = [ "nodejs_22" "pnpm_10" "summarize" ];
programs.moltbot.toolNames = [ "nodejs_22" "pnpm_10" "summarize" ];
```
If you override `programs.clawdbot.package`, use `pkgs.clawdbotPackages.withTools { ... }.clawdbot` to apply these lists.
If you override `programs.moltbot.package`, use `pkgs.moltbotPackages.withTools { ... }.moltbot` to apply these lists.
---
## Packaging & Updates
**Goal:** `nix-clawdbot` is a great Nix package. Automation, promotion, and fleet rollout live elsewhere.
**Goal:** `nix-moltbot` is a great Nix package. Automation, promotion, and fleet rollout live elsewhere.
### Stable only (for now)
@ -624,25 +624,25 @@ We ship a single pinned upstream commit:
Outputs:
```
.#clawdbot
.#clawdbot-gateway
.#moltbot
.#moltbot-gateway
```
Pin lives in:
- `nix/sources/clawdbot-source.nix`
- `nix/sources/moltbot-source.nix`
### Responsibilities (who owns what)
- **clawdbot (upstream)**: source code, tests, releases.
- **nix-clawdbot**: Nix packaging, pins, CI builds.
- **clawdinators**: update cadence, smoke tests, promotion, rollout/rollback.
- **moltbot (upstream)**: source code, tests, releases.
- **nix-moltbot**: Nix packaging, pins, CI builds.
- **moltinators**: update cadence, smoke tests, promotion, rollout/rollback.
### Automated pipeline (no manual steps)
1) **clawdinators updater** proposes a new stable pin.
1) **moltinators updater** proposes a new stable pin.
2) **Garnix** builds the package on Linux + macOS and runs `pnpm test` on Linux.
It also validates the generated Nix config options against the upstream schema.
3) **clawdinators smoke test** runs against real Discord in `#clawdinators-test`.
3) **moltinators smoke test** runs against real Discord in `#moltinators-test`.
4) If green → promote to stable.
5) If red → keep current stable pin.
@ -654,22 +654,22 @@ Pin lives in:
```bash
# macOS: check service
launchctl print gui/$UID/com.steipete.clawdbot.gateway | grep state
launchctl print gui/$UID/com.steipete.moltbot.gateway | grep state
# macOS: view logs
tail -50 /tmp/clawdbot/clawdbot-gateway.log
tail -50 /tmp/moltbot/moltbot-gateway.log
# macOS: restart
launchctl kickstart -k gui/$UID/com.steipete.clawdbot.gateway
launchctl kickstart -k gui/$UID/com.steipete.moltbot.gateway
# Linux: check service
systemctl --user status clawdbot-gateway
systemctl --user status moltbot-gateway
# Linux: view logs
journalctl --user -u clawdbot-gateway -f
journalctl --user -u moltbot-gateway -f
# Linux: restart
systemctl --user restart clawdbot-gateway
systemctl --user restart moltbot-gateway
# Rollback
home-manager generations # list
@ -680,10 +680,10 @@ home-manager switch --rollback # revert
| Package | Contents |
| --- | --- |
| `clawdbot` (default) | macOS: gateway + app + tools · Linux: gateway + tools (headless) |
| `clawdbot-gateway` | Gateway CLI only |
| `clawdbot-tools` | Toolchain bundle (gateway helpers + CLIs) |
| `clawdbot-app` | macOS app only |
| `moltbot` (default) | macOS: gateway + app + tools · Linux: gateway + tools (headless) |
| `moltbot-gateway` | Gateway CLI only |
| `moltbot-tools` | Toolchain bundle (gateway helpers + CLIs) |
| `moltbot-app` | macOS app only |
### What we manage vs what you manage
@ -717,7 +717,7 @@ home-manager switch --rollback # revert
## Philosophy
The Zen of ~~Python~~ Clawdbot, ~~by~~ shamelessly stolen from Tim Peters
The Zen of ~~Python~~ Moltbot, ~~by~~ shamelessly stolen from Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
@ -743,7 +743,7 @@ Namespaces are one honking great idea -- let's do more of those!
## Upstream
Wraps [Clawdbot](https://github.com/clawdbot/clawdbot) by Peter Steinberger.
Wraps [Moltbot](https://github.com/moltbot/moltbot) by Peter Steinberger.
## License

View File

@ -1,17 +1,17 @@
# Clawdbot Plugin Architecture (Maintainer Memo)
# Moltbot Plugin Architecture (Maintainer Memo)
Purpose: extend Clawdbot capabilities without bloating core; ship tools + skills + config as reproducible units you can pin, test, and roll back. nix-clawdbot shows the contract; Clawdbot core should treat the same interface as first-class, even off-Nix.
Purpose: extend Moltbot capabilities without bloating core; ship tools + skills + config as reproducible units you can pin, test, and roll back. nix-moltbot shows the contract; Moltbot core should treat the same interface as first-class, even off-Nix.
## What a Plugin Is (and is not)
- **Is:** bundle of binaries/CLIs, skills that teach the agent to use them, optional config/env requirements.
- **Not:** new transports/providers; model plumbing; secrets baked in; inline scripts or ad-hoc package-manager installs; a place for random config outside its scope.
- Why not skills-only: skills without binaries can hallucinate capability. Plugins ground skills in real tools and deliver versioned, reproducible functionality.
## Interface Contract (reference implementation: nix-clawdbot)
Every plugin artifact exposes the same fields (flake output `clawdbotPlugin` today, but the shape is host-agnostic):
## Interface Contract (reference implementation: nix-moltbot)
Every plugin artifact exposes the same fields (flake output `moltbotPlugin` today, but the shape is host-agnostic):
```nix
clawdbotPlugin = {
moltbotPlugin = {
name = "summarize"; # unique; last-wins on collision
skills = [ ./skills/summarize ]; # dirs containing SKILL.md
packages = [ pkgs.summarize-cli ]; # binaries placed on PATH
@ -52,10 +52,10 @@ plugins = [
- Invariant: providing `settings` requires at least one `stateDir`.
## Dev workflow (fast iteration)
- Worktree: build and test plugins outside the core repo; point Clawdbot at a local path source (e.g., `source = "path:/Users/you/code/my-plugin"`).
- Worktree: build and test plugins outside the core repo; point Moltbot at a local path source (e.g., `source = "path:/Users/you/code/my-plugin"`).
- Rebuild loop: change plugin → `home-manager switch` (or host-equivalent) → gateway restarts with new PATH/skills/config; no manual copying.
- Name collisions: use the same plugin `name` to override a pinned version (last entry wins); keep unique names otherwise to avoid surprise overrides.
- Skills placement: skills land under `~/.clawdbot*/workspace/skills/<plugin>/...` so you can inspect quickly; delete the workspace to fully reset cached skills.
- Skills placement: skills land under `~/.moltbot*/workspace/skills/<plugin>/...` so you can inspect quickly; delete the workspace to fully reset cached skills.
- Env guardrails: required env vars must point to files (non-empty) or the activation fails—supply temp files during dev to exercise the checks.
- Settings JSON: inspect the rendered `config.json` in the first `stateDir` to confirm schema and defaults before committing.
@ -65,15 +65,15 @@ plugins = [
Enable (host side):
```nix
programs.clawdbot.instances.default.plugins = [
{ source = "github:clawdbot/nix-steipete-tools?dir=tools/summarize"; }
programs.moltbot.instances.default.plugins = [
{ source = "github:moltbot/nix-steipete-tools?dir=tools/summarize"; }
];
```
Plugin contract (inside the plugin repo):
```nix
clawdbotPlugin = {
moltbotPlugin = {
name = "summarize";
skills = [ ./skills/summarize ];
packages = [ self.packages.${system}.summarize-cli ];
@ -85,7 +85,7 @@ clawdbotPlugin = {
Enable (host side):
```nix
programs.clawdbot.instances.default.plugins = [
programs.moltbot.instances.default.plugins = [
{
source = "github:joshp123/xuezh";
config = {
@ -117,7 +117,7 @@ programs.clawdbot.instances.default.plugins = [
Plugin contract (inside `xuezh`):
```nix
clawdbotPlugin = {
moltbotPlugin = {
name = "xuezh";
skills = [ ./skills/xuezh ];
packages = [ self.packages.${system}.default ];
@ -132,7 +132,7 @@ Host behavior: creates `~/.config/xuezh/config.json` from `settings`; exports bo
## First-Party Plugin Set (current)
- summarize, peekaboo, oracle, poltergeist, sag, camsnap, gogcli, bird, sonoscli, imsg.
- Each follows the same contract: packages + skills; env/state declared via `needs`; enabled via config toggle; sources pinned (see nix-clawdbot firstParty mapping).
- Each follows the same contract: packages + skills; env/state declared via `needs`; enabled via config toggle; sources pinned (see nix-moltbot firstParty mapping).
## Authoring Rules
- Keep CLIs configurable via env; honor XDG paths; no inline scripts.
@ -144,6 +144,6 @@ Host behavior: creates `~/.config/xuezh/config.json` from `settings`; exports bo
## Why this approach
- Capability grounding: skills map to real tools, not hypothetical ones.
- Reproducibility: versioned bundle of tool + skill + config schema; easy rollback.
- Clean core: main Clawdbot stays transport/model-focused; plugins carry integrations.
- Clean core: main Moltbot stays transport/model-focused; plugins carry integrations.
- Operational sanity: one toggle wires tools, env, skills; failure is explicit and early.
- Portability: contract is host-agnostic; Nix just enforces determinism and zero drift.

View File

@ -1,4 +1,4 @@
# RFC: Declarative Clawdbot as a Nix Package (nix-clawdbot)
# RFC: Declarative Moltbot as a Nix Package (nix-moltbot)
- Date: 2026-01-02
- Status: Implementing
@ -6,7 +6,7 @@
## 1) Narrative: what we are building and why
Clawdbot is powerful but hard to install and configure for new users, especially those who do not want to learn Nix internals. We need a batteriesincluded, obvious, and safe path to get a working Clawdbot instance with minimal friction. This RFC proposes a dedicated public repo, `nix-clawdbot`, that packages Clawdbot for Nix and provides a declarative, userfriendly configuration layer with strong defaults and an agentfirst onboarding flow.
Moltbot is powerful but hard to install and configure for new users, especially those who do not want to learn Nix internals. We need a batteriesincluded, obvious, and safe path to get a working Moltbot instance with minimal friction. This RFC proposes a dedicated public repo, `nix-moltbot`, that packages Moltbot for Nix and provides a declarative, userfriendly configuration layer with strong defaults and an agentfirst onboarding flow.
The goal is a **fully declarative bootstrap**: users provide a small set of inputs (token path + allowlist), and the setup is deterministic and repeatable.
@ -22,7 +22,7 @@ The goal is a **fully declarative bootstrap**: users provide a small set of inpu
## 1.2) Scope boundaries (avoid confusion)
This RFC is only about:
- The public `nix-clawdbot` repo (package + module + docs).
- The public `nix-moltbot` repo (package + module + docs).
- A generic, enduser Nix setup that lives outside any personal config repo.
This RFC is explicitly **not** about:
@ -32,7 +32,7 @@ This RFC is explicitly **not** about:
## 2) Goals / Nongoals
Goals:
- Provide a Nix package for Clawdbot and a Home Manager module with batteriesincluded defaults.
- Provide a Nix package for Moltbot and a Home Manager module with batteriesincluded defaults.
- Provide a macOS app bundle package aligned to the gateway version.
- Make configuration technically light with explicit options and guardrails.
- Telegramfirst configuration and defaults.
@ -40,17 +40,17 @@ Goals:
- New user can get a working bot in 10 minutes without understanding Nix internals.
Nongoals:
- Rewriting Clawdbot core functionality.
- Rewriting Moltbot core functionality.
- Supporting nonNix install paths in this repo.
- Shipping a hosted SaaS or paid hosting.
- Replacing upstream Clawdbot docs.
- Replacing upstream Moltbot docs.
- Crossplatform support (Linux/Windows) in v1.
- CI automation in v1.
## 3) System overview
`nix-clawdbot` is a public repo that provides (macOSonly in v1, no CI in v1):
- A Nix package derivation for the Clawdbot gateway.
`nix-moltbot` is a public repo that provides (macOSonly in v1, no CI in v1):
- A Nix package derivation for the Moltbot gateway.
- A Nix package for the macOS app bundle (DMG).
- A Home Manager module for userlevel config and service wiring.
- A nixdarwin module for macOS users (optional, thin wrapper over HM).
@ -59,20 +59,20 @@ Nongoals:
## 4) Components and responsibilities
- **Package derivation**: builds Clawdbot gateway from a pinned source.
- **App bundle**: installs Clawdbot.app from a pinned DMG matching the gateway version.
- **Home Manager module**: declarative config, writes `~/.clawdbot/clawdbot.json`, manages services.
- **Package derivation**: builds Moltbot gateway from a pinned source.
- **App bundle**: installs Moltbot.app from a pinned DMG matching the gateway version.
- **Home Manager module**: declarative config, writes `~/.moltbot/moltbot.json`, manages services.
- **Flake outputs**:
- `packages.<system>.clawdbot` (default batteriesincluded bundle)
- `packages.<system>.clawdbot-gateway`
- `packages.<system>.clawdbot-app`
- `packages.<system>.clawdbot-tools`
- `homeManagerModules.clawdbot`
- `darwinModules.clawdbot` (if needed)
- `packages.<system>.moltbot` (default batteriesincluded bundle)
- `packages.<system>.moltbot-gateway`
- `packages.<system>.moltbot-app`
- `packages.<system>.moltbot-tools`
- `homeManagerModules.moltbot`
- `darwinModules.moltbot` (if needed)
## 5) Configuration model (public contract)
The Home Manager module is the public contract. It must expose a small, explicit option set (enable, token path, allowlist) and render a deterministic `~/.clawdbot/clawdbot.json`.
The Home Manager module is the public contract. It must expose a small, explicit option set (enable, token path, allowlist) and render a deterministic `~/.moltbot/moltbot.json`.
The design constraint: users should not have to write arbitrary JSON. The module is the supported configuration surface for v1.
@ -92,7 +92,7 @@ The README is the only supported onboarding path. It must include:
## 8) Backing tools (batteriesincluded)
- Base and extended toolchains are installed via Nix by default.
- Tools correspond to upstream Clawdbot skill installers (brew/go/node/uv) mapped into nixpkgs where possible.
- Tools correspond to upstream Moltbot skill installers (brew/go/node/uv) mapped into nixpkgs where possible.
## 9) Compatibility guarantees
@ -105,7 +105,7 @@ The README is the only supported onboarding path. It must include:
We will maintain two distinct setups:
- **Prod (stable)**
- Uses `nix-clawdbot` batteriesincluded package.
- Uses `nix-moltbot` batteriesincluded package.
- Pinned to released tags.
- No source builds.
- Launchd managed by Nix.
@ -123,8 +123,8 @@ No changes to personal `nixos-config` are made in this repo; this is a plan only
This RFC is complete when:
- The repo is public with a clear README and agentfirst guide.
- Telegramfirst quickstart works on macOS with a real bot token.
- `nix run .#clawdbot` installs gateway + app + tools.
- Launchd uses `com.steipete.clawdbot.gateway` and logs to `/tmp/clawdbot/clawdbot-gateway.log`.
- `nix run .#moltbot` installs gateway + app + tools.
- Launchd uses `com.steipete.moltbot.gateway` and logs to `/tmp/moltbot/moltbot-gateway.log`.
- App runs in attachonly mode (does not spawn its own gateway).
- Smoke test: user sends a Telegram message in an allowlisted chat and receives a response.

View File

@ -1,8 +1,8 @@
# RFC: Clawdbot Plugin System — The Golden Path
# RFC: Moltbot Plugin System — The Golden Path
- Date: 2026-01-11
- Status: Draft
- Audience: Peter (clawdbot maintainer), nix-clawdbot maintainers
- Audience: Peter (moltbot maintainer), nix-moltbot maintainers
## Goals
@ -10,7 +10,7 @@
**Our goals:** Properly bundled tools with reproducible builds, single-install experience, it Just Works.
**This RFC argues:** The nix-clawdbot plugin model achieves both. It should become the golden path for extending clawdbot.
**This RFC argues:** The nix-moltbot plugin model achieves both. It should become the golden path for extending moltbot.
---
@ -18,8 +18,8 @@
Voice-call landed in core (+8K LOC). It works, but:
- Core now has Twilio/Telnyx deps even if you don't use voice-call
- Changes to voice-call require clawdbot releases
- Testing voice-call means testing all of clawdbot
- Changes to voice-call require moltbot releases
- Testing voice-call means testing all of moltbot
- Contributors need to understand the whole codebase
This pattern doesn't scale. Every new capability bloats core.
@ -35,7 +35,7 @@ Skills without tools are hallucinations waiting to happen.
---
## The nix-clawdbot Model: Bundle Everything
## The nix-moltbot Model: Bundle Everything
A plugin is **just a GitHub repo** that self-declares its contract:
@ -60,7 +60,7 @@ One install gives you:
### Real Example: xuezh (Chinese learning)
```nix
clawdbotPlugin = {
moltbotPlugin = {
name = "xuezh";
skills = [ ./skills/xuezh ];
packages = [ self.packages.${system}.default ];
@ -85,7 +85,7 @@ clawdbotPlugin = {
### Real Example: gohome (home automation)
```nix
clawdbotPlugin = {
moltbotPlugin = {
name = "gohome";
skills = [ ./skills/gohome ];
packages = [ self.packages.${system}.default ];
@ -114,7 +114,7 @@ MEDIA:http://gohome:8080/roborock/map.png?labels=names
### Real Example: padel (court booking)
```nix
clawdbotPlugin = {
moltbotPlugin = {
name = "padel";
skills = [ ./skills/padel ];
packages = [ self.packages.${system}.default ];
@ -152,7 +152,7 @@ Bundled plugin is "here's the tool, its docs, and everything it needs."
|--------|---------|--------|
| Core LOC | +8K per feature | Zero |
| Dependencies | Everyone gets them | Only if you install |
| Release cycle | Tied to clawdbot | Independent |
| Release cycle | Tied to moltbot | Independent |
| Testing | Test everything | Test plugin only |
| Contributor barrier | Understand whole codebase | Understand plugin only |
@ -195,23 +195,23 @@ voicecall status --call-id abc123 # Check for responses
## The Proposal: Make This the Golden Path
### What clawdbot core should do
### What moltbot core should do
1. **Document the plugin contract**`plugin.json` manifest schema (name, skills, bin, needs)
2. **Add discovery** — scan `~/.clawdbot/extensions/` at startup
2. **Add discovery** — scan `~/.moltbot/extensions/` at startup
3. **Validate env** — fail fast if `requiredEnv` missing
4. **Create state dirs** — from manifest
5. **Add `clawdbot plugins` CLI** — list, enable, disable, info
5. **Add `moltbot plugins` CLI** — list, enable, disable, info
That's it. No dynamic code loading, no TypeBox registration, no RPC handlers. Just: find plugins, validate their needs, put binaries on PATH, copy skills to workspace.
### How nix-clawdbot fits in
### How nix-moltbot fits in
nix-clawdbot is a **plugin installer** that wires plugins into clawdbot's plugin system:
nix-moltbot is a **plugin installer** that wires plugins into moltbot's plugin system:
```nix
# User's flake.nix
programs.clawdbot.plugins = [
programs.moltbot.plugins = [
# Remote: point at GitHub repo
{ source = "github:joshp123/xuezh"; }
{ source = "github:joshp123/padel-cli"; }
@ -220,35 +220,35 @@ programs.clawdbot.plugins = [
{ source = "path:/Users/josh/code/my-plugin"; }
];
# Or enable first-party plugins (pinned in nix-clawdbot):
programs.clawdbot.firstParty.summarize.enable = true;
programs.clawdbot.firstParty.oracle.enable = true;
# Or enable first-party plugins (pinned in nix-moltbot):
programs.moltbot.firstParty.summarize.enable = true;
programs.moltbot.firstParty.oracle.enable = true;
```
**Same contract, multiple sources:**
- `github:owner/repo` — pull from GitHub, pin to commit
- `path:/local/dir` — local checkout for dev iteration
- First-party toggles — curated plugins pinned in nix-clawdbot
- First-party toggles — curated plugins pinned in nix-moltbot
At activation time, nix-clawdbot:
At activation time, nix-moltbot:
1. Resolves flake sources (remote or local) → builds binaries
2. Validates `requiredEnv` (fails if missing)
3. Creates state dirs
4. Installs plugins to `~/.clawdbot/extensions/<plugin>/`
4. Installs plugins to `~/.moltbot/extensions/<plugin>/`
5. Writes `plugin.json` manifest for each
6. Symlinks skills to workspace
7. Adds binaries to PATH
**clawdbot core sees all plugins** — it scans `~/.clawdbot/extensions/`, reads manifests, knows what's installed. The difference is nix-clawdbot does the install + validation at build time (deterministic, fail-fast), while non-Nix users do it manually or via npm.
**moltbot core sees all plugins** — it scans `~/.moltbot/extensions/`, reads manifests, knows what's installed. The difference is nix-moltbot does the install + validation at build time (deterministic, fail-fast), while non-Nix users do it manually or via npm.
**Same plugin system, different installers:**
- Nix users: nix-clawdbot installs plugins declaratively
- Non-Nix users: `clawdbot plugins install` or manual setup
- clawdbot core: sees the same `~/.clawdbot/extensions/` structure either way
- Nix users: nix-moltbot installs plugins declaratively
- Non-Nix users: `moltbot plugins install` or manual setup
- moltbot core: sees the same `~/.moltbot/extensions/` structure either way
**Local dev workflow:** Point at a local path, change code, rebuild, gateway picks up changes. No push/pull cycle. Same contract, local iteration. For non-Nix: symlink your plugin dir into `~/.clawdbot/extensions/`.
**Local dev workflow:** Point at a local path, change code, rebuild, gateway picks up changes. No push/pull cycle. Same contract, local iteration. For non-Nix: symlink your plugin dir into `~/.moltbot/extensions/`.
### What nix-clawdbot provides (golden path)
### What nix-moltbot provides (golden path)
- **Reproducible builds** — binary built from source, same everywhere
- **Version pinning** — plugin source locked to exact commit
@ -258,7 +258,7 @@ At activation time, nix-clawdbot:
### What npm provides (fallback)
- `clawdbot plugins install @clawdbot/voice-call` — npm install to extensions dir
- `moltbot plugins install @moltbot/voice-call` — npm install to extensions dir
- Manual env var setup
- Manual version management
- No reproducibility guarantees
@ -280,12 +280,12 @@ voicecall expose --mode funnel|serve|off
As a plugin:
```nix
clawdbotPlugin = {
moltbotPlugin = {
name = "voice-call";
skills = [ ./skills/voice-call ];
packages = [ self.packages.${system}.default ];
needs = {
stateDirs = [ ".config/clawdbot-voice-call" ];
stateDirs = [ ".config/moltbot-voice-call" ];
requiredEnv = [ "TWILIO_ACCOUNT_SID" "TWILIO_AUTH_TOKEN" ];
};
};
@ -294,7 +294,7 @@ clawdbotPlugin = {
Install wires up Twilio creds. Binary handles webhook server. Skill teaches agent the CLI. Done.
**Migration path:**
1. Create `@clawdbot/voice-call` repo
1. Create `@moltbot/voice-call` repo
2. Move code from core
3. Add plugin contract
4. Remove from core
@ -304,7 +304,7 @@ Install wires up Twilio creds. Binary handles webhook server. Skill teaches agen
## The Plugin Ecosystem Vision
**First-party plugins** already exist — see [nix-steipete-tools](https://github.com/clawdbot/nix-steipete-tools/tree/main/tools):
**First-party plugins** already exist — see [nix-steipete-tools](https://github.com/moltbot/nix-steipete-tools/tree/main/tools):
- `summarize` — YouTube/article summarization
- `oracle` — second-model review
- `peekaboo` — screenshot capture
@ -316,13 +316,13 @@ Install wires up Twilio creds. Binary handles webhook server. Skill teaches agen
- `imsg` — iMessage integration
- `gogcli` — Google Calendar
All follow the same contract. All pinned in nix-clawdbot. Enable with one line:
All follow the same contract. All pinned in nix-moltbot. Enable with one line:
```nix
programs.clawdbot.firstParty.summarize.enable = true;
programs.moltbot.firstParty.summarize.enable = true;
```
**Community plugins** (anyone can ship):
- Just a GitHub repo with `flake.nix` + `clawdbotPlugin`
- Just a GitHub repo with `flake.nix` + `moltbotPlugin`
- No registry, no approval process
- User points at repo, wires secrets, it works
@ -346,10 +346,10 @@ programs.clawdbot.firstParty.summarize.enable = true;
**The pitch to Peter:**
Your voice-call is great. But it shouldn't live in core forever. The nix-clawdbot plugin model lets you:
Your voice-call is great. But it shouldn't live in core forever. The nix-moltbot plugin model lets you:
- Ship it independently (faster iteration)
- Keep core lean (easier maintenance)
- Let community extend clawdbot (ecosystem growth)
- Let community extend moltbot (ecosystem growth)
- Guarantee it works when installed (fail-fast validation)
All you need to add to core is plugin discovery + env validation. We already have the contract, the tooling, and real plugins in production.
@ -359,28 +359,28 @@ All you need to add to core is plugin discovery + env validation. We already hav
## Open Questions
1. **Manifest format:**
- Nix users: `clawdbotPlugin` in `flake.nix` (already works)
- Nix users: `moltbotPlugin` in `flake.nix` (already works)
- Non-Nix users: `plugin.json` in plugin directory
- **Suggested:** clawdbot core defines `plugin.json` schema. Same fields as `clawdbotPlugin`:
- **Suggested:** moltbot core defines `plugin.json` schema. Same fields as `moltbotPlugin`:
```json
{
"name": "voice-call",
"skills": ["./skills/voice-call"],
"bin": { "voicecall": "./bin/voicecall" },
"needs": {
"stateDirs": [".config/clawdbot-voice-call"],
"stateDirs": [".config/moltbot-voice-call"],
"requiredEnv": ["TWILIO_ACCOUNT_SID", "TWILIO_AUTH_TOKEN"]
}
}
```
2. **Discovery paths:**
- **Suggested:** `~/.clawdbot/extensions/<plugin>/` for user-installed, `.clawdbot/extensions/<plugin>/` for project-local
- clawdbot core scans both paths at startup
- nix-clawdbot installs to the same paths — same structure, different installer
- **Suggested:** `~/.moltbot/extensions/<plugin>/` for user-installed, `.moltbot/extensions/<plugin>/` for project-local
- moltbot core scans both paths at startup
- nix-moltbot installs to the same paths — same structure, different installer
3. **First-party plugins for non-Nix:**
- **Suggested:** `@clawdbot/` npm scope, but don't invest heavily. Point people to Nix.
- **Suggested:** `@moltbot/` npm scope, but don't invest heavily. Point people to Nix.
4. **Voice-call extraction:** Want to do this now, or later?

View File

@ -3,5 +3,5 @@
This plugin is intentionally tiny.
Knobs
- CLAWDBOT_USER (optional): name to greet
- MOLTBOT_USER (optional): name to greet

View File

@ -1,5 +1,5 @@
{
description = "Hello-world Clawdbot plugin";
description = "Hello-world Moltbot plugin";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
@ -22,7 +22,7 @@
drv = self.packages.${system}.default;
};
clawdbotPlugin = {
moltbotPlugin = {
name = "hello-world";
skills = [ ./skills/hello-world ];
packages = [ self.packages.${system}.default ];

View File

@ -1,3 +1,3 @@
module github.com/acme/hello-world-clawdbot
module github.com/acme/hello-world-moltbot
go 1.22

View File

@ -6,7 +6,7 @@ import (
)
func main() {
name := os.Getenv("CLAWDBOT_USER")
name := os.Getenv("MOLTBOT_USER")
if name == "" {
name = "human"
}

10
flake.lock generated
View File

@ -43,15 +43,15 @@
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1768673601,
"narHash": "sha256-n5+aU505rTI1sJGd3PDhfvJS00lLjiARckqjLxdG+XA=",
"owner": "clawdbot",
"lastModified": 1769518314,
"narHash": "sha256-r48vscCGwB4ujzNq7tnrvO6FpStbKr+45ap2m2skO4Q=",
"owner": "moltbot",
"repo": "nix-steipete-tools",
"rev": "1ab855984e2581e35a76d57cbb97abf0693dad3b",
"rev": "9a9b3b97418e3705d325ab9aad5693ac1208c891",
"type": "github"
},
"original": {
"owner": "clawdbot",
"owner": "moltbot",
"repo": "nix-steipete-tools",
"type": "github"
}

View File

@ -1,5 +1,5 @@
{
description = "nix-clawdbot: declarative Clawdbot packaging";
description = "nix-moltbot: declarative Moltbot packaging";
nixConfig = {
extra-substituters = [ "https://cache.garnix.io" ];
@ -13,13 +13,13 @@
flake-utils.url = "github:numtide/flake-utils";
home-manager.url = "github:nix-community/home-manager";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
nix-steipete-tools.url = "github:clawdbot/nix-steipete-tools";
nix-steipete-tools.url = "github:moltbot/nix-steipete-tools";
};
outputs = { self, nixpkgs, flake-utils, home-manager, nix-steipete-tools }:
let
overlay = import ./nix/overlay.nix;
sourceInfoStable = import ./nix/sources/clawdbot-source.nix;
sourceInfoStable = import ./nix/sources/moltbot-source.nix;
systems = [ "x86_64-linux" "aarch64-darwin" ];
in
flake-utils.lib.eachSystem systems (system:
@ -39,20 +39,20 @@
in
{
packages = packageSetStable // {
default = packageSetStable.clawdbot;
default = packageSetStable.moltbot;
};
apps = {
clawdbot = flake-utils.lib.mkApp { drv = packageSetStable.clawdbot-gateway; };
moltbot = flake-utils.lib.mkApp { drv = packageSetStable.moltbot-gateway; };
};
checks = {
gateway = packageSetStable.clawdbot-gateway;
gateway = packageSetStable.moltbot-gateway;
} // (if pkgs.stdenv.hostPlatform.isLinux then {
gateway-tests = pkgs.callPackage ./nix/checks/clawdbot-gateway-tests.nix {
gateway-tests = pkgs.callPackage ./nix/checks/moltbot-gateway-tests.nix {
sourceInfo = sourceInfoStable;
};
config-options = pkgs.callPackage ./nix/checks/clawdbot-config-options.nix {
config-options = pkgs.callPackage ./nix/checks/moltbot-config-options.nix {
sourceInfo = sourceInfoStable;
};
} else {});
@ -67,7 +67,7 @@
}
) // {
overlays.default = overlay;
homeManagerModules.clawdbot = import ./nix/modules/home-manager/clawdbot.nix;
darwinModules.clawdbot = import ./nix/modules/darwin/clawdbot.nix;
homeManagerModules.moltbot = import ./nix/modules/home-manager/moltbot.nix;
darwinModules.moltbot = import ./nix/modules/darwin/moltbot.nix;
};
}

View File

@ -1,12 +1,12 @@
builds:
include:
- "packages.aarch64-darwin.clawdbot"
- "packages.aarch64-darwin.clawdbot-gateway"
- "packages.aarch64-darwin.clawdbot-tools"
- "packages.aarch64-darwin.clawdbot-app"
- "packages.x86_64-linux.clawdbot"
- "packages.x86_64-linux.clawdbot-gateway"
- "packages.x86_64-linux.clawdbot-tools"
- "packages.aarch64-darwin.moltbot"
- "packages.aarch64-darwin.moltbot-gateway"
- "packages.aarch64-darwin.moltbot-tools"
- "packages.aarch64-darwin.moltbot-app"
- "packages.x86_64-linux.moltbot"
- "packages.x86_64-linux.moltbot-gateway"
- "packages.x86_64-linux.moltbot-tools"
- "checks.aarch64-darwin.gateway"
- "checks.x86_64-linux.gateway"
- "checks.x86_64-linux.gateway-tests"

View File

@ -33,7 +33,7 @@ let
in
stdenv.mkDerivation (finalAttrs: {
pname = "clawdbot-config-options";
pname = "moltbot-config-options";
version = "2026.1.8-2";
src = fetchFromGitHub sourceFetch;
@ -73,7 +73,7 @@ stdenv.mkDerivation (finalAttrs: {
REMOVE_PACKAGE_MANAGER_FIELD_SH = "${../scripts/remove-package-manager-field.sh}";
STDENV_SETUP = "${stdenv}/setup";
CONFIG_OPTIONS_GENERATOR = "${../scripts/generate-config-options.ts}";
CONFIG_OPTIONS_GOLDEN = "${../generated/clawdbot-config-options.nix}";
CONFIG_OPTIONS_GOLDEN = "${../generated/moltbot-config-options.nix}";
NODE_ENGINE_CHECK = "${../scripts/check-node-engine.ts}";
};

View File

@ -34,7 +34,7 @@ let
in
stdenv.mkDerivation (finalAttrs: {
pname = "clawdbot-gateway-tests";
pname = "moltbot-gateway-tests";
version = "2026.1.8-2";
src = fetchFromGitHub sourceFetch;

View File

@ -1,4 +1,4 @@
# Generated from upstream Clawdbot schema. DO NOT EDIT.
# Generated from upstream Moltbot schema. DO NOT EDIT.
{ lib }:
let
t = lib.types;

View File

@ -2,6 +2,6 @@
{
config = lib.mkIf (config ? home-manager) {
home-manager.sharedModules = [ ../home-manager/clawdbot.nix ];
home-manager.sharedModules = [ ../home-manager/moltbot.nix ];
};
}

View File

@ -1,36 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage: clawdbot-reload [test|prod|both]
Re-render Clawdbot config via Home Manager (no sudo) and restart gateway(s).
Defaults to: test
EOF
}
instance="${1:-test}"
case "$instance" in
test) labels=("com.steipete.clawdbot.gateway.nix-test") ;;
prod) labels=("com.steipete.clawdbot.gateway.nix") ;;
both) labels=("com.steipete.clawdbot.gateway.nix" "com.steipete.clawdbot.gateway.nix-test") ;;
-h|--help) usage; exit 0 ;;
*) usage; exit 1 ;;
esac
if command -v hm-apply >/dev/null 2>&1; then
hm-apply
elif [[ -n "${CLAWDBOT_RELOAD_HM_CMD:-}" ]]; then
eval "$CLAWDBOT_RELOAD_HM_CMD"
else
echo "[clawdbot-reload] no Home Manager command available." >&2
echo "[clawdbot-reload] install hm-apply or set CLAWDBOT_RELOAD_HM_CMD." >&2
exit 1
fi
for label in "${labels[@]}"; do
/bin/launchctl kickstart -k "gui/$UID/$label"
done

View File

@ -30,14 +30,14 @@ link_agent() {
/bin/launchctl kickstart -k "gui/$UID/$label" 2>/dev/null || true
}
link_agent "$HOME/Library/LaunchAgents/com.steipete.clawdbot.gateway.nix.plist" \
"com.steipete.clawdbot.gateway.nix"
link_agent "$HOME/Library/LaunchAgents/com.steipete.moltbot.gateway.nix.plist" \
"com.steipete.moltbot.gateway.nix"
link_agent "$HOME/Library/LaunchAgents/com.steipete.clawdbot.gateway.nix-test.plist" \
"com.steipete.clawdbot.gateway.nix-test"
link_agent "$HOME/Library/LaunchAgents/com.steipete.moltbot.gateway.nix-test.plist" \
"com.steipete.moltbot.gateway.nix-test"
link_agent "$HOME/Library/LaunchAgents/com.steipete.clawdbot.gateway.prod.plist" \
"com.steipete.clawdbot.gateway.prod"
link_agent "$HOME/Library/LaunchAgents/com.steipete.moltbot.gateway.prod.plist" \
"com.steipete.moltbot.gateway.prod"
link_agent "$HOME/Library/LaunchAgents/com.steipete.clawdbot.gateway.test.plist" \
"com.steipete.clawdbot.gateway.test"
link_agent "$HOME/Library/LaunchAgents/com.steipete.moltbot.gateway.test.plist" \
"com.steipete.moltbot.gateway.test"

View File

@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage: moltbot-reload [test|prod|both]
Re-render Moltbot config via Home Manager (no sudo) and restart gateway(s).
Defaults to: test
EOF
}
instance="${1:-test}"
case "$instance" in
test) labels=("com.steipete.moltbot.gateway.nix-test") ;;
prod) labels=("com.steipete.moltbot.gateway.nix") ;;
both) labels=("com.steipete.moltbot.gateway.nix" "com.steipete.moltbot.gateway.nix-test") ;;
-h|--help) usage; exit 0 ;;
*) usage; exit 1 ;;
esac
if command -v hm-apply >/dev/null 2>&1; then
hm-apply
elif [[ -n "${MOLTBOT_RELOAD_HM_CMD:-}" ]]; then
eval "$MOLTBOT_RELOAD_HM_CMD"
else
echo "[moltbot-reload] no Home Manager command available." >&2
echo "[moltbot-reload] install hm-apply or set MOLTBOT_RELOAD_HM_CMD." >&2
exit 1
fi
for label in "${labels[@]}"; do
/bin/launchctl kickstart -k "gui/$UID/$label"
done

View File

@ -1,7 +1,7 @@
{ config, lib, pkgs, ... }:
let
cfg = config.programs.clawdbot;
cfg = config.programs.moltbot;
homeDir = config.home.homeDirectory;
autoExcludeTools = lib.optionals config.programs.git.enable [ "git" ];
effectiveExcludeTools = lib.unique (cfg.excludeTools ++ autoExcludeTools);
@ -12,11 +12,11 @@ let
toolOverridesEnabled = cfg.toolNames != null || effectiveExcludeTools != [];
toolSets = import ../../tools/extended.nix ({ inherit pkgs; } // toolOverrides);
defaultPackage =
if toolOverridesEnabled && cfg.package == pkgs.clawdbot
then (pkgs.clawdbotPackages.withTools toolOverrides).clawdbot
if toolOverridesEnabled && cfg.package == pkgs.moltbot
then (pkgs.moltbotPackages.withTools toolOverrides).moltbot
else cfg.package;
appPackage = if cfg.appPackage != null then cfg.appPackage else defaultPackage;
generatedConfigOptions = import ../../generated/clawdbot-config-options.nix { lib = lib; };
generatedConfigOptions = import ../../generated/moltbot-config-options.nix { lib = lib; };
mkBaseConfig = workspaceDir: inst: {
gateway = { mode = "local"; };
@ -57,7 +57,7 @@ let
stepieteRev = "e4e2cac265de35175015cf1ae836b0b30dddd7b7";
stepieteNarHash = "sha256-L8bKt5rK78dFP3ZoP1Oi1SSAforXVHZDsSiDO+NsvEE=";
stepiete = tool:
"github:clawdbot/nix-steipete-tools?dir=tools/${tool}&rev=${stepieteRev}&narHash=${stepieteNarHash}";
"github:moltbot/nix-steipete-tools?dir=tools/${tool}&rev=${stepieteRev}&narHash=${stepieteNarHash}";
in {
summarize = stepiete "summarize";
peekaboo = stepiete "peekaboo";
@ -82,53 +82,53 @@ let
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Enable this Clawdbot instance.";
description = "Enable this Moltbot instance.";
};
package = lib.mkOption {
type = lib.types.package;
default = defaultPackage;
description = "Clawdbot batteries-included package.";
description = "Moltbot batteries-included package.";
};
stateDir = lib.mkOption {
type = lib.types.str;
default = if name == "default"
then "${homeDir}/.clawdbot"
else "${homeDir}/.clawdbot-${name}";
description = "State directory for this Clawdbot instance (logs, sessions, config).";
then "${homeDir}/.moltbot"
else "${homeDir}/.moltbot-${name}";
description = "State directory for this Moltbot instance (logs, sessions, config).";
};
workspaceDir = lib.mkOption {
type = lib.types.str;
default = "${config.stateDir}/workspace";
description = "Workspace directory for this Clawdbot instance.";
description = "Workspace directory for this Moltbot instance.";
};
configPath = lib.mkOption {
type = lib.types.str;
default = "${config.stateDir}/clawdbot.json";
description = "Path to generated Clawdbot config JSON.";
default = "${config.stateDir}/moltbot.json";
description = "Path to generated Moltbot config JSON.";
};
logPath = lib.mkOption {
type = lib.types.str;
default = if name == "default"
then "/tmp/clawdbot/clawdbot-gateway.log"
else "/tmp/clawdbot/clawdbot-gateway-${name}.log";
description = "Log path for this Clawdbot gateway instance.";
then "/tmp/moltbot/moltbot-gateway.log"
else "/tmp/moltbot/moltbot-gateway-${name}.log";
description = "Log path for this Moltbot gateway instance.";
};
gatewayPort = lib.mkOption {
type = lib.types.int;
default = 18789;
description = "Gateway port used by the Clawdbot desktop app.";
description = "Gateway port used by the Moltbot desktop app.";
};
gatewayPath = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Local path to Clawdbot gateway source (dev only).";
description = "Local path to Moltbot gateway source (dev only).";
};
gatewayPnpmDepsHash = lib.mkOption {
@ -227,41 +227,41 @@ let
launchd.enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Run Clawdbot gateway via launchd (macOS).";
description = "Run Moltbot gateway via launchd (macOS).";
};
launchd.label = lib.mkOption {
type = lib.types.str;
default = if name == "default"
then "com.steipete.clawdbot.gateway"
else "com.steipete.clawdbot.gateway.${name}";
then "com.steipete.moltbot.gateway"
else "com.steipete.moltbot.gateway.${name}";
description = "launchd label for this instance.";
};
systemd.enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Run Clawdbot gateway via systemd user service (Linux).";
description = "Run Moltbot gateway via systemd user service (Linux).";
};
systemd.unitName = lib.mkOption {
type = lib.types.str;
default = if name == "default"
then "clawdbot-gateway"
else "clawdbot-gateway-${name}";
then "moltbot-gateway"
else "moltbot-gateway-${name}";
description = "systemd user service unit name for this instance.";
};
app.install.enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Install Clawdbot.app for this instance.";
description = "Install Moltbot.app for this instance.";
};
app.install.path = lib.mkOption {
type = lib.types.str;
default = "${homeDir}/Applications/Clawdbot.app";
description = "Destination path for this instance's Clawdbot.app bundle.";
default = "${homeDir}/Applications/Moltbot.app";
description = "Destination path for this instance's Moltbot.app bundle.";
};
appDefaults = {
@ -281,13 +281,13 @@ let
configOverrides = lib.mkOption {
type = lib.types.attrs;
default = {};
description = "Additional Clawdbot config to merge into the generated JSON.";
description = "Additional Moltbot config to merge into the generated JSON.";
};
config = lib.mkOption {
type = lib.types.submodule { options = generatedConfigOptions; };
default = {};
description = "Upstream Clawdbot config (generated from schema).";
description = "Upstream Moltbot config (generated from schema).";
};
};
};
@ -297,8 +297,8 @@ let
package = cfg.package;
stateDir = cfg.stateDir;
workspaceDir = cfg.workspaceDir;
configPath = "${cfg.stateDir}/clawdbot.json";
logPath = "/tmp/clawdbot/clawdbot-gateway.log";
configPath = "${cfg.stateDir}/moltbot.json";
logPath = "/tmp/moltbot/moltbot-gateway.log";
gatewayPort = 18789;
providers = cfg.providers;
routing = cfg.routing;
@ -314,7 +314,7 @@ let
app = {
install = {
enable = false;
path = "${homeDir}/Applications/Clawdbot.app";
path = "${homeDir}/Applications/Moltbot.app";
};
};
};
@ -343,8 +343,8 @@ let
renderSkill = skill:
let
metadataLine =
if skill ? clawdbot && skill.clawdbot != null
then "metadata: ${builtins.toJSON { clawdbot = skill.clawdbot; }}"
if skill ? moltbot && skill.moltbot != null
then "metadata: ${builtins.toJSON { moltbot = skill.moltbot; }}"
else null;
homepageLine =
if skill ? homepage && skill.homepage != null
@ -372,7 +372,7 @@ let
if duplicateNames == [] then [] else [
{
assertion = false;
message = "programs.clawdbot.skills has duplicate names: ${lib.concatStringsSep ", " duplicateNames}";
message = "programs.moltbot.skills has duplicate names: ${lib.concatStringsSep ", " duplicateNames}";
}
];
in
@ -398,7 +398,7 @@ let
name = "${base}/${skill.name}";
value = {
source = builtins.path {
name = "clawdbot-skill-${skill.name}";
name = "moltbot-skill-${skill.name}";
path = source;
};
recursive = true;
@ -420,19 +420,19 @@ let
documentsAssertions = lib.optionals documentsEnabled [
{
assertion = builtins.pathExists cfg.documents;
message = "programs.clawdbot.documents must point to an existing directory.";
message = "programs.moltbot.documents must point to an existing directory.";
}
{
assertion = builtins.pathExists (cfg.documents + "/AGENTS.md");
message = "Missing AGENTS.md in programs.clawdbot.documents.";
message = "Missing AGENTS.md in programs.moltbot.documents.";
}
{
assertion = builtins.pathExists (cfg.documents + "/SOUL.md");
message = "Missing SOUL.md in programs.clawdbot.documents.";
message = "Missing SOUL.md in programs.moltbot.documents.";
}
{
assertion = builtins.pathExists (cfg.documents + "/TOOLS.md");
message = "Missing TOOLS.md in programs.clawdbot.documents.";
message = "Missing TOOLS.md in programs.moltbot.documents.";
}
];
@ -441,7 +441,7 @@ let
let
guardLine = file: ''
if [ -e "${file}" ] && [ ! -L "${file}" ]; then
echo "Clawdbot documents are managed by Nix. Please adopt ${file} into your documents directory and re-run." >&2
echo "Moltbot documents are managed by Nix. Please adopt ${file} into your documents directory and re-run." >&2
exit 1
fi
'';
@ -502,13 +502,13 @@ let
];
reportText = lib.concatStringsSep "\n" reportLines;
in
pkgs.writeText "clawdbot-tools-report.md" reportText
pkgs.writeText "moltbot-tools-report.md" reportText
else
null;
toolsWithReport =
if documentsEnabled then
pkgs.runCommand "clawdbot-tools-with-report.md" {} ''
pkgs.runCommand "moltbot-tools-with-report.md" {} ''
cat ${cfg.documents + "/TOOLS.md"} > $out
echo "" >> $out
cat ${toolsReport} >> $out
@ -537,15 +537,15 @@ let
resolvePlugin = plugin: let
flake = builtins.getFlake plugin.source;
clawdbotPlugin =
if flake ? clawdbotPlugin then flake.clawdbotPlugin
else throw "clawdbotPlugin missing in ${plugin.source}";
needs = clawdbotPlugin.needs or {};
moltbotPlugin =
if flake ? moltbotPlugin then flake.moltbotPlugin
else throw "moltbotPlugin missing in ${plugin.source}";
needs = moltbotPlugin.needs or {};
in {
source = plugin.source;
name = clawdbotPlugin.name or (throw "clawdbotPlugin.name missing in ${plugin.source}");
skills = clawdbotPlugin.skills or [];
packages = clawdbotPlugin.packages or [];
name = moltbotPlugin.name or (throw "moltbotPlugin.name missing in ${plugin.source}");
skills = moltbotPlugin.skills or [];
packages = moltbotPlugin.packages or [];
needs = {
stateDirs = needs.stateDirs or [];
requiredEnv = needs.requiredEnv or [];
@ -567,7 +567,7 @@ let
if duplicates == []
then ordered
else lib.warn
"programs.clawdbot.instances.${instName}: duplicate plugin names detected (${lib.concatStringsSep ", " duplicates}); last entry wins."
"programs.moltbot.instances.${instName}: duplicate plugin names detected (${lib.concatStringsSep ", " duplicates}); last entry wins."
ordered
) enabledInstances;
@ -615,11 +615,11 @@ let
missing = missingFor p;
in {
assertion = missing == [];
message = "programs.clawdbot.instances.${instName}: plugin ${p.name} missing required env: ${lib.concatStringsSep ", " missing}";
message = "programs.moltbot.instances.${instName}: plugin ${p.name} missing required env: ${lib.concatStringsSep ", " missing}";
};
mkConfigAssertion = p: {
assertion = !(configMissingStateDir p);
message = "programs.clawdbot.instances.${instName}: plugin ${p.name} provides settings but declares no stateDirs (needed for config.json).";
message = "programs.moltbot.instances.${instName}: plugin ${p.name} provides settings but declares no stateDirs (needed for config.json).";
};
in
(map mkAssertion plugins) ++ (map mkConfigAssertion plugins)
@ -717,10 +717,10 @@ let
mkInstanceConfig = name: inst: let
gatewayPackage =
if inst.gatewayPath != null then
pkgs.callPackage ../../packages/clawdbot-gateway.nix {
pkgs.callPackage ../../packages/moltbot-gateway.nix {
gatewaySrc = builtins.path {
path = inst.gatewayPath;
name = "clawdbot-gateway-src";
name = "moltbot-gateway-src";
};
pnpmDepsHash = inst.gatewayPnpmDepsHash;
}
@ -733,8 +733,8 @@ let
(lib.recursiveUpdate baseConfig (lib.recursiveUpdate (mkTelegramConfig inst) (mkRoutingConfig inst)))
inst.configOverrides;
configJson = builtins.toJSON mergedConfig;
configFile = pkgs.writeText "clawdbot-${name}.json" configJson;
gatewayWrapper = pkgs.writeShellScriptBin "clawdbot-gateway-${name}" ''
configFile = pkgs.writeText "moltbot-${name}.json" configJson;
gatewayWrapper = pkgs.writeShellScriptBin "moltbot-gateway-${name}" ''
set -euo pipefail
if [ -n "${lib.makeBinPath pluginPackages}" ]; then
@ -756,7 +756,7 @@ let
export ANTHROPIC_API_KEY
fi
exec "${gatewayPackage}/bin/clawdbot" "$@"
exec "${gatewayPackage}/bin/moltbot" "$@"
'';
in {
homeFile = {
@ -774,7 +774,7 @@ let
config = {
Label = inst.launchd.label;
ProgramArguments = [
"${gatewayWrapper}/bin/clawdbot-gateway-${name}"
"${gatewayWrapper}/bin/moltbot-gateway-${name}"
"gateway"
"--port"
"${toString inst.gatewayPort}"
@ -786,15 +786,14 @@ let
StandardErrorPath = inst.logPath;
EnvironmentVariables = {
HOME = homeDir;
MOLTBOT_CONFIG_PATH = inst.configPath;
MOLTBOT_STATE_DIR = inst.stateDir;
MOLTBOT_IMAGE_BACKEND = "sips";
MOLTBOT_NIX_MODE = "1";
CLAWDBOT_CONFIG_PATH = inst.configPath;
CLAWDBOT_STATE_DIR = inst.stateDir;
CLAWDBOT_IMAGE_BACKEND = "sips";
CLAWDBOT_NIX_MODE = "1";
# Backward-compatible env names (gateway still uses CLAWDIS_* in some builds).
CLAWDIS_CONFIG_PATH = inst.configPath;
CLAWDIS_STATE_DIR = inst.stateDir;
CLAWDIS_IMAGE_BACKEND = "sips";
CLAWDIS_NIX_MODE = "1";
};
};
};
@ -803,21 +802,21 @@ let
systemdService = lib.optionalAttrs (pkgs.stdenv.hostPlatform.isLinux && inst.systemd.enable) {
"${inst.systemd.unitName}" = {
Unit = {
Description = "Clawdbot gateway (${name})";
Description = "Moltbot gateway (${name})";
};
Service = {
ExecStart = "${gatewayWrapper}/bin/clawdbot-gateway-${name} gateway --port ${toString inst.gatewayPort}";
ExecStart = "${gatewayWrapper}/bin/moltbot-gateway-${name} gateway --port ${toString inst.gatewayPort}";
WorkingDirectory = inst.stateDir;
Restart = "always";
RestartSec = "1s";
Environment = [
"HOME=${homeDir}"
"MOLTBOT_CONFIG_PATH=${inst.configPath}"
"MOLTBOT_STATE_DIR=${inst.stateDir}"
"MOLTBOT_NIX_MODE=1"
"CLAWDBOT_CONFIG_PATH=${inst.configPath}"
"CLAWDBOT_STATE_DIR=${inst.stateDir}"
"CLAWDBOT_NIX_MODE=1"
"CLAWDIS_CONFIG_PATH=${inst.configPath}"
"CLAWDIS_STATE_DIR=${inst.stateDir}"
"CLAWDIS_NIX_MODE=1"
];
StandardOutput = "append:${inst.logPath}";
StandardError = "append:${inst.logPath}";
@ -838,7 +837,7 @@ let
else {
name = lib.removePrefix "${homeDir}/" inst.app.install.path;
value = {
source = "${appPackage}/Applications/Clawdbot.app";
source = "${appPackage}/Applications/Moltbot.app";
recursive = true;
force = true;
};
@ -859,22 +858,22 @@ let
assertions = lib.flatten (lib.mapAttrsToList (name: inst: [
{
assertion = !inst.providers.telegram.enable || inst.providers.telegram.botTokenFile != "";
message = "programs.clawdbot.instances.${name}.providers.telegram.botTokenFile must be set when Telegram is enabled.";
message = "programs.moltbot.instances.${name}.providers.telegram.botTokenFile must be set when Telegram is enabled.";
}
{
assertion = !inst.providers.telegram.enable || (lib.length inst.providers.telegram.allowFrom > 0);
message = "programs.clawdbot.instances.${name}.providers.telegram.allowFrom must be non-empty when Telegram is enabled.";
message = "programs.moltbot.instances.${name}.providers.telegram.allowFrom must be non-empty when Telegram is enabled.";
}
]) enabledInstances);
in {
options.programs.clawdbot = {
enable = lib.mkEnableOption "Clawdbot (batteries-included)";
options.programs.moltbot = {
enable = lib.mkEnableOption "Moltbot (batteries-included)";
package = lib.mkOption {
type = lib.types.package;
default = pkgs.clawdbot;
description = "Clawdbot batteries-included package.";
default = pkgs.moltbot;
description = "Moltbot batteries-included package.";
};
toolNames = lib.mkOption {
@ -892,25 +891,25 @@ in {
appPackage = lib.mkOption {
type = lib.types.nullOr lib.types.package;
default = null;
description = "Optional Clawdbot app package (defaults to package if unset).";
description = "Optional Moltbot app package (defaults to package if unset).";
};
installApp = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Install Clawdbot.app at the default location.";
description = "Install Moltbot.app at the default location.";
};
stateDir = lib.mkOption {
type = lib.types.str;
default = "${homeDir}/.clawdbot";
description = "State directory for Clawdbot (logs, sessions, config).";
default = "${homeDir}/.moltbot";
description = "State directory for Moltbot (logs, sessions, config).";
};
workspaceDir = lib.mkOption {
type = lib.types.str;
default = "${homeDir}/.clawdbot/workspace";
description = "Workspace directory for Clawdbot agent skills.";
default = "${homeDir}/.moltbot/workspace";
description = "Workspace directory for Moltbot agent skills.";
};
documents = lib.mkOption {
@ -941,10 +940,10 @@ in {
default = "";
description = "Optional skill body (markdown).";
};
clawdbot = lib.mkOption {
moltbot = lib.mkOption {
type = lib.types.nullOr lib.types.attrs;
default = null;
description = "Optional clawdbot metadata for the skill frontmatter.";
description = "Optional moltbot metadata for the skill frontmatter.";
};
mode = lib.mkOption {
type = lib.types.enum [ "symlink" "copy" "inline" ];
@ -1098,19 +1097,19 @@ in {
launchd.enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Run Clawdbot gateway via launchd (macOS).";
description = "Run Moltbot gateway via launchd (macOS).";
};
systemd.enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Run Clawdbot gateway via systemd user service (Linux).";
description = "Run Moltbot gateway via systemd user service (Linux).";
};
instances = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule instanceModule);
default = {};
description = "Named Clawdbot instances (prod/test).";
description = "Named Moltbot instances (prod/test).";
};
exposePluginPackages = lib.mkOption {
@ -1123,14 +1122,14 @@ in {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Install clawdbot-reload helper for no-sudo config refresh + gateway restart.";
description = "Install moltbot-reload helper for no-sudo config refresh + gateway restart.";
};
};
config = lib.mkOption {
type = lib.types.submodule { options = generatedConfigOptions; };
default = {};
description = "Upstream Clawdbot config (generated from schema).";
description = "Upstream Moltbot config (generated from schema).";
};
};
@ -1138,7 +1137,7 @@ in {
assertions = assertions ++ [
{
assertion = lib.length (lib.attrNames appDefaultsEnabled) <= 1;
message = "Only one Clawdbot instance may enable appDefaults.";
message = "Only one Moltbot instance may enable appDefaults.";
}
] ++ documentsAssertions ++ skillAssertions ++ pluginAssertions ++ pluginSkillAssertions;
@ -1150,8 +1149,8 @@ in {
home.file =
(lib.listToAttrs (map (item: item.homeFile) instanceConfigs))
// (lib.optionalAttrs (pkgs.stdenv.hostPlatform.isDarwin && appPackage != null && cfg.installApp) {
"Applications/Clawdbot.app" = {
source = "${appPackage}/Applications/Clawdbot.app";
"Applications/Moltbot.app" = {
source = "${appPackage}/Applications/Moltbot.app";
recursive = true;
force = true;
};
@ -1162,44 +1161,44 @@ in {
// pluginSkillsFiles
// pluginConfigFiles
// (lib.optionalAttrs cfg.reloadScript.enable {
".local/bin/clawdbot-reload" = {
".local/bin/moltbot-reload" = {
executable = true;
source = ./clawdbot-reload.sh;
source = ./moltbot-reload.sh;
};
});
home.activation.clawdbotDocumentGuard = lib.mkIf documentsEnabled (
home.activation.moltbotDocumentGuard = lib.mkIf documentsEnabled (
lib.hm.dag.entryBefore [ "writeBoundary" ] ''
set -euo pipefail
${documentsGuard}
''
);
home.activation.clawdbotDirs = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
home.activation.moltbotDirs = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
/bin/mkdir -p ${lib.concatStringsSep " " (lib.concatMap (item: item.dirs) instanceConfigs)}
${lib.optionalString (pluginStateDirsAll != []) "/bin/mkdir -p ${lib.concatStringsSep " " pluginStateDirsAll}"}
'';
home.activation.clawdbotConfigFiles = lib.hm.dag.entryAfter [ "clawdbotDirs" ] ''
home.activation.moltbotConfigFiles = lib.hm.dag.entryAfter [ "moltbotDirs" ] ''
set -euo pipefail
${lib.concatStringsSep "\n" (map (item: "/bin/ln -sfn ${item.configFile} ${item.configPath}") instanceConfigs)}
'';
home.activation.clawdbotPluginGuard = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
home.activation.moltbotPluginGuard = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
set -euo pipefail
${pluginGuards}
'';
home.activation.clawdbotAppDefaults = lib.mkIf (pkgs.stdenv.hostPlatform.isDarwin && appDefaults != {}) (
home.activation.moltbotAppDefaults = lib.mkIf (pkgs.stdenv.hostPlatform.isDarwin && appDefaults != {}) (
lib.hm.dag.entryAfter [ "writeBoundary" ] ''
/usr/bin/defaults write com.steipete.Clawdbot clawdbot.gateway.attachExistingOnly -bool ${lib.boolToString (appDefaults.attachExistingOnly or true)}
/usr/bin/defaults write com.steipete.Clawdbot gatewayPort -int ${toString (appDefaults.gatewayPort or 18789)}
/usr/bin/defaults write com.steipete.Moltbot moltbot.gateway.attachExistingOnly -bool ${lib.boolToString (appDefaults.attachExistingOnly or true)}
/usr/bin/defaults write com.steipete.Moltbot gatewayPort -int ${toString (appDefaults.gatewayPort or 18789)}
''
);
home.activation.clawdbotLaunchdRelink = lib.mkIf pkgs.stdenv.hostPlatform.isDarwin (
home.activation.moltbotLaunchdRelink = lib.mkIf pkgs.stdenv.hostPlatform.isDarwin (
lib.hm.dag.entryAfter [ "linkGeneration" ] ''
/usr/bin/env bash ${./clawdbot-launchd-relink.sh}
/usr/bin/env bash ${./moltbot-launchd-relink.sh}
''
);

View File

@ -9,7 +9,7 @@ let
};
in
packages // {
clawdbotPackages = packages // {
moltbotPackages = packages // {
inherit toolNames withTools;
};
}

View File

@ -1,23 +0,0 @@
{ lib
, buildEnv
, clawdbot-gateway
, clawdbot-app ? null
, extendedTools ? []
}:
let
appPaths = lib.optional (clawdbot-app != null) clawdbot-app;
appLinks = lib.optional (clawdbot-app != null) "/Applications";
in
buildEnv {
name = "clawdbot-2.0.0-beta5";
paths = [ clawdbot-gateway ] ++ appPaths ++ extendedTools;
pathsToLink = [ "/bin" ] ++ appLinks;
meta = with lib; {
description = "Clawdbot batteries-included bundle (gateway + app + tools)";
homepage = "https://github.com/clawdbot/clawdbot";
license = licenses.mit;
platforms = platforms.darwin ++ platforms.linux;
};
}

View File

@ -1,5 +1,5 @@
{ pkgs
, sourceInfo ? import ../sources/clawdbot-source.nix
, sourceInfo ? import ../sources/moltbot-source.nix
, steipetePkgs ? {}
, toolNamesOverride ? null
, excludeToolNames ? []
@ -11,23 +11,23 @@ let
steipetePkgs = steipetePkgs;
inherit toolNamesOverride excludeToolNames;
};
clawdbotGateway = pkgs.callPackage ./clawdbot-gateway.nix {
moltbotGateway = pkgs.callPackage ./moltbot-gateway.nix {
inherit sourceInfo;
pnpmDepsHash = sourceInfo.pnpmDepsHash or null;
};
clawdbotApp = if isDarwin then pkgs.callPackage ./clawdbot-app.nix { } else null;
clawdbotTools = pkgs.buildEnv {
name = "clawdbot-tools";
moltbotApp = if isDarwin then pkgs.callPackage ./moltbot-app.nix { } else null;
moltbotTools = pkgs.buildEnv {
name = "moltbot-tools";
paths = toolSets.tools;
pathsToLink = [ "/bin" ];
};
clawdbotBundle = pkgs.callPackage ./clawdbot-batteries.nix {
clawdbot-gateway = clawdbotGateway;
clawdbot-app = clawdbotApp;
moltbotBundle = pkgs.callPackage ./moltbot-batteries.nix {
moltbot-gateway = moltbotGateway;
moltbot-app = moltbotApp;
extendedTools = toolSets.tools;
};
in {
clawdbot-gateway = clawdbotGateway;
clawdbot = clawdbotBundle;
clawdbot-tools = clawdbotTools;
} // (if isDarwin then { clawdbot-app = clawdbotApp; } else {})
moltbot-gateway = moltbotGateway;
moltbot = moltbotBundle;
moltbot-tools = moltbotTools;
} // (if isDarwin then { moltbot-app = moltbotApp; } else {})

View File

@ -4,22 +4,22 @@
}:
stdenvNoCC.mkDerivation {
pname = "clawdbot-app";
pname = "moltbot-app";
version = "2026.1.23";
src = fetchzip {
url = "https://github.com/clawdbot/clawdbot/releases/download/v2026.1.23/Clawdbot-2026.1.23.zip";
url = "https://github.com/moltbot/moltbot/releases/download/v2026.1.23/Clawdbot-2026.1.23.zip";
hash = "sha256-HGN8yfDHkoP30YBk11U7kugE6RVkDs9oGwyUdLztToQ=";
stripRoot = false;
};
dontUnpack = true;
installPhase = "${../scripts/clawdbot-app-install.sh}";
installPhase = "${../scripts/moltbot-app-install.sh}";
meta = with lib; {
description = "Clawdbot macOS app bundle";
homepage = "https://github.com/clawdbot/clawdbot";
description = "Moltbot macOS app bundle";
homepage = "https://github.com/moltbot/moltbot";
license = licenses.mit;
platforms = platforms.darwin;
};

View File

@ -0,0 +1,23 @@
{ lib
, buildEnv
, moltbot-gateway
, moltbot-app ? null
, extendedTools ? []
}:
let
appPaths = lib.optional (moltbot-app != null) moltbot-app;
appLinks = lib.optional (moltbot-app != null) "/Applications";
in
buildEnv {
name = "moltbot-2.0.0-beta5";
paths = [ moltbot-gateway ] ++ appPaths ++ extendedTools;
pathsToLink = [ "/bin" ] ++ appLinks;
meta = with lib; {
description = "Moltbot batteries-included bundle (gateway + app + tools)";
homepage = "https://github.com/moltbot/moltbot";
license = licenses.mit;
platforms = platforms.darwin ++ platforms.linux;
};
}

View File

@ -7,6 +7,7 @@
, pkg-config
, jq
, python3
, perl
, node-gyp
, makeWrapper
, vips
@ -37,7 +38,7 @@ let
in
stdenv.mkDerivation (finalAttrs: {
pname = "clawdbot-gateway";
pname = "moltbot-gateway";
version = "2026.1.8-2";
src = if gatewaySrc != null then gatewaySrc else fetchFromGitHub sourceFetch;
@ -59,6 +60,7 @@ stdenv.mkDerivation (finalAttrs: {
pkg-config
jq
python3
perl
node-gyp
makeWrapper
zstd
@ -90,10 +92,10 @@ stdenv.mkDerivation (finalAttrs: {
dontPatchShebangs = true;
meta = with lib; {
description = "Telegram-first AI gateway (Clawdbot)";
homepage = "https://github.com/clawdbot/clawdbot";
description = "Telegram-first AI gateway (Moltbot)";
homepage = "https://github.com/moltbot/moltbot";
license = licenses.mit;
platforms = platforms.darwin ++ platforms.linux;
mainProgram = "clawdbot";
mainProgram = "moltbot";
};
})

View File

@ -1,3 +1,3 @@
#!/bin/sh
set -e
install -Dm755 "$src" "$out/bin/clawdbot-entrypoint"
install -Dm755 "$src" "$out/bin/moltbot-entrypoint"

View File

@ -1,8 +1,8 @@
#!/bin/sh
set -e
mkdir -p "$out/lib/clawdbot" "$out/bin"
mkdir -p "$out/lib/moltbot" "$out/bin"
cp -r dist node_modules package.json ui "$out/lib/clawdbot/"
cp -r dist node_modules package.json ui "$out/lib/moltbot/"
if [ -z "${STDENV_SETUP:-}" ]; then
echo "STDENV_SETUP is not set" >&2
@ -13,15 +13,15 @@ if [ ! -f "$STDENV_SETUP" ]; then
exit 1
fi
bash -e -c '. "$STDENV_SETUP"; patchShebangs "$out/lib/clawdbot/node_modules/.bin"'
if [ -d "$out/lib/clawdbot/ui/node_modules/.bin" ]; then
bash -e -c '. "$STDENV_SETUP"; patchShebangs "$out/lib/clawdbot/ui/node_modules/.bin"'
bash -e -c '. "$STDENV_SETUP"; patchShebangs "$out/lib/moltbot/node_modules/.bin"'
if [ -d "$out/lib/moltbot/ui/node_modules/.bin" ]; then
bash -e -c '. "$STDENV_SETUP"; patchShebangs "$out/lib/moltbot/ui/node_modules/.bin"'
fi
# Work around missing dependency declaration in pi-coding-agent (strip-ansi).
# Ensure it is resolvable at runtime without changing upstream.
pi_pkg="$(find "$out/lib/clawdbot/node_modules/.pnpm" -path "*/node_modules/@mariozechner/pi-coding-agent" -print | head -n 1)"
strip_ansi_src="$(find "$out/lib/clawdbot/node_modules/.pnpm" -path "*/node_modules/strip-ansi" -print | head -n 1)"
pi_pkg="$(find "$out/lib/moltbot/node_modules/.pnpm" -path "*/node_modules/@mariozechner/pi-coding-agent" -print | head -n 1)"
strip_ansi_src="$(find "$out/lib/moltbot/node_modules/.pnpm" -path "*/node_modules/strip-ansi" -print | head -n 1)"
if [ -n "$strip_ansi_src" ]; then
if [ -n "$pi_pkg" ] && [ ! -e "$pi_pkg/node_modules/strip-ansi" ]; then
@ -29,9 +29,9 @@ if [ -n "$strip_ansi_src" ]; then
ln -s "$strip_ansi_src" "$pi_pkg/node_modules/strip-ansi"
fi
if [ ! -e "$out/lib/clawdbot/node_modules/strip-ansi" ]; then
mkdir -p "$out/lib/clawdbot/node_modules"
ln -s "$strip_ansi_src" "$out/lib/clawdbot/node_modules/strip-ansi"
if [ ! -e "$out/lib/moltbot/node_modules/strip-ansi" ]; then
mkdir -p "$out/lib/moltbot/node_modules"
ln -s "$strip_ansi_src" "$out/lib/moltbot/node_modules/strip-ansi"
fi
fi
bash -e -c '. "$STDENV_SETUP"; makeWrapper "$NODE_BIN" "$out/bin/clawdbot" --add-flags "$out/lib/clawdbot/dist/index.js" --set-default CLAWDBOT_NIX_MODE "1"'
bash -e -c '. "$STDENV_SETUP"; makeWrapper "$NODE_BIN" "$out/bin/moltbot" --add-flags "$out/lib/moltbot/dist/index.js" --set-default MOLTBOT_NIX_MODE "1" --set-default CLAWDBOT_NIX_MODE "1"'

View File

@ -5,8 +5,8 @@ if [ -f package.json ]; then
fi
if [ -f src/logging.ts ]; then
if ! grep -q "CLAWDBOT_LOG_DIR" src/logging.ts; then
sed -i 's/export const DEFAULT_LOG_DIR = "\/tmp\/clawdbot";/export const DEFAULT_LOG_DIR = process.env.CLAWDBOT_LOG_DIR ?? "\/tmp\/clawdbot";/' src/logging.ts
if ! grep -q "MOLTBOT_LOG_DIR" src/logging.ts; then
sed -i 's/export const DEFAULT_LOG_DIR = "\/tmp\/moltbot";/export const DEFAULT_LOG_DIR = process.env.MOLTBOT_LOG_DIR ?? "\/tmp\/moltbot";/' src/logging.ts
fi
fi

View File

@ -12,11 +12,11 @@ fi
export HOME="$(mktemp -d)"
export TMPDIR="${HOME}/tmp"
mkdir -p "$TMPDIR"
export CLAWDBOT_LOG_DIR="${TMPDIR}/clawdbot-logs"
export CLAWDBOT_LOG_PATH="${CLAWDBOT_LOG_DIR}/clawdbot-gateway.log"
mkdir -p "$CLAWDBOT_LOG_DIR"
mkdir -p /tmp/clawdbot || true
chmod 700 /tmp/clawdbot || true
export MOLTBOT_LOG_DIR="${TMPDIR}/moltbot-logs"
export MOLTBOT_LOG_PATH="${MOLTBOT_LOG_DIR}/moltbot-gateway.log"
mkdir -p "$MOLTBOT_LOG_DIR"
mkdir -p /tmp/moltbot || true
chmod 700 /tmp/moltbot || true
export VITEST_POOL="threads"
export VITEST_MIN_THREADS="1"
export VITEST_MAX_THREADS="1"

View File

@ -10,19 +10,19 @@ const argValue = (flag: string): string | null => {
};
const repo = argValue("--repo") ?? process.cwd();
const outPath = argValue("--out") ?? path.join(process.cwd(), "nix/generated/clawdbot-config-options.nix");
const outPath = argValue("--out") ?? path.join(process.cwd(), "nix/generated/moltbot-config-options.nix");
const schemaPath = path.join(repo, "src/config/zod-schema.ts");
const schemaUrl = pathToFileURL(schemaPath).href;
const loadSchema = async (): Promise<Record<string, unknown>> => {
const mod = await import(schemaUrl);
const ClawdbotSchema = mod.ClawdbotSchema;
if (!ClawdbotSchema || typeof ClawdbotSchema.toJSONSchema !== "function") {
console.error(`ClawdbotSchema not found at ${schemaPath}`);
const MoltbotSchema = mod.MoltbotSchema;
if (!MoltbotSchema || typeof MoltbotSchema.toJSONSchema !== "function") {
console.error(`MoltbotSchema not found at ${schemaPath}`);
process.exit(1);
}
return ClawdbotSchema.toJSONSchema({
return MoltbotSchema.toJSONSchema({
target: "draft-07",
unrepresentable: "any",
}) as Record<string, unknown>;
@ -244,7 +244,7 @@ const renderOption = (key: string, schemaObj: JsonSchema, _required: boolean, in
.map((key) => renderOption(key, rootProps[key], requiredRoot.has(key), " "))
.join("\n\n");
const output = `# Generated from upstream Clawdbot schema. DO NOT EDIT.\n{ lib }:\nlet\n t = lib.types;\nin\n{\n${body}\n}\n`;
const output = `# Generated from upstream Moltbot schema. DO NOT EDIT.\n{ lib }:\nlet\n t = lib.types;\nin\n{\n${body}\n}\n`;
fs.mkdirSync(path.dirname(outPath), { recursive: true });
fs.writeFileSync(outPath, output, "utf8");

View File

@ -3,7 +3,7 @@ set -e
mkdir -p "$out/Applications"
app_path="$(find "$src" -maxdepth 2 -name '*.app' -print -quit)"
if [ -z "$app_path" ]; then
echo "Clawdbot.app not found in $src" >&2
echo "Moltbot.app not found in $src" >&2
exit 1
fi
cp -R "$app_path" "$out/Applications/Clawdbot.app"
cp -R "$app_path" "$out/Applications/Moltbot.app"

View File

@ -1,8 +0,0 @@
# Pinned Clawdbot source for nix-clawdbot
{
owner = "clawdbot";
repo = "clawdbot";
rev = "66a5b324a1e6c0fbbb5fd2ab5cb0e4f29894bda4";
hash = "sha256-9Mu9FE0+RGxK/Pz2pT0ajluOAQLphOHZkf/pCKvcmN4=";
pnpmDepsHash = "sha256-VX1AmmGkae3tI5l9inInRE5b6cM4GMlMfjomHdsGags=";
}

View File

@ -0,0 +1,8 @@
# Pinned Moltbot source for nix-moltbot
{
owner = "moltbot";
repo = "moltbot";
rev = "a49250fffc3f1e44c3d0de381cdc5f42dece36a6";
hash = "sha256-Wjeby/7pxS6qwqsnCTArMFioqPTq83MvsQ+FPIglom8=";
pnpmDepsHash = "sha256-VX1AmmGkae3tI5l9inInRE5b6cM4GMlMfjomHdsGags=";
}

View File

@ -2,8 +2,8 @@
set -euo pipefail
repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
source_file="$repo_root/nix/sources/clawdbot-source.nix"
app_file="$repo_root/nix/packages/clawdbot-app.nix"
source_file="$repo_root/nix/sources/moltbot-source.nix"
app_file="$repo_root/nix/packages/moltbot-app.nix"
log() {
printf '>> %s\n' "$*"
@ -12,7 +12,7 @@ log() {
upstream_checks_green() {
local sha="$1"
local checks_json
checks_json=$(gh api "/repos/clawdbot/clawdbot/commits/${sha}/check-runs?per_page=100" 2>/dev/null || true)
checks_json=$(gh api "/repos/moltbot/moltbot/commits/${sha}/check-runs?per_page=100" 2>/dev/null || true)
if [[ -z "$checks_json" ]]; then
log "No check runs found for $sha"
return 1
@ -45,12 +45,12 @@ if ! command -v jq >/dev/null 2>&1; then
exit 1
fi
log "Resolving clawdbot main SHAs"
mapfile -t candidate_shas < <(gh api /repos/clawdbot/clawdbot/commits?per_page=10 | jq -r '.[].sha' || true)
log "Resolving moltbot main SHAs"
mapfile -t candidate_shas < <(gh api /repos/moltbot/moltbot/commits?per_page=10 | jq -r '.[].sha' || true)
if [[ ${#candidate_shas[@]} -eq 0 ]]; then
latest_sha=$(git ls-remote https://github.com/clawdbot/clawdbot.git refs/heads/main | awk '{print $1}' || true)
latest_sha=$(git ls-remote https://github.com/moltbot/moltbot.git refs/heads/main | awk '{print $1}' || true)
if [[ -z "$latest_sha" ]]; then
echo "Failed to resolve clawdbot main SHA" >&2
echo "Failed to resolve moltbot main SHA" >&2
exit 1
fi
candidate_shas=("$latest_sha")
@ -66,7 +66,7 @@ for sha in "${candidate_shas[@]}"; do
continue
fi
log "Testing upstream SHA: $sha"
source_url="https://github.com/clawdbot/clawdbot/archive/${sha}.tar.gz"
source_url="https://github.com/moltbot/moltbot/archive/${sha}.tar.gz"
log "Prefetching source tarball"
source_prefetch=$(
nix --extra-experimental-features "nix-command flakes" store prefetch-file --unpack --json "$source_url" 2>"/tmp/nix-prefetch-source.err" \
@ -99,12 +99,12 @@ for sha in "${candidate_shas[@]}"; do
build_log=$(mktemp)
log "Building gateway to validate pnpmDepsHash"
if ! nix build .#clawdbot-gateway --accept-flake-config >"$build_log" 2>&1; then
if ! nix build .#moltbot-gateway --accept-flake-config >"$build_log" 2>&1; then
pnpm_hash=$(grep -Eo 'got: *sha256-[A-Za-z0-9+/=]+' "$build_log" | head -n 1 | sed 's/.*got: *//' || true)
if [[ -n "$pnpm_hash" ]]; then
log "pnpmDepsHash mismatch detected: $pnpm_hash"
perl -0pi -e "s|pnpmDepsHash = \"[^\"]*\";|pnpmDepsHash = \"${pnpm_hash}\";|" "$source_file"
if ! nix build .#clawdbot-gateway --accept-flake-config >"$build_log" 2>&1; then
if ! nix build .#moltbot-gateway --accept-flake-config >"$build_log" 2>&1; then
tail -n 200 "$build_log" >&2 || true
rm -f "$build_log"
continue
@ -130,19 +130,19 @@ fi
log "Selected upstream SHA: $selected_sha"
log "Fetching latest release metadata"
release_json=$(gh api /repos/clawdbot/clawdbot/releases?per_page=20 || true)
release_json=$(gh api /repos/moltbot/moltbot/releases?per_page=20 || true)
if [[ -z "$release_json" ]]; then
echo "Failed to fetch release metadata" >&2
exit 1
fi
release_tag=$(printf '%s' "$release_json" | jq -r '[.[] | select([.assets[]?.name | (test("^(Clawdbot|Clawdis)-.*\\.zip$") and (test("dSYM") | not))] | any)][0].tag_name // empty')
release_tag=$(printf '%s' "$release_json" | jq -r '[.[] | select([.assets[]?.name | (test("^Clawdbot-.*\\.zip$") and (test("dSYM") | not))] | any)][0].tag_name // empty')
if [[ -z "$release_tag" ]]; then
echo "Failed to resolve a release tag with a Clawdbot app asset" >&2
exit 1
fi
log "Latest app release tag with asset: $release_tag"
app_url=$(printf '%s' "$release_json" | jq -r '[.[] | select([.assets[]?.name | (test("^(Clawdbot|Clawdis)-.*\\.zip$") and (test("dSYM") | not))] | any)][0].assets[] | select(.name | (test("^(Clawdbot|Clawdis)-.*\\.zip$") and (test("dSYM") | not))) | .browser_download_url' | head -n 1 || true)
app_url=$(printf '%s' "$release_json" | jq -r '[.[] | select([.assets[]?.name | (test("^Clawdbot-.*\\.zip$") and (test("dSYM") | not))] | any)][0].assets[] | select(.name | (test("^Clawdbot-.*\\.zip$") and (test("dSYM") | not))) | .browser_download_url' | head -n 1 || true)
if [[ -z "$app_url" ]]; then
echo "Failed to resolve Clawdbot app asset URL from latest release" >&2
exit 1
@ -178,7 +178,7 @@ if [[ -z "$selected_source_store_path" ]]; then
exit 1
fi
log "Regenerating clawdbot config options from upstream schema"
log "Regenerating moltbot config options from upstream schema"
tmp_src=$(mktemp -d)
cleanup_tmp() {
rm -rf "$tmp_src"
@ -191,7 +191,7 @@ nix shell --extra-experimental-features "nix-command flakes" nixpkgs#nodejs_22 n
bash -c "cd '$tmp_src/src' && pnpm install --frozen-lockfile --ignore-scripts"
nix shell --extra-experimental-features "nix-command flakes" nixpkgs#nodejs_22 nixpkgs#pnpm_10 -c \
bash -c "cd '$tmp_src/src' && pnpm exec tsx '$repo_root/nix/scripts/generate-config-options.ts' --repo . --out '$repo_root/nix/generated/clawdbot-config-options.nix'"
bash -c "cd '$tmp_src/src' && pnpm exec tsx '$repo_root/nix/scripts/generate-config-options.ts' --repo . --out '$repo_root/nix/generated/moltbot-config-options.nix'"
cleanup_tmp
trap - EXIT
@ -200,12 +200,12 @@ log "Building app to validate fetchzip hash"
current_system=$(nix eval --impure --raw --expr 'builtins.currentSystem' 2>/dev/null || true)
if [[ "$current_system" == *darwin* ]]; then
app_build_log=$(mktemp)
if ! nix build .#clawdbot-app --accept-flake-config >"$app_build_log" 2>&1; then
if ! nix build .#moltbot-app --accept-flake-config >"$app_build_log" 2>&1; then
app_hash_mismatch=$(grep -Eo 'got: *sha256-[A-Za-z0-9+/=]+' "$app_build_log" | head -n 1 | sed 's/.*got: *//' || true)
if [[ -n "$app_hash_mismatch" ]]; then
log "App hash mismatch detected: $app_hash_mismatch"
perl -0pi -e "s|hash = \"[^\"]+\";|hash = \"${app_hash_mismatch}\";|" "$app_file"
if ! nix build .#clawdbot-app --accept-flake-config >"$app_build_log" 2>&1; then
if ! nix build .#moltbot-app --accept-flake-config >"$app_build_log" 2>&1; then
tail -n 200 "$app_build_log" >&2 || true
rm -f "$app_build_log"
exit 1
@ -227,22 +227,22 @@ if git diff --quiet; then
fi
log "Committing updated pins"
git add "$source_file" "$app_file" "$repo_root/nix/generated/clawdbot-config-options.nix"
git add "$source_file" "$app_file" "$repo_root/nix/generated/moltbot-config-options.nix"
git commit -F - <<'EOF'
🤖 codex: bump clawdbot pins (no-issue)
🤖 codex: bump moltbot pins (no-issue)
What:
- pin clawdbot source to latest upstream main
- pin moltbot source to latest upstream main
- refresh macOS app pin to latest release asset
- update source and app hashes
- regenerate config options from upstream schema
Why:
- keep nix-clawdbot on latest upstream for yolo mode
- keep nix-moltbot on latest upstream for yolo mode
Tests:
- nix build .#clawdbot-gateway --accept-flake-config
- nix build .#clawdbot-app --accept-flake-config
- nix build .#moltbot-gateway --accept-flake-config
- nix build .#moltbot-app --accept-flake-config
EOF
log "Rebasing on latest main"

View File

@ -1,4 +1,4 @@
# AGENTS.md — Clawdbot Workspace
# AGENTS.md — Moltbot Workspace
This file is managed by Nix. Update it in the repo, not in the workspace.

View File

@ -1,4 +1,4 @@
# SOUL.md
Clawdbot exists to do useful work reliably with minimal friction.
Moltbot exists to do useful work reliably with minimal friction.

View File

@ -1,24 +1,24 @@
{
description = "Clawdbot local";
description = "Moltbot local";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
nix-clawdbot.url = "github:clawdbot/nix-clawdbot";
nix-moltbot.url = "github:moltbot/nix-moltbot";
};
outputs = { self, nixpkgs, home-manager, nix-clawdbot }:
outputs = { self, nixpkgs, home-manager, nix-moltbot }:
let
# REPLACE: aarch64-darwin (Apple Silicon), x86_64-darwin (Intel), or x86_64-linux
system = "<system>";
pkgs = import nixpkgs { inherit system; overlays = [ nix-clawdbot.overlays.default ]; };
pkgs = import nixpkgs { inherit system; overlays = [ nix-moltbot.overlays.default ]; };
in {
# REPLACE: <user> with your username (run `whoami`)
homeConfigurations."<user>" = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
modules = [
nix-clawdbot.homeManagerModules.clawdbot
nix-moltbot.homeManagerModules.moltbot
{
# Required for Home Manager standalone
home.username = "<user>";
@ -27,7 +27,7 @@
home.stateVersion = "24.11";
programs.home-manager.enable = true;
programs.clawdbot = {
programs.moltbot = {
# REPLACE: path to your managed documents directory
documents = ./documents;
instances.default = {