{"id":47608886,"url":"https://github.com/easyzoom/zoom-shell","last_synced_at":"2026-05-27T13:03:46.666Z","repository":{"id":345736797,"uuid":"1187130482","full_name":"easyzoom/zoom-shell","owner":"easyzoom","description":"Embedded C shell for MCUs: zero malloc, I/O callbacks, linker-section commands, subcommands, vars, users, optional extensions (ai bridge, hexdump, calc, games…). MIT.","archived":false,"fork":false,"pushed_at":"2026-05-27T08:06:39.000Z","size":148,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-27T10:07:28.345Z","etag":null,"topics":["ai","ai-agents","c99","cli","debugging","embedded","embedded-systems","mcu","shell","zero-malloc"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/easyzoom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-20T11:26:40.000Z","updated_at":"2026-05-27T08:09:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/easyzoom/zoom-shell","commit_stats":null,"previous_names":["easyzoom/zoom-shell"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/easyzoom/zoom-shell","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easyzoom%2Fzoom-shell","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easyzoom%2Fzoom-shell/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easyzoom%2Fzoom-shell/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easyzoom%2Fzoom-shell/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/easyzoom","download_url":"https://codeload.github.com/easyzoom/zoom-shell/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easyzoom%2Fzoom-shell/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33566879,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-27T02:00:06.184Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","ai-agents","c99","cli","debugging","embedded","embedded-systems","mcu","shell","zero-malloc"],"created_at":"2026-04-01T19:50:00.777Z","updated_at":"2026-05-27T13:03:46.661Z","avatar_url":"https://github.com/easyzoom.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003e 中文版 / Chinese version: [README.zh.md](./README.zh.md)\n\n# Zoom Shell v1.2\n\n**Embedded enhanced shell** — zero malloc, zero OS dependency, runs on bare-metal microcontrollers.\n\nDistills the best ideas from Zephyr Shell, RT-Thread msh, FreeRTOS CLI, USMART, nr_micro_shell, and letter-shell into three unique features.\n\n**Documentation** (see [docs/](docs/en/) for details):\n\n| Document | Contents |\n|------|------|\n| [docs/README.md](docs/en/README.md) | Documentation index |\n| [docs/getting_started.md](docs/en/getting_started.md) | Build, test, directory layout, and configuration entry points |\n| [docs/extensions_overview.md](docs/en/extensions_overview.md) | Extension modules and macro reference |\n| [docs/porting_general.md](docs/en/porting_general.md) | General porting checklist (linker script, tick, I/O) |\n| [docs/porting_esp_idf.md](docs/en/porting_esp_idf.md) | Dedicated ESP-IDF porting guide |\n| [docs/ai_bridge.md](docs/en/ai_bridge.md) | AI HTTP bridge: switches, callbacks, the `ai` command, gateway, and security |\n\n## Three Distinguishing Features\n\n### 1. Hierarchical subcommand tree\n\nOther embedded shells only support flat commands. Zoom Shell supports unlimited hierarchical nesting of subcommands, and Tab completion walks the tree:\n\n```c\nZOOM_SUBCMD_SET(sub_gpio,\n    ZOOM_SUBCMD(set,    cmd_gpio_set,    \"Set pin level\"),\n    ZOOM_SUBCMD(get,    cmd_gpio_get,    \"Get pin level\"),\n    ZOOM_SUBCMD(toggle, cmd_gpio_toggle, \"Toggle pin\"),\n);\nZOOM_EXPORT_CMD_WITH_SUB(gpio, sub_gpio, \"GPIO operations\",\n                          ZOOM_ATTR_DEFAULT, ZOOM_USER_USER);\n```\n\n```\nzoom\u003e gpio set 13 1\n[OK] GPIO pin 13 set to 1\n```\n\n### 2. Variable observation system\n\nInspect and modify any registered variable in real time over the serial port, similar to Simulink External Mode:\n\n```c\nstatic int32_t pid_kp = 100;\nZOOM_EXPORT_VAR(pid_kp, pid_kp, ZOOM_VAR_INT32, \"PID Kp x100\", ZOOM_VAR_RW, ZOOM_USER_GUEST);\n```\n\n```\nzoom\u003e var list\n  Name             Type     Value        Attr  Description\n  pid_kp           int32    100          [RW]  PID Kp x100\n  motor_speed      float    0.000        [RO]  Motor RPM\nzoom\u003e var set pid_kp 200\n[OK] pid_kp = 200\n```\n\n### 3. Command execution timing\n\nInspired by USMART, automatically measures command execution time:\n\n```\nzoom\u003e perf on\nzoom\u003e some_command\n[OK] some_command (elapsed: 12 ms)\n```\n\n## Feature Comparison\n\n| Feature | letter-shell | nr_micro | FreeRTOS CLI | Zephyr | msh | USMART | **Zoom Shell** |\n|------|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n| Subcommand tree | - | - | - | Y | - | - | **Y** |\n| Variable observation | - | - | - | - | - | Partial | **Y** |\n| Command timing | - | - | - | - | - | Y | **Y** |\n| User permissions | Y | - | - | - | - | - | **Y** |\n| Tab completion | Y | Y | - | Y | - | - | **Y** |\n| History | Y | Y | - | Y | - | - | **Y** |\n| Zero malloc | Y | Y | - | Y | Y | Y | **Y** |\n| Linker-section registration | Y | - | - | Y | Y | - | **Y** |\n| Conditionally-compiled commands | - | - | - | Y | - | - | **Y** |\n| ANSI color output | - | - | - | Y | - | - | **Y** |\n\n## AI HTTP Bridge (optional extension)\n\nWhen the firmware side needs to forward a sentence from the serial port to a **self-hosted HTTP gateway** (which then talks to an LLM, an OpenClaw-compatible service, etc.), enable **`ZOOM_USING_AI_BRIDGE`** and compile and link `extensions/ai_bridge/zoom_shell_ai_bridge.c`.\n\n- **Shell commands**: `ai url \u003chttp(s)://...\u003e` sets the POST endpoint; `ai ask \u003ctext...\u003e` sends the whole text as the request body; `ai status` shows the configuration and whether the callback is ready.\n- **Port implementation**: the library does **not** include a TLS/HTTP implementation. After a successful `zoom_shell_init()`, call **`zoom_ai_bridge_set_post(shell, your_http_post)`**, and inside the callback use ESP-IDF `esp_http_client`, mbedTLS, etc. to send the POST and write the response into a buffer for the shell to print.\n- **Security**: keep the API key in the gateway's environment variables and let the gateway access the cloud API; the firmware should only hold an internal or configurable URL.\n\n**Detailed documentation**: [docs/ai_bridge.md](docs/en/ai_bridge.md). See \"Interoperating with the OpenClaw / Claw ecosystem\" below for how this relates to the OpenClaw / Claw ecosystem.\n\n## Quick Start\n\n### Build and run the x86 demo\n\n```bash\ncd zoom-shell\nmake demo\n./build/zoom_shell_demo\n```\n\n### Port to your MCU\n\n**Step 1: create a configuration file** `zoom_shell_cfg_user.h`\n\n```c\n#define ZOOM_USING_HISTORY        1\n#define ZOOM_USING_USER           1\n#define ZOOM_USING_VAR            1\n#define ZOOM_CMD_MAX_LENGTH       128\n#define ZOOM_HISTORY_MAX_NUMBER   5\n#define ZOOM_PRINT_BUFFER         128\n\n#define ZOOM_GET_TICK()  HAL_GetTick()  /* your millisecond tick */\n```\n\n**Step 2: implement the I/O callbacks**\n\n```c\n#include \"zoom_shell.h\"\n\nzoom_shell_t shell;\nchar shell_buffer[768];  /* 128 * (5+1) = 768 */\n\nint16_t uart_read(char *data, uint16_t len) {\n    /* Read one byte from the UART */\n    (void)len;\n    if (HAL_UART_Receive(\u0026huart1, (uint8_t *)data, 1, HAL_MAX_DELAY) == HAL_OK)\n        return 1;\n    return 0;\n}\n\nint16_t uart_write(const char *data, uint16_t len) {\n    HAL_UART_Transmit(\u0026huart1, (uint8_t *)data, len, HAL_MAX_DELAY);\n    return len;\n}\n```\n\n**Step 3: initialize and run**\n\n```c\n/* Blocking mode (inside an RTOS task) */\nshell.read  = uart_read;\nshell.write = uart_write;\nzoom_shell_init(\u0026shell, shell_buffer, sizeof(shell_buffer));\nzoom_shell_run(\u0026shell);  /* does not return */\n\n/* Or: interrupt-driven mode (bare-metal main loop) */\nshell.read  = uart_read;\nshell.write = uart_write;\nzoom_shell_init(\u0026shell, shell_buffer, sizeof(shell_buffer));\nzoom_shell_print_welcome(\u0026shell);\nzoom_shell_show_prompt(\u0026shell);\n/* Inside the UART interrupt: */\nvoid USART1_IRQHandler(void) {\n    char c;\n    if (HAL_UART_Receive(\u0026huart1, (uint8_t *)\u0026c, 1, 0) == HAL_OK) {\n        zoom_shell_input(\u0026shell, c);\n    }\n}\n```\n\n**Step 4: register commands and variables**\n\n```c\nstatic int cmd_led(zoom_shell_t *sh, int argc, char *argv[]) {\n    if (argc \u003c 1) { zoom_error(sh, \"Usage: led \u003con|off\u003e\\r\\n\"); return -1; }\n    if (argv[0][0] == 'o' \u0026\u0026 argv[0][1] == 'n') HAL_GPIO_WritePin(LED_GPIO, LED_PIN, 1);\n    else HAL_GPIO_WritePin(LED_GPIO, LED_PIN, 0);\n    return 0;\n}\nZOOM_EXPORT_CMD(led, cmd_led, \"Control LED\", ZOOM_ATTR_DEFAULT, ZOOM_USER_GUEST);\n\nstatic int32_t adc_value = 0;\nZOOM_EXPORT_VAR(adc, adc_value, ZOOM_VAR_INT32, \"ADC reading\", ZOOM_VAR_RO, ZOOM_USER_GUEST);\n```\n\n**Step 5: linker script** — add to your `.ld` file:\n\n```ld\n.zoom_command ALIGN(4) : {\n    _zoom_cmd_start = .;\n    KEEP(*(zoomCommand))\n    _zoom_cmd_end = .;\n} \u003e FLASH\n\n.zoom_var ALIGN(4) : {\n    _zoom_var_start = .;\n    KEEP(*(zoomVar))\n    _zoom_var_end = .;\n} \u003e FLASH\n\n.zoom_user ALIGN(4) : {\n    _zoom_user_start = .;\n    KEEP(*(zoomUser))\n    _zoom_user_end = .;\n} \u003e FLASH\n```\n\n## Directory Layout\n\n```\nzoom-shell/\n├── include/\n│   ├── zoom_shell.h          # Main header (data structures + API + export macros)\n│   └── zoom_shell_cfg.h      # Default configuration macros\n├── src/\n│   ├── zoom_shell_core.c     # Core implementation\n│   ├── zoom_shell_cmds.c     # Built-in commands\n│   └── zoom_shell_var.c      # Variable observation system\n├── demo/\n│   └── x86-gcc/              # x86 platform demo\n├── Makefile\n└── README.md\n```\n\n## Configuration System\n\nAll configuration knobs use `#ifndef` to provide defaults; override them at compile time with `-DZOOM_SHELL_CFG_USER='\"your_cfg.h\"'`:\n\n| Macro | Default | Description |\n|---|---|---|\n| `ZOOM_USING_CMD_EXPORT` | 1 | 1 = linker section, 0 = static array |\n| `ZOOM_USING_HISTORY` | 1 | Command history |\n| `ZOOM_USING_USER` | 1 | User / permission system |\n| `ZOOM_USING_VAR` | 1 | Variable observation |\n| `ZOOM_USING_PERF` | 1 | Command timing |\n| `ZOOM_USING_ANSI` | 1 | ANSI escape codes / colors |\n| `ZOOM_USING_LOCK` | 0 | Mutex lock |\n| `ZOOM_CMD_MAX_LENGTH` | 128 | Maximum command-line length |\n| `ZOOM_CMD_MAX_ARGS` | 8 | Maximum number of arguments |\n| `ZOOM_HISTORY_MAX_NUMBER` | 5 | Number of history entries |\n| `ZOOM_MAX_USERS` | 4 | Maximum number of users |\n| `ZOOM_PRINT_BUFFER` | 128 | Formatted-output buffer |\n| `ZOOM_GET_TICK()` | 0 | Millisecond-tick accessor function |\n\n## API Cheat Sheet\n\n```c\n/* Core */\nint  zoom_shell_init(zoom_shell_t *shell, char *buffer, uint16_t size);\nint  zoom_shell_run(zoom_shell_t *shell);\nvoid zoom_shell_input(zoom_shell_t *shell, char data);\nint  zoom_shell_exec(zoom_shell_t *shell, const char *cmd_line);\n\n/* Output */\nzoom_printf(shell, fmt, ...);   /* plain output */\nzoom_info(shell, fmt, ...);     /* [INFO] blue */\nzoom_warn(shell, fmt, ...);     /* [WARN] yellow */\nzoom_error(shell, fmt, ...);    /* [ERR]  red */\nzoom_ok(shell, fmt, ...);       /* [OK]   green */\n\n/* Export macros */\nZOOM_EXPORT_CMD(name, func, desc, attr, level);\nZOOM_EXPORT_CMD_WITH_SUB(name, subcmd_set, desc, attr, level);\nZOOM_SUBCMD_SET(name, ...);\nZOOM_SUBCMD(name, func, desc);\nZOOM_EXPORT_VAR(name, var, type, desc, rw, level);\nZOOM_EXPORT_USER(name, password, level);\n```\n\n## Design Principles\n\n- **Zero malloc** — all memory is statically allocated or supplied by the user\n- **Zero OS dependency** — depends only on `\u003cstdint.h\u003e` `\u003cstdbool.h\u003e` `\u003cstddef.h\u003e` `\u003cstring.h\u003e` `\u003cstdarg.h\u003e`\n- **Pure-callback I/O** — read/write can be wired to UART/USB/SPI/BLE or any other interface\n- **Conditional-compilation trimming** — every functional module can be toggled independently; minimal configuration is around 2 KB of ROM\n\n## Interoperating with the OpenClaw / Claw Ecosystem\n\nThe firmware-side **`ai` command and HTTP callback** are described above under \"**AI HTTP Bridge (optional extension)**\"; this section covers how responsibilities are split with host-side tooling.\n\n**OpenClaw, NullClaw, ZeroClaw, Mimiclaw** and similar projects belong to the \"self-hosted AI assistant / multi-channel orchestration\" category (typically Node, Rust, or Zig, or MCU firmware with a network stack). They have **different responsibilities** from Zoom Shell (a serial debugging command line) and **will not** be merged into this repository's core as submodules.\n\nRecommended ways to combine them:\n\n| Approach | Description |\n|------|------|\n| **Serial bridge (host side)** | The device runs Zoom Shell while OpenClaw or similar tools run on the PC; text is sent over the serial port to the device, and the device side still goes through the `read`/`write` callbacks. No library changes needed — just agree on the baud rate and line protocol in documentation or scripts. |\n| **Optional `ai` extension (firmware side)** | With `ZOOM_USING_AI_BRIDGE` enabled, you provide an **HTTP POST callback** (implemented by you on top of ESP-IDF / mbedTLS / etc.) and can use `ai url` / `ai ask` to POST a line of text to a self-hosted gateway, which then forwards it to any LLM or OpenClaw-compatible service. The library does **not** include a TLS/HTTP implementation, avoiding a hard dependency on any network stack. |\n\nRelationship to projects like **Mimiclaw** (\"MCU + WiFi + LLM\"): **conceptually complementary** — you can borrow their approach to networking and key management; if you need similar capabilities, integrate the platform SDK yourself on top of this extension, and **do not** claim compatibility with their upstream APIs.\n\n## CI / Releases (GitHub Actions)\n\nPushes to `main` / `master` and pull requests automatically run `make test` and `make demo`.\n\n**Cut a new release** (run at the repository root):\n\n```bash\ngit tag -a v1.2.0 -m \"Zoom Shell 1.2.0\"\ngit push origin v1.2.0\n```\n\nPushing a tag that matches `v*.*.*` triggers the tests again, uses `git archive` to produce `zoom-shell-\u003cversion\u003e.tar.gz` / `.zip`, attaches `zoom-shell-\u003cversion\u003e-demo-linux-x86_64` (the demo built on Ubuntu) and `SHA256SUMS`, and automatically creates and uploads the GitHub Release.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasyzoom%2Fzoom-shell","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feasyzoom%2Fzoom-shell","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasyzoom%2Fzoom-shell/lists"}