🤖 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:
parent
474ee38945
commit
f0482a8a0c
4
.github/workflows/yolo-update.yml
vendored
4
.github/workflows/yolo-update.yml
vendored
@ -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
|
||||
|
||||
12
AGENTS.md
12
AGENTS.md
@ -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: “I’m 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
160
README.md
@ -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
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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 batteries‑included, 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, user‑friendly configuration layer with strong defaults and an agent‑first 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 batteries‑included, 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, user‑friendly configuration layer with strong defaults and an agent‑first 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, end‑user 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 / Non‑goals
|
||||
|
||||
Goals:
|
||||
- Provide a Nix package for Clawdbot and a Home Manager module with batteries‑included defaults.
|
||||
- Provide a Nix package for Moltbot and a Home Manager module with batteries‑included defaults.
|
||||
- Provide a macOS app bundle package aligned to the gateway version.
|
||||
- Make configuration technically light with explicit options and guardrails.
|
||||
- Telegram‑first configuration and defaults.
|
||||
@ -40,17 +40,17 @@ Goals:
|
||||
- New user can get a working bot in 10 minutes without understanding Nix internals.
|
||||
|
||||
Non‑goals:
|
||||
- Rewriting Clawdbot core functionality.
|
||||
- Rewriting Moltbot core functionality.
|
||||
- Supporting non‑Nix install paths in this repo.
|
||||
- Shipping a hosted SaaS or paid hosting.
|
||||
- Replacing upstream Clawdbot docs.
|
||||
- Replacing upstream Moltbot docs.
|
||||
- Cross‑platform support (Linux/Windows) in v1.
|
||||
- CI automation in v1.
|
||||
|
||||
## 3) System overview
|
||||
|
||||
`nix-clawdbot` is a public repo that provides (macOS‑only in v1, no CI in v1):
|
||||
- A Nix package derivation for the Clawdbot gateway.
|
||||
`nix-moltbot` is a public repo that provides (macOS‑only 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 user‑level config and service wiring.
|
||||
- A nix‑darwin module for macOS users (optional, thin wrapper over HM).
|
||||
@ -59,20 +59,20 @@ Non‑goals:
|
||||
|
||||
## 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 batteries‑included bundle)
|
||||
- `packages.<system>.clawdbot-gateway`
|
||||
- `packages.<system>.clawdbot-app`
|
||||
- `packages.<system>.clawdbot-tools`
|
||||
- `homeManagerModules.clawdbot`
|
||||
- `darwinModules.clawdbot` (if needed)
|
||||
- `packages.<system>.moltbot` (default batteries‑included 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 (batteries‑included)
|
||||
|
||||
- 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` batteries‑included package.
|
||||
- Uses `nix-moltbot` batteries‑included 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 agent‑first guide.
|
||||
- Telegram‑first 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 attach‑only mode (does not spawn its own gateway).
|
||||
- Smoke test: user sends a Telegram message in an allowlisted chat and receives a response.
|
||||
|
||||
@ -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?
|
||||
|
||||
|
||||
@ -3,5 +3,5 @@
|
||||
This plugin is intentionally tiny.
|
||||
|
||||
Knobs
|
||||
- CLAWDBOT_USER (optional): name to greet
|
||||
- MOLTBOT_USER (optional): name to greet
|
||||
|
||||
|
||||
@ -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 ];
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
module github.com/acme/hello-world-clawdbot
|
||||
module github.com/acme/hello-world-moltbot
|
||||
|
||||
go 1.22
|
||||
|
||||
@ -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
10
flake.lock
generated
@ -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"
|
||||
}
|
||||
|
||||
20
flake.nix
20
flake.nix
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
14
garnix.yaml
14
garnix.yaml
@ -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"
|
||||
|
||||
@ -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}";
|
||||
};
|
||||
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -2,6 +2,6 @@
|
||||
|
||||
{
|
||||
config = lib.mkIf (config ? home-manager) {
|
||||
home-manager.sharedModules = [ ../home-manager/clawdbot.nix ];
|
||||
home-manager.sharedModules = [ ../home-manager/moltbot.nix ];
|
||||
};
|
||||
}
|
||||
@ -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
|
||||
@ -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"
|
||||
36
nix/modules/home-manager/moltbot-reload.sh
Normal file
36
nix/modules/home-manager/moltbot-reload.sh
Normal 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
|
||||
@ -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}
|
||||
''
|
||||
);
|
||||
|
||||
@ -9,7 +9,7 @@ let
|
||||
};
|
||||
in
|
||||
packages // {
|
||||
clawdbotPackages = packages // {
|
||||
moltbotPackages = packages // {
|
||||
inherit toolNames withTools;
|
||||
};
|
||||
}
|
||||
|
||||
@ -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;
|
||||
};
|
||||
}
|
||||
@ -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 {})
|
||||
|
||||
@ -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;
|
||||
};
|
||||
23
nix/packages/moltbot-batteries.nix
Normal file
23
nix/packages/moltbot-batteries.nix
Normal 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;
|
||||
};
|
||||
}
|
||||
@ -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";
|
||||
};
|
||||
})
|
||||
@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
install -Dm755 "$src" "$out/bin/clawdbot-entrypoint"
|
||||
install -Dm755 "$src" "$out/bin/moltbot-entrypoint"
|
||||
|
||||
@ -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"'
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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"
|
||||
@ -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=";
|
||||
}
|
||||
8
nix/sources/moltbot-source.nix
Normal file
8
nix/sources/moltbot-source.nix
Normal 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=";
|
||||
}
|
||||
@ -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"
|
||||
|
||||
@ -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.
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
|
||||
@ -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 = {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user