Skills seed
Grow firmware on any hardware through HTTP — upload C, compile on device, apply with watchdog rollback
git clone https://github.com/openclaw/skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/awis13/seed" ~/.claude/skills/clawdbot-skills-seed && rm -rf "$T"
skills/awis13/seed/SKILL.mdseed.c — Self-Growing Firmware
Source: https://github.com/Awis13/seed
You have access to a seed node — a minimal C firmware with an HTTP API that you can grow by writing and compiling new firmware on the device.
First steps
If the user hasn't given you a node address and token, ask them:
- Do they already have a seed node running? If so, get the IP and token.
- If not, offer to deploy one. All they need is a Linux machine with gcc:
# On the target machine (Pi, VPS, any Linux box): curl -fsSL https://raw.githubusercontent.com/Awis13/seed/main/seeds/linux/seed.c -o seed.c gcc -O2 -o seed seed.c ./seed 8080 # Token will be printed — give it to the agent
The seed binary is ~70KB, zero dependencies beyond libc.
Connecting
The node prints its address and token on startup. If you don't know them:
# The user will provide the address, or: curl http://<ip>:8080/health # no auth needed curl http://<ip>:8080/skill # full connection details + token
All requests except
/health need: Authorization: Bearer <token>
What you can do
1. Discover the hardware
curl -H "Authorization: Bearer $TOKEN" http://$HOST/capabilities
Returns: arch, CPU, RAM, disk, temperature, GPIO, I2C, serial ports, USB devices, WiFi, Bluetooth, WireGuard — everything the node has.
2. Read the running firmware
curl -H "Authorization: Bearer $TOKEN" http://$HOST/firmware/source
Returns the C source code currently running on the node.
3. Write new firmware
curl -H "Authorization: Bearer $TOKEN" \ -X POST --data-binary @new_firmware.c \ http://$HOST/firmware/source
Upload C source code. The node saves it for compilation.
4. Compile on the device
curl -H "Authorization: Bearer $TOKEN" -X POST http://$HOST/firmware/build
The node runs
gcc -O2 on itself. Check errors with GET /firmware/build/logs.
5. Apply (hot-swap)
curl -H "Authorization: Bearer $TOKEN" -X POST http://$HOST/firmware/apply
Atomic binary swap. 10-second watchdog — if the new firmware fails the health check, the old version is restored automatically.
API reference
| Method | Path | Description |
|---|---|---|
| GET | /health | Alive check (no auth) |
| GET | /capabilities | Hardware fingerprint |
| GET | /config.md | Node config (markdown) |
| POST | /config.md | Update config |
| GET | /events | Event log (?since=unix_ts) |
| GET | /firmware/version | Version, build date, uptime |
| GET | /firmware/source | Read source code |
| POST | /firmware/source | Upload new source |
| POST | /firmware/build | Compile (gcc -O2) |
| GET | /firmware/build/logs | Compiler output |
| POST | /firmware/apply | Apply + watchdog rollback |
| GET | /skill | Generate this file with live connection details |
Writing firmware
Constraints:
- C only, libc only — no external libraries
must compile with no extra flagsgcc -O2 -o seed seed.c- Single-threaded, one request at a time
- Max request body: 64KB
- 3 failed applies -> /firmware/apply locks (POST /firmware/apply/reset to unlock)
Handler pattern:
if (strcmp(req.path, "/myendpoint") == 0 && strcmp(req.method, "GET") == 0) { char resp[4096]; snprintf(resp, sizeof(resp), "{\"key\":\"value\"}"); json_resp(fd, 200, "OK", resp); goto done; }
Available functions:
— send JSON responsejson_resp(fd, code, status, json)
— send plain texttext_resp(fd, code, status, text)
— send anythingrespond(fd, code, status, content_type, body, len)
— read file, returns malloc'd bufferfile_read(path, &len)
— write filefile_write(path, data, len)
— run command, capture outputcmd_out(shell_cmd, buf, bufsize)
— log eventevent_add(fmt, ...)
Request struct:
req.method, req.path, req.body (malloc'd, may be NULL),
req.body_len, req.content_length. Path includes query string.
Auth is already checked before your handler.
/health is always public.
Capabilities example
{ "type": "seed", "version": "0.1.0", "seed": true, "hostname": "raspberrypi", "arch": "armv6l", "cpus": 1, "mem_mb": 512, "disk_mb": 14000, "temp_c": 42.3, "board_model": "Raspberry Pi Zero W Rev 1.1", "has_gcc": true, "net_interfaces": ["eth0", "wlan0", "usb0"], "serial_ports": ["/dev/ttyAMA0"], "i2c_buses": ["/dev/i2c-1"], "gpio_chips": ["/dev/gpiochip0"], "has_wifi": true, "has_bluetooth": true, "endpoints": ["/health", "/capabilities", "/config.md", ...] }
Use this to decide what the node can do and what firmware to write.
Typical workflow
— is it alive?GET /health
— what hardware does it have?GET /capabilities
— read the current codeGET /firmware/source- Write new firmware that adds the endpoints you need
— upload itPOST /firmware/source
— compilePOST /firmware/build
— check for errorsGET /firmware/build/logs
— deploy (auto-rollback on failure)POST /firmware/apply- Test the new endpoints
- Repeat — the grown firmware still has
, so you can grow it again/firmware/*