Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 55 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ pkg/cron/ ← Scheduled tasks (reminders etc)
pkg/heartbeat/ ← Periodic heartbeat (checks HEARTBEAT.md)
pkg/tools/ ← Agent tools (exec, read_file, write_file, web, etc)
pkg/skills/ ← Skill system (installable capabilities)
workspace/ ← Embedded templates (USER.md, IDENTITY.md, AGENT.md)
firmware/overlay/ ← Files baked into Luckfox firmware image
workspace/ ← Workspace templates embedded into binary via go:embed
firmware/overlay/etc/ ← Init script + SSH banner baked into firmware rootfs.img
```

## Critical Hardware Constraints
Expand All @@ -43,7 +43,7 @@ firmware/overlay/ ← Files baked into Luckfox firmware image
- **CLI**: Added `luckyclaw stop`, `restart`, `gateway -b` (background)
- **Init script**: Auto-starts gateway on boot with OOM protection
- **SSH banner**: Shows ASCII art, status, memory, all commands on login
- **Default model**: `google/gemini-2.0-flash-exp:free` (free tier)
- **Default model**: `stepfun/step-3.5-flash:free` (free tier)
- **Defaults**: `max_tokens=16384`, `max_tool_iterations=25` (tuned for web search headroom)

### What We Did NOT Change
Expand Down Expand Up @@ -87,7 +87,27 @@ A shallow clone of the upstream PicoClaw repo is kept at `picoclaw-latest/` (git
### 12. Log File Destinations & Workspace Paths
- **Gateway log**: `/var/log/luckyclaw.log` (stdout/stderr from the init script). The init script uses an `sh -c "exec ..."` wrapper because BusyBox's `start-stop-daemon -b` redirects fds to `/dev/null` before shell redirects take effect.
- **Heartbeat log**: `<workspace>/heartbeat.log` (written directly by the heartbeat service, not stdout).
- **Runtime workspace**: `/oem/.luckyclaw/workspace/` — this is where the bot actually reads/writes data at runtime. The firmware overlay installs template files to `/root/.luckyclaw/workspace/` but these are NOT used at runtime because `luckyclaw onboard` creates its config at `/oem/`. Any default template changes must also be reflected in `createDefaultHeartbeatTemplate()` in `pkg/heartbeat/service.go`.
- **Runtime workspace**: `/oem/.luckyclaw/workspace/` — this is where the bot reads/writes data at runtime. `luckyclaw onboard` creates it by extracting the `workspace/` directory that is **embedded directly into the binary** via `go:embed` at compile time. `firmware/overlay/root/` is NOT involved in this — nothing reads `/root/.luckyclaw/` at runtime.

### 13. Firmware Overlay Structure
Only two parts of `firmware/overlay/` are meaningful:
- `firmware/overlay/etc/` — init script, SSH banner, timezone. **Must be tracked in git.** Gets baked into `rootfs.img`.
- `firmware/overlay/root/` — **Dead weight. Do not use.** Nothing reads `/root/.luckyclaw/` at runtime; workspace data comes from the binary embed.
- `firmware/overlay/usr/` — **Not tracked in git.** The ARM binary is compiled at SDK build time and placed here; it is not stored in the repo.

### 14. Binary-Only Updates (No Reflash Required)
The binary at `/usr/bin/luckyclaw` lives on the writable `rootfs` partition and can be replaced via SCP at any time without reflashing the firmware. This is how all development deploys work. Because `workspace/` is embedded in the binary, updating the binary also delivers new/updated skills and templates to users when they next run `luckyclaw onboard`. This architecture makes **over-the-air (OTA) auto-update** possible: the binary could check GitHub Releases, download a new ARM build, kill itself, overwrite `/usr/bin/luckyclaw`, and restart via the init script.

### 15. Project Philosophy — Conservative by Design
LuckyClaw is **not** trying to be PicoClaw or nanobot. It is PicoClaw's simpler, more conservative sibling — built for normal people who want a cheap, reliable AI assistant, not developers who need MCP, vision pipelines, or Web UIs.

**Upstream evaluation policy**: When asked to check what PicoClaw is up to or evaluate upstream changes, apply this filter:
- ✅ **Always port**: Security fixes, crash fixes, data loss fixes, reliability improvements
- ✅ **Consider porting**: Genuinely useful features that benefit everyday users (e.g., better memory handling, improved session stability, Telegram reliability fixes)
- ❌ **Never port**: Feature additions targeting developers or power users (MCP, vision, Web UI, system tray, new channels, new providers, model routing)

When in doubt, ask: *"Would a normal person on a $10 board benefit from this?"* If the answer is no, leave it upstream.


## Build & Deploy

Expand All @@ -101,7 +121,7 @@ This runs `deps`, `fmt`, `vet`, and the full `test` suite in one command.
### Cross-Compile
```bash
GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=0 \
go build -ldflags "-s -w -X main.version=0.2.0" \
go build -ldflags "-s -w -X main.version=0.2.x" \
-o build/luckyclaw-linux-arm ./cmd/luckyclaw
```

Expand Down Expand Up @@ -130,10 +150,36 @@ luckyclaw gateway -b # Start in background
luckyclaw stop # Stop cleanly
```

