fireclaw 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +117 -109
- package/bin/fireclaw +11 -3
- package/bin/vm-common.sh +244 -37
- package/bin/vm-ctl +182 -37
- package/bin/vm-provision +152 -18
- package/bin/vm-setup +237 -94
- package/package.json +5 -4
- package/scripts/provision-guest.sh +134 -25
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 bchewy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,149 +1,157 @@
|
|
|
1
1
|
# fireclaw
|
|
2
2
|
|
|
3
|
-
Run [OpenClaw](https://github.com/openclaw/openclaw)
|
|
4
|
-
|
|
5
|
-
## Why
|
|
6
|
-
|
|
7
|
-
Running OpenClaw directly on a host (bare metal or in Docker) means every instance shares the kernel, network namespace, and often the Docker socket. That's fine for a single bot, but problematic when you want:
|
|
8
|
-
|
|
9
|
-
- **Isolation** — one misbehaving instance can't interfere with others or the host
|
|
10
|
-
- **Reproducibility** — each VM boots from a clean rootfs image, no drift
|
|
11
|
-
- **Security** — no Docker socket mount into the container; the guest runs its own Docker daemon
|
|
12
|
-
- **Density** — Firecracker VMs boot in ~125ms and use ~5MB overhead per VM, so you can pack many instances on a single host
|
|
13
|
-
|
|
14
|
-
This repo is a minimal control plane that wires up Firecracker VM lifecycle, networking, and OpenClaw provisioning with plain bash and systemd. No orchestrator, no Kubernetes, no extra daemons.
|
|
3
|
+
Run [OpenClaw](https://github.com/openclaw/openclaw) agents inside Firecracker microVMs — one VM per instance, each with its own kernel, filesystem, Docker daemon, and network. A small Bash CLI drives Firecracker + systemd directly: no Kubernetes, no always-on daemon, no hidden state.
|
|
15
4
|
|
|
16
5
|
## How it works
|
|
17
6
|
|
|
7
|
+
`fireclaw setup` builds four things on the host, then provisions the guest over SSH:
|
|
8
|
+
|
|
9
|
+
1. **Instance state** — `/var/lib/fireclaw/.vm-<id>/` holds `.env` (allocation + config), `.token` (gateway auth token), `provision.vars` (guest provisioning input, including secrets), and `known_hosts` (the guest SSH host key, pinned after the first successful login). The directory is root-only (`0700`); the secret files are mode `0600`.
|
|
10
|
+
2. **VM assets** — `/srv/firecracker/vm-demo/<id>/`: a copy of the base rootfs resized to `--disk-size`, kernel (+ optional initrd), a cloud-init seed image (ubuntu user, SSH key, static IP by MAC match), the Firecracker JSON config, and generated `start-vm.sh` / `stop-vm.sh`.
|
|
11
|
+
3. **Two systemd units** — `firecracker-vmdemo-<id>.service` runs the VM: `Restart=always` (an in-guest reboot or VMM crash comes back on its own) and an `ExecStop` that asks the guest to shut down cleanly through the Firecracker API socket before the VMM exits. `vmdemo-proxy-<id>.service` runs socat as an unprivileged dynamic user, forwarding `127.0.0.1:<HOST_PORT>` → `<VM_IP>:18789`, and starts/stops with the VM unit.
|
|
12
|
+
4. **Network** — one tap per VM on the `fc-br0` bridge (`172.16.0.1/24`). Each tap is an *isolated* bridge port, so VMs cannot exchange IP or ARP traffic with each other — only with the host and, via a MASQUERADE rule, the internet. Host port and VM IP are allocated under a lock, so concurrent setups cannot collide.
|
|
13
|
+
|
|
14
|
+
Guest provisioning (`scripts/provision-guest.sh`, SCP'd in and run once over SSH) installs Docker with bridge/iptables disabled, pulls the OpenClaw image, writes the gateway/model/skills config (Telegram is enabled only when a token was provided, otherwise explicitly disabled), installs a health script, and creates `openclaw-<id>.service`, which runs the container with `--network host` serving the gateway on `:18789`. The copied secrets are removed from guest `/tmp` when the script exits.
|
|
15
|
+
|
|
16
|
+
```mermaid
|
|
17
|
+
flowchart LR
|
|
18
|
+
cli["fireclaw CLI<br/>sudo fireclaw ..."]
|
|
19
|
+
|
|
20
|
+
subgraph host["Host"]
|
|
21
|
+
state["state<br/>/var/lib/fireclaw/.vm-id"]
|
|
22
|
+
assets["assets<br/>/srv/firecracker/vm-demo/id"]
|
|
23
|
+
vmUnit["firecracker-vmdemo-id.service"]
|
|
24
|
+
proxyUnit["vmdemo-proxy-id.service<br/>socat 127.0.0.1:HOST_PORT"]
|
|
25
|
+
net["fc-br0 bridge + NAT<br/>isolated tap per VM"]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
subgraph guest["Firecracker VM"]
|
|
29
|
+
cloudInit["cloud-init<br/>ubuntu user, SSH, static IP"]
|
|
30
|
+
docker["Docker (bridge off)"]
|
|
31
|
+
guestUnit["openclaw-id.service"]
|
|
32
|
+
container["OpenClaw container<br/>gateway :18789"]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
cli --> state
|
|
36
|
+
cli --> assets
|
|
37
|
+
cli --> vmUnit
|
|
38
|
+
vmUnit --> net
|
|
39
|
+
net --> guest
|
|
40
|
+
cli -->|"SCP + SSH provision"| docker
|
|
41
|
+
docker --> guestUnit
|
|
42
|
+
guestUnit --> container
|
|
43
|
+
proxyUnit -->|"forwards to VM_IP:18789"| container
|
|
44
|
+
cli -->|"health gates"| proxyUnit
|
|
18
45
|
```
|
|
19
|
-
Host
|
|
20
|
-
├── systemd: firecracker-vmdemo-<id>.service ← runs the VM
|
|
21
|
-
├── systemd: vmdemo-proxy-<id>.service ← socat: localhost:<port> → VM:18789
|
|
22
|
-
├── bridge: fc-br0 (172.16.0.0/24) ← shared bridge for all VMs
|
|
23
|
-
│
|
|
24
|
-
└── Firecracker VM (172.16.0.x)
|
|
25
|
-
├── cloud-init: ubuntu user, SSH key, Docker install
|
|
26
|
-
├── Docker: pulls OpenClaw image
|
|
27
|
-
├── systemd: openclaw-<id>.service ← docker run --network host ... gateway --bind lan --port 18789
|
|
28
|
-
└── Browser binaries (Playwright Chromium, installed at provision time)
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
1. **`fireclaw setup`** creates a new instance: copies the base rootfs, optionally resizes it (default `40G`), generates a cloud-init seed image, allocates an IP + host port, writes a Firecracker config, creates systemd units, boots the VM with a per-instance Firecracker API socket, waits for SSH, then SCPs `provision-guest.sh` into the guest and runs it.
|
|
32
|
-
|
|
33
|
-
2. **`provision-guest.sh`** runs inside the VM as root: waits for cloud-init/apt locks, expands the guest ext4 filesystem (`resize2fs`), configures Docker for Firecracker (`iptables=false`, `ip6tables=false`, `bridge=none`), pulls the OpenClaw image, runs the OpenClaw CLI (`doctor --fix` included), installs Playwright Chromium, writes browser path + health-check script, then creates and starts the guest systemd service.
|
|
34
|
-
|
|
35
|
-
3. **`fireclaw`** manages the lifecycle after setup: start/stop/restart VMs, tail logs (guest or host side), open an SSH shell, show status, or destroy an instance.
|
|
36
46
|
|
|
37
|
-
|
|
38
|
-
- **Instance state** `/var/lib/fireclaw/.vm-<id>/` — env file, token, provision vars
|
|
39
|
-
- **VM runtime** `/srv/firecracker/vm-demo/<id>/` — VM images, Firecracker config, logs
|
|
47
|
+
Lifecycle semantics:
|
|
40
48
|
|
|
41
|
-
|
|
49
|
+
- `setup`, `provision`, and `start` return success only after **both** health gates pass: the guest health script (container running + `/health` inside the VM) and the localhost proxy `/health`. `start` never reprovisions. `list`/`status` are looser inspection views (health may read up when either the proxy or the guest check responds).
|
|
50
|
+
- A `setup` failure *before* guest provisioning completes rolls back only that instance (units, tap, API socket, state, assets). After guest provisioning succeeds, failures keep the instance — inspect with `status`, retry with `provision`.
|
|
51
|
+
- `stop` shuts down proxy → guest service → VM (clean guest shutdown via the API socket) and disables the units, so a stopped instance stays stopped across host reboots until `start`.
|
|
52
|
+
- `provision <id> [flags]` updates the saved config and reruns guest provisioning on the existing VM — no new IP, port, or disk. Overrides are validated first; a rejected run changes nothing.
|
|
53
|
+
- `destroy` removes units, tap, API socket, state, and assets; `--force` also cleans up instances with unreadable state (units and directories only — a leftover tap or socket then needs manual removal).
|
|
42
54
|
|
|
43
|
-
|
|
44
|
-
- `firecracker` binary at `/usr/local/bin/firecracker` ([install guide](https://github.com/firecracker-microvm/firecracker/blob/main/docs/getting-started.md))
|
|
45
|
-
- `qemu-img` (from `qemu-utils`) for rootfs resizing
|
|
46
|
-
- `cloud-localds` (from `cloud-image-utils`), `socat`, `jq`, `iptables`, `iproute2`, `ssh`, `scp`, `curl`, `openssl`
|
|
47
|
-
- Base VM images: a Linux kernel (`vmlinux`) and an ext4 rootfs with cloud-init support. Optionally an initrd.
|
|
48
|
-
|
|
49
|
-
Set `BASE_IMAGES_DIR` or pass `--base-kernel`/`--base-rootfs`/`--base-initrd` to point at your images.
|
|
55
|
+
Naming note: runtime paths keep the historical `vmdemo` names (`/srv/firecracker/vm-demo`, `firecracker-vmdemo-*`, `vmdemo-proxy-*`) so existing instances keep working.
|
|
50
56
|
|
|
51
57
|
## Install
|
|
52
58
|
|
|
59
|
+
Host needs Linux with KVM (`/dev/kvm`), root access, `firecracker` on `PATH`, the usual tools (`systemctl`, `cloud-localds`, `qemu-img`, `iptables`, `ip`, `bridge`, `socat`, `jq`, `curl`, `openssl`, `ssh`, `scp`, `install`, `flock`), and base images (kernel + cloud-init-capable ext4 rootfs, default dir `/srv/firecracker/base/images`). `fireclaw doctor` checks all of this.
|
|
60
|
+
|
|
53
61
|
```bash
|
|
54
62
|
npm install -g fireclaw
|
|
55
63
|
```
|
|
56
64
|
|
|
57
|
-
|
|
65
|
+
If `sudo fireclaw` reports `command not found` (nvm/user-prefix installs aren't on root's `secure_path`):
|
|
58
66
|
|
|
59
67
|
```bash
|
|
60
|
-
sudo fireclaw
|
|
61
|
-
--instance my-bot \
|
|
62
|
-
--telegram-token "<your-bot-token>" \
|
|
63
|
-
--telegram-users "<your-telegram-user-id>" \
|
|
64
|
-
--model "anthropic/claude-opus-4-6" \
|
|
65
|
-
--anthropic-api-key "<key>"
|
|
68
|
+
sudo ln -s "$(command -v fireclaw)" /usr/local/bin/fireclaw
|
|
66
69
|
```
|
|
67
70
|
|
|
68
|
-
|
|
71
|
+
## Quick start
|
|
69
72
|
|
|
70
|
-
|
|
73
|
+
```bash
|
|
74
|
+
sudo fireclaw doctor
|
|
71
75
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
| `--disk-size` | `40G` | Resize copied rootfs image to this virtual size before boot |
|
|
83
|
-
| `--api-sock` | `<fc-dir>/firecracker.socket` | Firecracker API socket path (must be unique per VM) |
|
|
84
|
-
| `--anthropic-api-key` | | Anthropic API key |
|
|
85
|
-
| `--openai-api-key` | | OpenAI API key |
|
|
86
|
-
| `--minimax-api-key` | | MiniMax API key |
|
|
87
|
-
| `--skip-browser-install` | `false` | Skip Playwright Chromium install |
|
|
88
|
-
|
|
89
|
-
## Usage
|
|
76
|
+
# Local-only gateway (Telegram disabled):
|
|
77
|
+
sudo fireclaw setup --instance my-bot --model "openai/gpt-5.5" --openai-api-key "<key>"
|
|
78
|
+
|
|
79
|
+
# Telegram bot (DM allowlist, groups disabled):
|
|
80
|
+
sudo fireclaw setup --instance my-bot \
|
|
81
|
+
--telegram-token "<bot-token>" --telegram-users "<comma-separated-user-ids>" \
|
|
82
|
+
--model "openai/gpt-5.5" --openai-api-key "<key>"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Setup fails fast if the model's provider key is missing (`openai/*` → OpenAI key, `anthropic/*` → Anthropic, `minimax/*` → MiniMax). Keys can come from the environment instead of flags, keeping them out of `ps` output:
|
|
90
86
|
|
|
91
87
|
```bash
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
sudo OPENAI_API_KEY="<key>" fireclaw setup --instance my-bot
|
|
89
|
+
```
|
|
94
90
|
|
|
95
|
-
|
|
91
|
+
Setup prints the instance's IP, proxy port, and health on success. Verify any time with:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
96
94
|
sudo fireclaw status my-bot
|
|
95
|
+
curl -fsS http://127.0.0.1:<HOST_PORT>/health
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Commands
|
|
97
99
|
|
|
98
|
-
|
|
99
|
-
sudo fireclaw
|
|
100
|
-
sudo fireclaw
|
|
101
|
-
sudo fireclaw
|
|
100
|
+
```bash
|
|
101
|
+
sudo fireclaw doctor # preflight: commands, /dev/kvm, base images, bridge, capacity
|
|
102
|
+
sudo fireclaw setup <flags...> # create + provision a new instance (flags below)
|
|
103
|
+
sudo fireclaw provision <id> [flags...] # update saved config + rerun guest provisioning
|
|
104
|
+
sudo fireclaw list # fleet table with health
|
|
105
|
+
sudo fireclaw status [id] # detail for one instance (or the fleet)
|
|
106
|
+
sudo fireclaw start|stop|restart <id> # lifecycle; stop persists across host reboots
|
|
107
|
+
sudo fireclaw logs <id> [guest|host] # tail the guest service or host units
|
|
108
|
+
sudo fireclaw shell <id> ["command"] # SSH into the VM, or run one command
|
|
109
|
+
sudo fireclaw token <id> # print the gateway auth token
|
|
110
|
+
sudo fireclaw destroy <id> [--force] # full teardown
|
|
111
|
+
```
|
|
102
112
|
|
|
103
|
-
|
|
104
|
-
sudo fireclaw logs my-bot
|
|
113
|
+
`provision` accepts `--telegram-token`, `--no-telegram`, `--telegram-users`, `--model`, `--skills`, `--openclaw-image`, the three API-key flags, `--skip-browser-install`, and `--browser-install` — e.g. rotate a key with `provision my-bot --openai-api-key "<new>"`, or enable Telegram on a local-only instance later.
|
|
105
114
|
|
|
106
|
-
|
|
107
|
-
sudo fireclaw logs my-bot host
|
|
115
|
+
## Setup flags
|
|
108
116
|
|
|
109
|
-
|
|
110
|
-
|
|
117
|
+
| Flag | Default | Description |
|
|
118
|
+
|------|---------|-------------|
|
|
119
|
+
| `--instance <id>` | required | Instance ID (`[a-z0-9_-]+`) |
|
|
120
|
+
| `--telegram-token <token>` | none | Omit for a local-only gateway with Telegram disabled |
|
|
121
|
+
| `--telegram-users <csv>` | none | Allowed Telegram user IDs; required with `--telegram-token` |
|
|
122
|
+
| `--model <id>` | `openai/gpt-5.5` | OpenClaw model; its provider API key must be set |
|
|
123
|
+
| `--skills <csv>` | `github,tmux,coding-agent,session-logs,skill-creator` | Skill set |
|
|
124
|
+
| `--openclaw-image <image>` | `ghcr.io/openclaw/openclaw:latest` | Container image |
|
|
125
|
+
| `--host-port <n>` | first free port above `BASE_PORT` | Localhost proxy port (>= 1024) |
|
|
126
|
+
| `--vm-vcpu <n>` / `--vm-mem-mib <n>` | `4` / `8192` | VM sizing |
|
|
127
|
+
| `--disk-size <size>` | `40G` | Rootfs resize target |
|
|
128
|
+
| `--api-sock <path>` | `<fc-instance-dir>/firecracker.socket` | Firecracker API socket |
|
|
129
|
+
| `--base-kernel/-rootfs/-initrd <path>` | `<BASE_IMAGES_DIR>/...` | Base image paths |
|
|
130
|
+
| `--anthropic/openai/minimax-api-key <key>` | env var or empty | Provider keys |
|
|
131
|
+
| `--skip-browser-install` | off | Skip Playwright Chromium in the guest |
|
|
111
132
|
|
|
112
|
-
|
|
113
|
-
sudo fireclaw shell my-bot "docker ps"
|
|
133
|
+
## Defaults and state
|
|
114
134
|
|
|
115
|
-
|
|
116
|
-
sudo fireclaw token my-bot
|
|
135
|
+
Networking: bridge `fc-br0` at `172.16.0.1/24`, VM subnet `172.16.0.0/24` (auto-allocation requires `/24`), guest gateway `:18789`, first auto host port `18891` (`BASE_PORT`+1). The proxy is the intended access path; the guest gateway itself binds `0.0.0.0:18789` inside the VM, so keep bridge/subnet reachability private.
|
|
117
136
|
|
|
118
|
-
|
|
119
|
-
curl -fsS http://127.0.0.1:<HOST_PORT>/health
|
|
120
|
-
# If proxy health is flaky, inspect VM-side health too:
|
|
121
|
-
sudo fireclaw status my-bot
|
|
137
|
+
Overridable via environment: `STATE_ROOT` (`/var/lib/fireclaw`), `FC_ROOT` (`/srv/firecracker/vm-demo`), `BASE_PORT` (`18890`), `BRIDGE_NAME`, `BRIDGE_ADDR`, `SUBNET_CIDR`, `SSH_KEY_PATH` (`/home/ubuntu/.ssh/vmdemo_vm`), `BASE_IMAGES_DIR`, `DISK_SIZE`, `API_SOCK`, `OPENCLAW_IMAGE_DEFAULT`.
|
|
122
138
|
|
|
123
|
-
|
|
124
|
-
sudo fireclaw destroy my-bot
|
|
139
|
+
Per instance on disk: state in `STATE_ROOT/.vm-<id>/` (`.env`, `.token`, `provision.vars`, `known_hosts`), runtime in `FC_ROOT/<id>/` (`images/`, `config/`, `logs/`, `start-vm.sh`, `stop-vm.sh`), units in `/etc/systemd/system/firecracker-vmdemo-<id>.service` and `vmdemo-proxy-<id>.service`.
|
|
125
140
|
|
|
126
|
-
|
|
127
|
-
sudo fireclaw destroy my-bot --force
|
|
128
|
-
```
|
|
141
|
+
## Security model
|
|
129
142
|
|
|
130
|
-
|
|
143
|
+
- The isolation boundary is the VM, not a container namespace; no host Docker socket is mounted anywhere.
|
|
144
|
+
- VMs cannot reach each other (isolated bridge ports block IP and ARP between guests, plus an intra-bridge iptables `FORWARD` drop as defense-in-depth where `br_netfilter` is active); each sees only the host gateway and NATed egress.
|
|
145
|
+
- The host proxy is localhost-only and runs unprivileged; guest SSH host keys are pinned per instance and mismatches are reported.
|
|
146
|
+
- Secrets live root-only under `STATE_ROOT` (mode `0600`). The provisioning copies are removed from guest `/tmp` afterwards; the runtime secrets the service needs persist inside the guest in a `0600` env file and the OpenClaw config. The gateway token is never echoed — use `fireclaw token <id>`. Prefer env vars over flags for API keys.
|
|
131
147
|
|
|
132
|
-
|
|
148
|
+
## Troubleshooting
|
|
133
149
|
|
|
134
|
-
|
|
150
|
+
- VM won't start: `sudo journalctl -u firecracker-vmdemo-<id>.service -xe`; check `/dev/kvm` and `sudo fireclaw doctor`.
|
|
151
|
+
- SSH unreachable: `sudo fireclaw status <id>`; a host-key mismatch is reported explicitly — remove `STATE_ROOT/.vm-<id>/known_hosts` if the change is expected. If SSH never comes up, read the boot/console output in `/srv/firecracker/vm-demo/<id>/logs/`.
|
|
152
|
+
- Proxy health down: `curl -v http://127.0.0.1:<port>/health`, then `sudo fireclaw shell <id> "curl -fsS http://127.0.0.1:18789/health"`.
|
|
153
|
+
- Disk pressure in the guest: recreate with a larger `--disk-size`.
|
|
135
154
|
|
|
136
|
-
|
|
155
|
+
## Development
|
|
137
156
|
|
|
138
|
-
|
|
139
|
-
|----------|---------|
|
|
140
|
-
| `STATE_ROOT` | `/var/lib/fireclaw` |
|
|
141
|
-
| `FC_ROOT` | `/srv/firecracker/vm-demo` |
|
|
142
|
-
| `BASE_PORT` | `18890` |
|
|
143
|
-
| `BRIDGE_NAME` | `fc-br0` |
|
|
144
|
-
| `BRIDGE_ADDR` | `172.16.0.1/24` |
|
|
145
|
-
| `SUBNET_CIDR` | `172.16.0.0/24` |
|
|
146
|
-
| `SSH_KEY_PATH` | `~/.ssh/vmdemo_vm` |
|
|
147
|
-
| `BASE_IMAGES_DIR` | `/srv/firecracker/base/images` |
|
|
148
|
-
| `DISK_SIZE` | `40G` |
|
|
149
|
-
| `API_SOCK` | `<FC_ROOT>/<instance>/firecracker.socket` |
|
|
157
|
+
`npm test` runs shell syntax checks plus unit tests for `bin/vm-common.sh`; `npm run pack:check` validates package contents. Contributor conventions live in [AGENTS.md](AGENTS.md).
|
package/bin/fireclaw
CHANGED
|
@@ -13,11 +13,13 @@ ${bold}USAGE${reset}
|
|
|
13
13
|
fireclaw <command> [args...]
|
|
14
14
|
|
|
15
15
|
${bold}COMMANDS${reset}
|
|
16
|
+
${cyan}doctor${reset} Check host prerequisites
|
|
16
17
|
${cyan}setup${reset} <flags...> Create and provision a new VM instance
|
|
18
|
+
${cyan}provision${reset} <id> [flags...] Update saved config and re-run guest provisioning
|
|
17
19
|
${cyan}list${reset} List all instances
|
|
18
20
|
${cyan}status${reset} [id] Show instance status (all or one)
|
|
19
21
|
${cyan}start${reset} <id> Start an instance
|
|
20
|
-
${cyan}stop${reset} <id> Stop an instance
|
|
22
|
+
${cyan}stop${reset} <id> Stop an instance (stays stopped across host reboots)
|
|
21
23
|
${cyan}restart${reset} <id> Restart an instance
|
|
22
24
|
${cyan}logs${reset} <id> [guest|host] Stream logs
|
|
23
25
|
${cyan}shell${reset} <id> [command...] SSH into VM or run a command
|
|
@@ -25,7 +27,10 @@ ${bold}COMMANDS${reset}
|
|
|
25
27
|
${cyan}destroy${reset} <id> [--force] Destroy an instance
|
|
26
28
|
|
|
27
29
|
${bold}EXAMPLES${reset}
|
|
28
|
-
${dim}\$${reset} sudo fireclaw
|
|
30
|
+
${dim}\$${reset} sudo fireclaw doctor
|
|
31
|
+
${dim}\$${reset} sudo fireclaw setup --instance my-bot --openai-api-key <key>
|
|
32
|
+
${dim}\$${reset} sudo fireclaw setup --instance my-bot --telegram-token <tok> --telegram-users <uid> --openai-api-key <key>
|
|
33
|
+
${dim}\$${reset} sudo fireclaw provision my-bot --model openai/gpt-5.5
|
|
29
34
|
${dim}\$${reset} sudo fireclaw list
|
|
30
35
|
${dim}\$${reset} sudo fireclaw status my-bot
|
|
31
36
|
${dim}\$${reset} sudo fireclaw shell my-bot
|
|
@@ -43,9 +48,12 @@ shift || true
|
|
|
43
48
|
|
|
44
49
|
case "$cmd" in
|
|
45
50
|
setup|create|provision)
|
|
51
|
+
if [[ "$cmd" == "provision" ]]; then
|
|
52
|
+
VM_PROVISION_CMD_NAME="fireclaw provision" exec "$SCRIPT_DIR/vm-provision" "$@"
|
|
53
|
+
fi
|
|
46
54
|
VM_SETUP_CMD_NAME="fireclaw setup" exec "$SCRIPT_DIR/vm-setup" "$@"
|
|
47
55
|
;;
|
|
48
|
-
list|status|start|stop|restart|logs|shell|token|destroy)
|
|
56
|
+
doctor|list|status|start|stop|restart|logs|shell|token|destroy)
|
|
49
57
|
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" || "${1:-}" == "help" ]]; then
|
|
50
58
|
VM_CTL_CMD_NAME="fireclaw" exec "$SCRIPT_DIR/vm-ctl" --help
|
|
51
59
|
fi
|