Skip to content

feat: add Linux native platform support#92

Merged
zevorn merged 8 commits intomainfrom
website/add-home-nav
Mar 19, 2026
Merged

feat: add Linux native platform support#92
zevorn merged 8 commits intomainfrom
website/add-home-nav

Conversation

@zevorn
Copy link
Copy Markdown
Owner

@zevorn zevorn commented Mar 19, 2026

Summary

  • Add Linux native platform enabling rt-claw to run directly on Linux hosts without QEMU or cross-compilation
  • New POSIX OSAL backend: pthreads, libcurl HTTP/HTTPS, file-based KV storage (~/.config/rt-claw/kv/)
  • Platform integration: interactive shell with Tab completion, signal handling (SIGINT/SIGTERM), graceful shutdown
  • Full service/tool adaptation: GPIO stubs, scheduler via claw_kv, OTA stub, system info via uname/sysinfo
  • IM services (Feishu/Telegram) migrated from ESP-IDF HTTP to OSAL claw_net_post, Feishu WebSocket via libcurl
  • Complete shutdown lifecycle: claw_deinit() stops all services in reverse order with thread join
  • Cooperative thread cancellation via claw_thread_should_exit() API
  • Interruptible claw_thread_delay_ms() on Linux (200ms polling chunks)
  • Default log off on Linux for clean user experience

Test plan

  • make build-linux compiles successfully (42 targets)
  • make run-linux starts, shows banner, /help lists all commands
  • /ip displays network interfaces via getifaddrs()
  • Tab completion works for /commands in interactive terminal
  • /quit performs graceful shutdown (all services stopped)
  • -Dota=true build links; /ota check/update/rollback returns "unsupported"
  • -Dfeishu=true -Dtelegram=true build links
  • KV persistence: /ai_set model xxx persists across restart
  • Empty IM credentials: init fails, service skipped, no thread spawned

🤖 Generated with Claude Code

zevorn added 8 commits March 18, 2026 23:53
Add POSIX-based OSAL backend (osal/linux/) enabling rt-claw to run
natively on Linux without QEMU or cross-compilation:

- claw_os_linux.c: pthreads, POSIX semaphores, mutex+cond MQ,
  timer threads, cooperative cancellation, ANSI logging
- claw_net_linux.c: libcurl HTTP/HTTPS with native TLS
- claw_kv_linux.c: file KV at ~/.config/rt-claw/kv/ (atomic)

Platform integration (platform/linux/):
- main.c with SIGINT/SIGTERM signal handling
- Interactive shell (fgets/printf) with AI streaming
- No-op board abstraction

Build system:
- osal=linux Meson option + CLAW_PLATFORM_LINUX define
- libcurl dependency auto-detection
- Makefile: build-linux / run-linux targets

Service/tool adaptation:
- net_service.c: getifaddrs() for /ip command
- tool_system.c: uname() + sysinfo()
- tool_net.c: libcurl HTTP tool (HTTPS capable)
- swarm.c: POSIX sockets + /etc/machine-id node ID
- heartbeat.c: sysinfo() memory monitoring
- tool_sched.c: stub fix

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Address all findings from Codex review:

OSAL cooperative cancellation (Finding 4):
- Add claw_thread_should_exit() API to claw_os.h
- Implement via thread-local storage in Linux OSAL
- Add stubs in FreeRTOS/RT-Thread OSAL backends
- Update all long-running threads: gateway, scheduler, swarm
  receiver, AI worker, sched worker, IM workers to poll exit flag

Linux startup/shutdown (Finding 3, 5):
- Add claw_kv_init() + shell_nvs_config_load() to main.c
- KV persistence now works across restart

Thread leak fix (Finding 6):
- Save animation thread handle and join after AI chat

AC-6 tool/service completion (Finding 2):
- Register GPIO stub tools (gpio_set/get/config/blink/stop)
  that return "unsupported on this platform"
- Migrate tool_sched from NVS to claw_kv for cross-platform
  task persistence (list_tasks/schedule_task/remove_task)
- Add Linux OTA stub backend (ota_stub.c) implementing all
  claw_ota_platform_* symbols, -Dota=true builds and links

AC-7 IM service migration (Finding 1):
- Telegram: replace esp_http_client with claw_net_post in
  tg_api_post(), remove platform guard, keep message queue
  and AI worker architecture unchanged
- Feishu: replace esp_http_client REST calls with
  claw_net_post, add libcurl WebSocket transport for Linux
  (curl_ws_recv/curl_ws_send), keep ESP-IDF WebSocket for
  ESP-IDF builds