### SDK Overlay (for firmware builds)
Keep these directories in sync:
- `firmware/overlay/` — canonical overlay files
- `luckfox-pico-sdk/project/cfg/BoardConfig_IPC/overlay/luckyclaw-overlay/` — SDK build overlay
### Build Distributable Firmware Image

A distributable `.img` bundles the ARM binary (with `workspace/` embedded) + the init script + SSH banner into a single flashable file. Steps:

```bash
# 1. Build ARM binary (go:embed bakes workspace/ into it automatically)
make build-arm
# Output: build/luckyclaw-linux-arm

# 2. Copy binary into the SDK overlay (untracked — do this every time before building image)
cp build/luckyclaw-linux-arm \
luckfox-pico-sdk/project/cfg/BoardConfig_IPC/overlay/luckyclaw-overlay/usr/bin/luckyclaw
chmod +x luckfox-pico-sdk/project/cfg/BoardConfig_IPC/overlay/luckyclaw-overlay/usr/bin/luckyclaw

# 3. Build the firmware image
cd luckfox-pico-sdk && ./build.sh

# 4. Output image is at:
# luckfox-pico-sdk/IMAGE/<timestamp>/IMAGES/update.img
# Rename for distribution: luckyclaw-luckfox_pico_plus_rv1103-vX.Y.Z.img
```

> **Note:** The SDK overlay `etc/` is kept in sync with `firmware/overlay/etc/` in the repo. If you modify the init script or SSH banner, copy the changes to both locations before building.

> **What's in the image:** `update.img` = kernel + rootfs (containing `/usr/bin/luckyclaw` with embedded workspace) + oem partition. When a user runs `luckyclaw onboard` after flashing, the embedded workspace is extracted to `/oem/.luckyclaw/workspace/`.

### SDK Overlay Sync
The SDK overlay `etc/` must stay in sync with the repo:
- `firmware/overlay/etc/` — canonical, tracked in git
- `luckfox-pico-sdk/project/cfg/BoardConfig_IPC/overlay/luckyclaw-overlay/etc/` — SDK copy, NOT tracked in git

## File Map

Expand Down
12 changes: 12 additions & 0 deletions IMPROVEMENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ Items listed here are planned enhancements that are not yet scheduled for implem

## Installation / Deployment

### `luckyclaw install` Command
**Priority**: High
**Description**: Create a new subcommand `luckyclaw install` that automates the setup of LuckyClaw on a stock Linux/Buildroot environment. It should:
1. Extract and write the init script to `/etc/init.d/S99luckyclaw` (using `go:embed` from the binary).
2. Extract and write the SSH banner to `/etc/profile.d/luckyclaw-banner.sh`.
3. Configure the binary for OOM protection (calling `oom_score_adj` logic).
4. Ensure the default `/oem/.luckyclaw/workspace` exists (calling `onboard` logic if missing).

**Benefit**: Enables a "one-liner" installation for users who already have a working board running stock firmware, without requiring them to reflash using our custom image. Supports the "conservative brother" vision by making the tool easier to adopt on any ARM/Linux hardware.

**Blocked by**: Nothing.

### OTA Binary Updates (No Reflash)
**Priority**: Medium
**Description**: The LuckyClaw binary at `/usr/bin/luckyclaw` can be replaced via SCP without reflashing the entire firmware, since user data lives on `/oem/.luckyclaw/` (a separate partition). An `luckyclaw update` command could check the GitHub Releases API for the latest version, download the matching ARM binary, replace itself, and restart — all without touching config, sessions, cron jobs, or memory.
Expand Down
126 changes: 89 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<h1>🦞 LuckyClaw: AI Assistant for Luckfox Pico</h1>

<h3>One-stop AI firmware for Luckfox Pico boards</h3>
<h3>The streamlined AI companion for Luckfox hardware.</h3>

<p>
<img src="https://img.shields.io/badge/Go-1.25+-00ADD8?style=flat&logo=go&logoColor=white" alt="Go">
Expand All @@ -15,33 +15,61 @@

---

LuckyClaw is a purpose-built AI assistant for [Luckfox Pico](https://wiki.luckfox.com/Luckfox-Pico/Luckfox-Pico-quick-start/) boards. It's a fork of [PicoClaw](https://github.com/sipeed/picoclaw), optimized specifically for Luckfox hardware with baked-in memory management, interactive setup, and pre-built firmware images.
LuckyClaw is a streamlined, self-contained AI assistant purpose-built for the [Luckfox Pico](https://wiki.luckfox.com/Luckfox-Pico/Luckfox-Pico-quick-start/) ecosystem. While based on the excellent work of [PicoClaw](https://github.com/sipeed/picoclaw), LuckyClaw prioritizes absolute stability and ease of use for everyday users over the complex feature velocity of its upstream counterpart.

**What makes it different from PicoClaw:**
**Who it's for:** LuckyClaw is designed for those who want a reliable, 24/7 digital companion on Telegram or Discord without the overhead of manual compilation, complex configurations, or dedicated server maintenance. If you have a Luckfox board, you have a professional-grade AI assistant.

- 🔧 **Pre-built firmware** — Flash and go, no SDK required for end-users
- 🧙 **Interactive onboarding** — `luckyclaw onboard` walks you through API key, model, timezone, and Telegram setup
- 🧠 **Memory-optimized** — GOGC and GOMEMLIMIT baked into the binary for 64MB boards
- 📟 **SSH banner** — See gateway status and available commands on login
- 🦞 **Board-aware** — Detects Luckfox Pico model, shows board-specific info in `status`
- 🌍 **Timezone-aware** — Embedded timezone database, correct local time on any board
- 📎 **File attachments** — Send files directly to Telegram via the `send_file` tool
- ⚡ **Iteration budgeting** — Agent knows its tool limits, reserves capacity for responses
**What makes it different:**

- 🔧 **Pre-built firmware** — Flash and go, no SDK or compilation required
- 🧙 **Interactive onboarding** — `luckyclaw onboard` walks you through everything in 2 minutes
- 🧠 **Memory-optimized** — Tuned specifically for 64MB boards, not general-purpose servers
- 📟 **SSH banner** — See gateway status and commands on every login
- 🌍 **Timezone-aware** — Correct local time on the board, no `/usr/share/zoneinfo` needed
- 📎 **File attachments** — Send files directly via Telegram
- 🤙 **Conservative by design** — Fewer features, fewer surprises, fewer crashes

> [!NOTE]
> LuckyClaw is built on top of [PicoClaw](https://github.com/sipeed/picoclaw) by [Sipeed](https://sipeed.com). All credit for the core AI agent engine goes to the PicoClaw team and the original [nanobot](https://github.com/HKUDS/nanobot) project.
> LuckyClaw is built on top of [PicoClaw](https://github.com/sipeed/picoclaw) by [Sipeed](https://sipeed.com). PicoClaw is the upstream project — LuckyClaw is the simpler, more opinionated fork optimized for Luckfox hardware and everyday users. We cherry-pick stability fixes and genuinely useful features from upstream; we don't try to keep pace with every new addition.

## ⚡ Quick Start (End Users)

### Supported Boards
### Option A: Flash Pre-Built Firmware (Recommended for Beginners)

Download the firmware image for your board from [GitHub Releases](https://github.com/jamesrossdev/luckyclaw/releases) and follow the [LuckyClaw Flashing Guide](doc/FLASHING_GUIDE.md).

After flashing, connect via SSH and run:
```bash
luckyclaw onboard
```

### Option B: Binary Install on Existing Luckfox (No Reflash)

If your board is already running Luckfox Buildroot, you can install LuckyClaw directly:

```bash
# Download the ARMv7 binary
wget https://github.com/jamesrossdev/luckyclaw/releases/latest/download/luckyclaw-linux-arm -O /usr/bin/luckyclaw
chmod +x /usr/bin/luckyclaw

# Run onboard setup
luckyclaw onboard

# Start in background
luckyclaw gateway -b
```


| Board | Chip | Image |
|-------|------|-------|
| **Luckfox Pico Plus** | RV1103 | `luckyclaw-luckfox_pico_plus_rv1103-vX.X.X.img` |
| **Luckfox Pico Pro Max** | RV1106 | `luckyclaw-luckfox_pico_pro_max_rv1106-vX.X.X.img` |
| **Luckfox Pico Pro** | RV1106 | `luckyclaw-luckfox_pico_pro_max_rv1106-vX.X.X.img`* |
| **Luckfox Pico Max** | RV1106 | `luckyclaw-luckfox_pico_pro_max_rv1106-vX.X.X.img`* |

\* *The Pico Pro (128MB RAM) and Pico Max (256MB RAM) share the same RV1106 SoC and firmware image.*

> [!IMPORTANT]
> LuckyClaw currently only supports these two boards. Other Luckfox variants (Pico Mini, Pico Zero, etc.) are untested and may not work.
> LuckyClaw currently only supports these three board variants. Other Luckfox variants (Pico Mini, Pico Zero, etc.) are untested and may not work.

### 1. Flash the firmware

Expand Down Expand Up @@ -288,53 +316,77 @@ Keep the codebase clean using the integrated Makefile targets:

### Build firmware image

The `firmware/` directory contains the SDK overlay files that get baked into the firmware image:
The firmware overlay only contains OS-level files that get baked into `rootfs.img`. The **workspace templates** (`SOUL.md`, skills, etc.) are **embedded directly into the binary** via `go:embed workspace` — so every binary already carries the full workspace inside it. Users get workspace files by running `luckyclaw onboard`, which extracts them to `/oem/.luckyclaw/workspace/`.

```
firmware/overlay/
├── etc/
│ ├── init.d/S99luckyclaw # Auto-start on boot
│ ├── profile.d/luckyclaw-banner.sh # SSH login banner
│ └── ssl/certs/ca-certificates.crt # TLS certificates
├── root/.luckyclaw/
│ ├── config.json # Default config
│ └── workspace/ # Default workspace files
└── usr/bin/luckyclaw # The binary
└── etc/
├── init.d/S99luckyclaw # Auto-start on boot
├── profile.d/luckyclaw-banner.sh # SSH login banner
└── ssl/certs/ca-certificates.crt # TLS certificates
```

To build a firmware image:
To build a distributable firmware image:

1. **Build the ARM binary**: `make build-arm`
2. **Clone the SDK**: `git clone https://github.com/LuckfoxTECH/luckfox-pico.git luckfox-pico-sdk`
3. **Copy overlay**: `cp -r firmware/overlay/* luckfox-pico-sdk/project/cfg/BoardConfig_IPC/overlay/luckyclaw-overlay/`
4. **Copy binary**: `cp build/luckyclaw-linux-arm luckfox-pico-sdk/project/cfg/BoardConfig_IPC/overlay/luckyclaw-overlay/usr/bin/luckyclaw`
5. **Build image**:
1. **Build the ARM binary** (workspace is embedded automatically):
```bash
cd luckfox-pico-sdk
./build.sh lunch # Select your board config
./build.sh
make build-arm
# Output: build/luckyclaw-linux-arm
```

The firmware image will be in `luckfox-pico-sdk/output/image/`.
2. **Clone the SDK** (one-time setup):
```bash
git clone https://github.com/LuckfoxTECH/luckfox-pico.git luckfox-pico-sdk
```

3. **Sync the `etc/` overlay to the SDK** (do this if init script or banner changed):
```bash
cp -r firmware/overlay/etc/ \
luckfox-pico-sdk/project/cfg/BoardConfig_IPC/overlay/luckyclaw-overlay/etc/
```

4. **Copy the ARM binary into the SDK overlay**:
```bash
cp build/luckyclaw-linux-arm \
luckfox-pico-sdk/project/cfg/BoardConfig_IPC/overlay/luckyclaw-overlay/usr/bin/luckyclaw
chmod +x \
luckfox-pico-sdk/project/cfg/BoardConfig_IPC/overlay/luckyclaw-overlay/usr/bin/luckyclaw
```

5. **Build the firmware image**:
```bash
cd luckfox-pico-sdk && ./build.sh
```

6. **Find the output image**:
```
luckfox-pico-sdk/IMAGE/<timestamp>/IMAGES/update.img
```
Rename it: `luckyclaw-luckfox_pico_plus_rv110x-vX.Y.Z.img` depending on your board and version.

When a user flashes this image and runs `luckyclaw onboard`, the embedded workspace is extracted to `/oem/.luckyclaw/workspace/`.

### Project structure

```
luckyclaw/
├── cmd/luckyclaw/main.go # Entry point, CLI, and onboarding wizard
├── cmd/luckyclaw/main.go # Entry point, CLI, onboarding wizard (embeds workspace/)
├── pkg/
│ ├── agent/ # Core agent loop and context builder
│ ├── bus/ # Internal message bus
│ ├── channels/ # Telegram, Discord, and other messaging integrations
│ ├── config/ # Configuration and system settings
│ ├── providers/ # LLM provider implementations (OpenRouter, etc.)
│ ├── skills/ # Skill loader and installer
│ ├── tools/ # Agent tools (shell, file, i2c, spi, send_file)
│ └── ...
├── firmware/ # SDK overlay files and init scripts
├── workspace/ # Default templates for the agent workspace
├── firmware/overlay/etc/ # Init script + SSH banner baked into firmware image
├── workspace/ # Templates embedded into binary via go:embed
└── assets/ # Documentation images and media
```



### Performance tuning

LuckyClaw automatically sets `GOGC=20` and `GOMEMLIMIT=24MiB` at startup for memory-constrained boards. These can be overridden via environment variables if your board has more RAM.
Expand Down
Binary file removed assets/arch.jpg
Binary file not shown.
Binary file removed assets/clawdchat-icon.png
Binary file not shown.
Binary file removed assets/licheervnano.png
Binary file not shown.
Binary file removed assets/logo.jpg
Binary file not shown.
Binary file modified assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed assets/picoclaw_code.gif
Binary file not shown.
Binary file removed assets/picoclaw_detect_person.mp4
Binary file not shown.
Binary file removed assets/picoclaw_mem.gif
Binary file not shown.
Binary file removed assets/picoclaw_memory.gif
Binary file not shown.
Binary file removed assets/picoclaw_scedule.gif
Binary file not shown.
Binary file removed assets/picoclaw_search.gif
Binary file not shown.
24 changes: 21 additions & 3 deletions cmd/luckyclaw/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ import (
var embeddedFiles embed.FS

var (
version = "dev"
version = "v0.2.1"
gitCommit string
buildTime string
goVersion string
Expand Down Expand Up @@ -342,7 +342,7 @@ func onboard() {
}
}
if total > 0 {
fmt.Printf(" Memory: %dMB / %dMB available\n", avail/1024, total/1024)
fmt.Printf(" Memory: %dMB available / %dMB total\n", avail/1024, total/1024)
}
}
fmt.Println()
Expand Down Expand Up @@ -999,6 +999,24 @@ func gatewayCmd() {
// Inject channel manager into agent loop for command handling
agentLoop.SetChannelManager(channelManager)

// Wire Discord moderation tool callbacks from the live DiscordChannel
if discordCh, ok := channelManager.GetChannel("discord"); ok {
if dc, ok := discordCh.(*channels.DiscordChannel); ok {
if tool, ok := agentLoop.GetTool("discord_delete_message"); ok {
if dt, ok := tool.(*tools.DiscordDeleteMessageTool); ok {
dt.SetDeleteCallback(dc.DeleteMessage)
logger.InfoC("discord", "Delete message callback wired to Discord channel")
}
}
if tool, ok := agentLoop.GetTool("discord_timeout_user"); ok {
if tt, ok := tool.(*tools.DiscordTimeoutUserTool); ok {
tt.SetTimeoutCallback(dc.TimeoutUser)
logger.InfoC("discord", "Timeout user callback wired to Discord channel")
}
}
}
}

var transcriber *voice.GroqTranscriber
if cfg.Providers.Groq.APIKey != "" {
transcriber = voice.NewGroqTranscriber(cfg.Providers.Groq.APIKey)
Expand Down Expand Up @@ -1124,7 +1142,7 @@ func statusCmd() {
}
}
if total > 0 {
fmt.Printf(" Memory: %dMB / %dMB available\n", avail/1024, total/1024)
fmt.Printf(" Memory: %dMB available / %dMB total\n", avail/1024, total/1024)
}
}

Expand Down
Loading
Loading