Build verification:
- Default build: 42/42, 16 tools registered
- -Dota=true: links successfully, 20 tools + OTA stub
- -Dfeishu=true -Dtelegram=true: links successfully

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Graceful shutdown (Finding 1):
- Add claw_deinit() that stops services in reverse init order
- Add stop() to gateway, scheduler, swarm, ai_engine, feishu,
  telegram: save thread handles, join threads, free resources
- Wire stop callbacks into service table in claw_init.c
- main.c calls claw_deinit() after shell exits
- Track per-service init success; skip start() on failed init()
- Add SO_RCVTIMEO to swarm UDP socket for interruptible recv
- Fix ota_check_thread to check claw_thread_should_exit()

IM runtime config (Finding 2):
- Add /telegram_set and /telegram_status shell commands
- Add SHELL_NVS_NS_TELEGRAM KV namespace
- shell_nvs_config_load() now restores Telegram bot token
- telegram_init() returns CLAW_ERROR on missing token
- feishu_init() returns CLAW_ERROR on missing credentials
- claw_init skips start() for services whose init() failed

OTA unsupported semantics (Finding 3):
- Add claw_ota_supported() API (1 on ESP-IDF, 0 on Linux)
- ota_trigger_update() checks platform support upfront
- /ota rollback checks claw_ota_supported() synchronously
- No worker thread spawned on unsupported platforms

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Thread ownership (Finding 1):
- Add sched_tool_stop(): save sched_ai worker handle, join on
  stop, free semaphore/mutex resources
- Add ota_service_stop(): save ota_check thread handle, join
- Add claw_tools_stop() that calls sched_tool_stop()
- Wire tools stop and ota stop into service table
- Verified: /quit now stops all services including tools and OTA

Feishu shutdown safety (Finding 2):
- Reorder feishu_stop(): set ws_connected=0 first, join main
  thread (it exits on next recv timeout since exit flag is set),
  then destroy curl/ws handle after thread is gone
- Eliminates use-after-free race on CURL WebSocket handle

OTA unsupported semantics (Finding 3):
- Add claw_ota_supported() check at entry of tool_ota_check,
  tool_ota_update, tool_ota_rollback
- Restructure cmd_ota(): version always works, all other
  sub-commands check claw_ota_supported() first
- No-URL update path also gated by platform check
- tool_ota_rollback checks return value before reporting ok

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Interruptible delay (Finding 1, 3):
- Linux claw_thread_delay_ms() now sleeps in 200ms chunks,
  checking claw_thread_should_exit() between each chunk
- This makes ALL long waits interruptible: OTA auto-check
  30s boot wait, Feishu 10s token retry, reconnect delays

Feishu retry exit (Finding 1):
- Token fetch retry loop checks claw_thread_should_exit()
  before each retry — breaks immediately on shutdown
- WS connect retry loop checks claw_thread_should_exit()
- Verified: Feishu with bad creds + /quit exits in ~4s
  instead of hanging in 10s retry loop

Heartbeat lifecycle (Finding 2):
- Save last worker thread handle in s_last_worker
- Join previous worker before spawning new one (no leak)
- Add heartbeat_stop(): remove scheduler task, join
  last worker, free mutexes
- Wire heartbeat_stop into service table

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
tool_sched shutdown deadlock (Finding 1):
- Swap ai_engine before tools in service table so reverse
  stop order is: tools → ai_engine (tools stops first while
  AI worker is still alive to process pending requests)
- sched_tool_stop() now removes all scheduler tasks before
  joining worker, and wakes worker via sem_give
- submit_and_wait() in ai_engine now uses 500ms timeout loop
  checking claw_thread_should_exit(), returns CLAW_ERROR on
  shutdown instead of blocking forever
- Verified: persisted sched task + /quit exits cleanly

heartbeat stop race (Finding 2):
- heartbeat_stop() now waits for s_busy==0 after sched_remove
  before destroying resources, preventing use-after-free of
  mutex by in-flight callback
- Verified: heartbeat=true build /quit exits cleanly

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Linux log defaults changed:
- s_log_enabled defaults to 0: logs off by default
- s_log_level = CLAW_LOG_INFO (was DEBUG)
- Users enable via /log on command at runtime

Shell Tab completion for /commands:
- Raw terminal mode (termios) for character-by-character input
- Tab key triggers command name completion for /commands
- Supports backspace, Ctrl-C/Ctrl-D, escape sequence filtering
- Falls back to fgets() when stdin is not a TTY (pipes)
- Temporarily restores cooked mode during AI output and
  command execution for proper line-buffered output
- Reuses find_completions() pattern from zynq-a9 shell

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
@zevorn zevorn merged commit 21f21ea into main Mar 19, 2026
11 checks passed
@zevorn zevorn deleted the website/add-home-nav branch March 19, 2026 01:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant