Agent skill

Janos Uart App

by C5Lab in C5Lab/M5MonsterC5-CardputerADV

Build LVGL touchscreen applications that communicate with JanOS ESP32C5 firmware over UART.

MITAuto-check passedDevelopment

Install Janos Uart App

skills CLI
$ npx skills add C5Lab/M5MonsterC5-CardputerADV --skill janos-uart-app -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install C5Lab/M5MonsterC5-CardputerADV janos-uart-app --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/C5Lab/M5MonsterC5-CardputerADV.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.github/skills/janos-uart-app .claude/skills/janos-uart-app && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
janos-uart-app
GitHub stars
232
Token cost
~4.7k tokens
SKILL.md length
674 words
Files
2
Skills in repo
1
Repo updated
First seen
Licence
MIT

At a glance

Build LVGL touchscreen applications that communicate with JanOS ESP32C5 firmware over UART.

  • Works in 8 steps: Scan-Select-Attack → Evil Twin Flow → Connect-ListHosts-ARPBan → …
  • Creating screens for Tab5
  • SKILL.md covers Architecture, UART Setup, Sending Commands and Reading & Parsing Responses, plus 4 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md

What it does

Janos Uart App is an agent skill from C5Lab/M5MonsterC5-CardputerADV. Build LVGL touchscreen applications that communicate with JanOS ESP32C5 firmware over UART. Use when creating screens for Tab5, CoreS3, Cardputer, or any ESP-IDF device that sends UART commands like scannetworks, startdeauth, listhosts, showpass. Covers screen building, UART parsing, attack flows, and navigation patterns.

Its SKILL.md is about 4.7k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `commands-reference.md`).

It sits in Development. It works with ESP32. The licence is MIT.

When your agent uses it

  • Creating screens for Tab5
  • Any ESP-IDF device that sends UART commands like scannetworks

Example prompts

  • “/janos-uart-app”

Workflow steps

8 steps, taken from the step headings in SKILL.md.

  1. Scan-Select-Attack
  2. Evil Twin Flow
  3. Connect-ListHosts-ARPBan
  4. Portal/Karma Setup
  5. Wardrive
  6. Beacon Spam from SSID File
  7. PCAP Capture
  8. Bluetooth Locate

What it can do on your machine

Read from SKILL.md and the folder at commit ad750dd. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are c).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Janos Uart App loads about 4.7k tokens when it runs. Until then it costs about 86 tokens; SKILL.md has 674 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~86
When it runs · the whole SKILL.md, loaded when a task matches
~4.7k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from C5Lab/M5MonsterC5-CardputerADV at commit ad750dd, republished under its MIT licence (© C5Lab). 674 words, ~4,668 tokens.

Download SKILL.mdSave it as .claude/skills/janos-uart-app/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
janos-uart-app
description
Build LVGL touchscreen applications that communicate with JanOS ESP32C5 firmware over UART. Use when creating screens for Tab5, CoreS3, Cardputer, or any ESP-IDF device that sends UART commands like scan_networks, start_deauth, list_hosts, show_pass. Covers screen building, UART parsing, attack flows, and navigation patterns.

JanOS UART Application Builder

Guide for building ESP-IDF + LVGL applications that control JanOS firmware on ESP32C5 via UART. Reference implementation: /Users/janulrich/kod/dev/tabgit/M5MonsterC5-Tab5/main/main.c

For the complete command list, see commands-reference.md.

Architecture

┌────────────────────────────────┐        UART (115200 8N1)        ┌──────────────────────┐
│  UI Device (Tab5/CoreS3/etc)   │ ──────────────────────────────> │  JanOS on ESP32C5    │
│  - LVGL touchscreen            │ <────────────────────────────── │  - WiFi radio        │
│  - Sends text commands         │        Text responses           │  - BLE radio         │
│  - Parses text responses       │                                 │  - SD card           │
│  - FreeRTOS tasks for I/O      │                                 │  - GPS (optional)    │
└────────────────────────────────┘                                 └──────────────────────┘

JanOS exposes a text CLI over UART. The UI app sends commands like scan_networks\r\n and parses the multi-line text responses to update the screen.

UART Setup

c
#define UART_NUM          UART_NUM_1
#define UART_BAUD_RATE    115200
#define UART_BUF_SIZE     4096

static void uart_init(void) {
    const uart_config_t uart_config = {
        .baud_rate = UART_BAUD_RATE,
        .data_bits = UART_DATA_8_BITS,
        .parity    = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_DEFAULT,
    };
    uart_driver_install(UART_NUM, UART_BUF_SIZE * 2, 0, 0, NULL, 0);
    uart_param_config(UART_NUM, &uart_config);
    uart_set_pin(UART_NUM, tx_pin, rx_pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
}

Pin assignments (configurable, stored in NVS):

ConnectorTXRXUsage
Grove5354UART1 (primary)
M5Bus3738UART2 (Kraken secondary)

For CoreS3: use the appropriate GPIO for your board. The Tab5 reference stores pin config in NVS and reads with get_uart1_pins().

Sending Commands

Always append \r\n. Log every command sent.

c
static void uart_send_command(const char *cmd) {
    uart_write_bytes(UART_NUM, cmd, strlen(cmd));
    uart_write_bytes(UART_NUM, "\r\n", 2);
    ESP_LOGI(TAG, "Sent: %s", cmd);
}

Reading & Parsing Responses

Core Pattern: Line-by-Line Accumulation

All UART parsing follows the same pattern -- read bytes, accumulate into a line buffer character by character, parse on newline:

c
char rx_buffer[UART_BUF_SIZE];
char line_buffer[512];
int line_pos = 0;

while (!done && !timed_out) {
    int len = uart_read_bytes(UART_NUM, rx_buffer, UART_BUF_SIZE - 1, pdMS_TO_TICKS(100));
    if (len > 0) {
        rx_buffer[len] = '\0';
        for (int i = 0; i < len; i++) {
            char c = rx_buffer[i];
            if (c == '\n' || c == '\r') {
                if (line_pos > 0) {
                    line_buffer[line_pos] = '\0';

                    // === PARSE THIS LINE ===
                    if (strstr(line_buffer, "COMPLETION_MARKER")) {
                        done = true;
                        break;
                    }
                    parse_data_line(line_buffer);

                    line_pos = 0;
                }
            } else if (line_pos < sizeof(line_buffer) - 1) {
                line_buffer[line_pos++] = c;
            }
        }
    }
}
Completion Markers

Every command response has a known end marker. Wait for it before proceeding:

CommandCompletion Marker
scan_networks"Scan results printed"
wifi_connect"SUCCESS" or "FAILED" or "TIMEOUT"
start_nmap"Scanned" + "open ports" (final summary line)
list_hosts"Discovered Hosts" (header line, data follows)
list_sd"HTML files found" (header, data follows), or timeout
show_passTimeout (no explicit end marker)
list_probesTimeout (no explicit end marker)
wpasec_upload"Done:"
start_pcap"PCAP radio capture started" or "PCAP net capture started" (initial); on stop: "PCAP saved:"
start_beacon_spam"Beacon spam started. Use 'stop' to end."
start_beacon_spam_ssids"Beacon spam started. Use 'stop' to end." (same as start_beacon_spam)
list_ssidsTimeout (no explicit end marker, list ends after last indexed line)
add_ssid"Added SSID:"
remove_ssid"SSID removed."
version"JanOS version: X.Y.Z" (single line, immediate)

For commands without explicit end markers, use a timeout with empty-read detection (e.g., 3 consecutive empty reads of 500ms each).

Key Parsing Recipes

Network scan CSV -- fields: index, SSID, (empty), BSSID, channel, security, RSSI, band:

c
// Line: "1","AX3","","C4:2B:44:12:29:20","112","WPA2","-59","5GHz"
static bool parse_network_line(const char *line, wifi_network_t *net) {
    if (line[0] != '"') return false;
    char temp[256];
    strncpy(temp, line, sizeof(temp) - 1);
    char *fields[8] = {NULL};
    int field_idx = 0;
    char *p = temp;
    while (*p && field_idx < 8) {
        if (*p == '"') {
            p++;
            fields[field_idx] = p;
            while (*p && *p != '"') p++;
            if (*p == '"') { *p = '\0'; p++; }
            field_idx++;
            if (*p == ',') p++;
        } else { p++; }
    }
    if (field_idx < 8) return false;
    net->index = atoi(fields[0]);
    strncpy(net->ssid, fields[1], sizeof(net->ssid) - 1);
    strncpy(net->bssid, fields[3], sizeof(net->bssid) - 1);
    net->channel = atoi(fields[4]);
    strncpy(net->security, fields[5], sizeof(net->security) - 1);
    net->rssi = atoi(fields[6]);
    strncpy(net->band, fields[7], sizeof(net->band) - 1);
    return true;
}

Host list -- parse " IP -> MAC" lines:

c
if (strstr(line, "Our IP:") != NULL) {
    // Extract IP after "Our IP: " up to ","
} else if (strstr(line, "->") != NULL) {
    char *p = line;
    while (*p == ' ') p++;
    // read IP until space, skip " -> ", read MAC
}

Evil twin passwords -- "SSID", "password":

c
if (line[0] == '"') {
    char *ssid_start = line + 1;
    char *ssid_end = strchr(ssid_start, '"');
    if (ssid_end && *(ssid_end+1) == ',' && *(ssid_end+3) == '"') {
        *ssid_end = '\0';
        char *pass_start = ssid_end + 4;
        char *pass_end = strchr(pass_start, '"');
        if (pass_end) { *pass_end = '\0'; /* ssid_start and pass_start are your values */ }
    }
}

HTML file list -- "N filename.html":

c
if (strstr(line_buffer, "HTML files found") != NULL) {
    header_found = true;
} else if (header_found && line_pos > 2) {
    int file_num;
    char filename[64];
    if (sscanf(line_buffer, "%d %63s", &file_num, filename) == 2) {
        // store filename at index file_num
    }
}

Probe list -- "N SSID":

c
char *p = line;
while (*p == ' ') p++;
if (isdigit((unsigned char)*p)) {
    int idx = 0;
    while (isdigit((unsigned char)*p)) { idx = idx * 10 + (*p - '0'); p++; }
    while (*p == ' ') p++;
    if (*p != '\0') {
        char ssid[33];
        strncpy(ssid, p, sizeof(ssid) - 1);
        // trim trailing whitespace
    }
}

Deauth detector -- "[DEAUTH] CH: N | AP: name (BSSID) | RSSI: N":

c
static bool parse_deauth_line(const char *line, deauth_entry_t *entry) {
    if (!strstr(line, "[DEAUTH]")) return false;
    const char *ch = strstr(line, "CH:");
    entry->channel = atoi(ch + 3);
    const char *ap = strstr(line, "AP:"); ap += 3; while (*ap == ' ') ap++;
    const char *paren = strchr(ap, '(');
    size_t ap_len = paren - ap;
    while (ap_len > 0 && ap[ap_len-1] == ' ') ap_len--;
    memcpy(entry->ap_name, ap, ap_len);
    const char *paren_end = strchr(paren + 1, ')');
    memcpy(entry->bssid, paren + 1, paren_end - paren - 1);
    entry->rssi = atoi(strstr(line, "RSSI:") + 5);
    return true;
}

Handshake success:

c
if (strstr(line, "HANDSHAKE IS COMPLETE AND VALID")) { /* handshake validated */ }
if (strstr(line, "PCAP saved:")) { /* extract filename from path */ }
if (strstr(line, "handshake saved for SSID:")) { /* extract SSID after "SSID: " */ }

Evil twin password capture:

c
if (strstr(line, "connected to SSID=")) { /* extract SSID between ' quotes */ }
if (strstr(line, "password=")) { /* extract password after = */ }
if (strstr(line, "Password verified!")) { /* attack succeeded */ }

wifi_connect result (password is optional -- omit for open networks):

c
if (strstr(rx_buffer, "SUCCESS")) { connected = true; }
if (strstr(rx_buffer, "FAILED") || strstr(rx_buffer, "TIMEOUT")) { failed = true; }
// Extract DHCP IP from: "DHCP IP: 192.168.0.5, Netmask: 255.255.255.0, GW: 192.168.0.1"
const char *dhcp = strstr(rx_buffer, "DHCP IP:");
if (dhcp) { /* parse IP, Netmask, GW */ }

start_nmap progress and results:

c
// Progress line: "  Scanning 192.168.0.4 ports 21-143 [1/100] ..."
if (strstr(line, "Scanning") && strstr(line, "ports") && strchr(line, '[')) {
    char ip[16]; int port_from, port_to, current, total;
    sscanf(line, "  Scanning %15s ports %d-%d [%d/%d]",
           ip, &port_from, &port_to, &current, &total);
    int pct = (current * 100) / total;
    // update progress bar
}
// New host: "Host: 192.168.0.4  (00:C0:CA:B4:E6:3F)"
if (strncmp(trimmed, "Host:", 5) == 0) {
    char ip[16], mac[18];
    if (sscanf(trimmed, "Host: %15s (%17[^)])", ip, mac) == 2) {
        // new host with MAC
    } else if (sscanf(trimmed, "Host: %15s (MAC unknown)", ip) == 1) {
        // new host without MAC
    }
}
// Open port: "    135/tcp  open  MSRPC"
int port; char service[32];
if (sscanf(trimmed, "%d/tcp open %31s", &port, service) == 2 ||
    sscanf(trimmed, "%d/tcp  open  %31s", &port, service) == 2) {
    // found open port
}
// Completion: "Scanned 4 hosts, found 4 open ports"
if (strstr(line, "Scanned") && strstr(line, "open ports")) {
    int hosts, ports;
    sscanf(line, "Scanned %d hosts, found %d open ports", &hosts, &ports);
    // scan complete
}

Screen Building

Screen Lifecycle
show_*_page()
  ├── Create LVGL objects (container, labels, buttons, table)
  ├── Register event callbacks
  ├── Start background UART monitor task (if needed)
  └── Set as current visible page

[User interacts / UART data arrives]

cleanup (on back/close):
  ├── Set monitoring_active = false
  ├── Send "stop" via UART
  ├── Wait for task to finish (furi_thread_join or vTaskDelete)
  ├── Delete LVGL objects (lv_obj_del)
  ├── NULL all pointers
  └── Free allocated memory
Tile (Button) Creation
c
static lv_obj_t *create_tile(lv_obj_t *parent, const char *icon_text,
                              const char *label_text, lv_color_t bg_color,
                              lv_event_cb_t cb, const char *user_data) {
    lv_obj_t *tile = lv_btn_create(parent);
    lv_obj_set_size(tile, TILE_WIDTH, TILE_HEIGHT);
    lv_obj_set_style_bg_color(tile, bg_color, LV_STATE_DEFAULT);
    lv_obj_set_style_bg_color(tile, lv_color_lighten(bg_color, 50), LV_STATE_PRESSED);
    lv_obj_set_style_radius(tile, 12, 0);
    lv_obj_set_style_shadow_width(tile, 0, 0);
    lv_obj_set_flex_flow(tile, LV_FLEX_FLOW_COLUMN);
    lv_obj_set_flex_align(tile, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);

    lv_obj_t *icon = lv_label_create(tile);
    lv_label_set_text(icon, icon_text);
    lv_obj_set_style_text_font(icon, &lv_font_montserrat_28, 0);
    lv_obj_set_style_text_color(icon, lv_color_white(), 0);

    lv_obj_t *label = lv_label_create(tile);
    lv_label_set_text(label, label_text);
    lv_obj_set_style_text_color(label, lv_color_white(), 0);

    if (cb) lv_obj_add_event_cb(tile, cb, LV_EVENT_CLICKED, (void *)user_data);
    return tile;
}

Scale TILE_WIDTH and TILE_HEIGHT based on display resolution. Tab5 uses 230x140 for a 1280x720 display. For CoreS3 (320x240), use ~100x80 or similar.

Navigation via Event Callbacks
c
static void main_tile_event_cb(lv_event_t *e) {
    const char *name = (const char *)lv_event_get_user_data(e);
    if (strcmp(name, "WiFi Scan & Attack") == 0)  show_scan_page();
    else if (strcmp(name, "Global WiFi Attacks") == 0) show_global_attacks_page();
    else if (strcmp(name, "Bluetooth") == 0) show_bluetooth_menu_page();
    // ...
}
Popup Pattern
c
// Semi-transparent overlay covering the whole screen
overlay = lv_obj_create(lv_scr_act());
lv_obj_remove_style_all(overlay);
lv_obj_set_size(overlay, lv_pct(100), lv_pct(100));
lv_obj_set_style_bg_color(overlay, lv_color_hex(0x000000), 0);
lv_obj_set_style_bg_opa(overlay, LV_OPA_50, 0);
lv_obj_clear_flag(overlay, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_add_flag(overlay, LV_OBJ_FLAG_CLICKABLE);  // block clicks to background

// Centered popup
popup = lv_obj_create(overlay);
lv_obj_set_size(popup, POPUP_W, POPUP_H);
lv_obj_center(popup);
// ... add content to popup ...

Close popup: lv_obj_del(overlay) deletes both overlay and popup (child).

Thread-Safe LVGL Updates

LVGL is NOT thread-safe. Any LVGL call from a background UART task must be wrapped:

c
if (bsp_display_lock(0)) {
    lv_label_set_text(status_label, "Connected!");
    bsp_display_unlock();
}

If bsp_display_lock is not available, use a mutex or LVGL's built-in lv_lock()/lv_unlock() (LVGL 9.x).

Show full SKILL.md (257 more words)Show less
Memory Management
  • Use PSRAM (heap_caps_malloc(size, MALLOC_CAP_SPIRAM)) for large data structures (network lists, probe arrays, host tables).
  • Use internal RAM for small UI state structs and LVGL objects (LVGL manages its own allocator).
  • Always free PSRAM allocations in cleanup functions.
  • Keep network scan results in a global structure so they survive screen transitions.

Common Workflows

1. Scan-Select-Attack
uart_send("scan_networks")
  → wait for "Scan results printed"
  → parse CSV lines into network array
  → show network list with checkboxes
  → user selects networks and taps attack button

uart_send("select_networks 1 3 5")    // 1-based indices
uart_send("start_deauth")             // or start_evil_twin, start_handshake, etc.
  → start monitor task to parse UART output
  → update screen with attack status

// On back/stop:
uart_send("stop")
2. Evil Twin Flow
scan_networks → select_networks → list_sd → user picks HTML
→ select_html <index> → start_evil_twin
→ monitor for: "Client connected", "Password received", "Password verified!"
→ stop
3. Connect-ListHosts-ARPBan
// Check if password known via show_pass evil, or ask user
// For open networks, omit the password:
wifi_connect <SSID>              // open network
wifi_connect <SSID> <password>   // WPA/WPA2 network
  → wait for "SUCCESS" / "FAILED" / "TIMEOUT"

list_hosts
  → wait for "Discovered Hosts", parse IP->MAC lines

// User taps a host:
arp_ban <MAC> [IP]
  → show "ARP Poisoning Active"

// On back:
stop
3b. Connect-NMAP (Port Scan)
wifi_connect <SSID> [password]
  → wait for "SUCCESS" / "FAILED" / "TIMEOUT"

start_nmap [quick|medium|heavy] [IP]
  → Phase 1 (host discovery): parse "Total: N hosts discovered"
  → Phase 2 (port scanning):
      for each "Host: <IP>  (<MAC>)" line → add host to list
      for each "Scanning <IP> ports X-Y [current/total]" → update progress bar
      for each "<port>/tcp  open  <service>" → add open port to current host
      "(no open ports)" → mark current host as no-ports
  → Completion: "Scanned N hosts, found M open ports"

// Can be stopped anytime with:
stop → "(scan stopped by user)"
4. Portal/Karma Setup
list_sd → user picks HTML → select_html <index>
start_portal <SSID>         // or start_karma <probe_index>
  → monitor for client connections and form submissions
  → stop
5. Wardrive
start_wardrive   // or start_wardrive_promisc
  → wait for "GPS fix obtained" (show "Acquiring GPS Fix..." until then)
  → parse CSV network lines as they arrive
  → show "Logged N networks to ..."
  → handle "GPS fix lost!" / "GPS fix recovered:"
  → stop
6. Beacon Spam from SSID File
list_ssids → show indexed SSID list
  → user can add_ssid <name> to append
  → user can remove_ssid <index> to delete
start_beacon_spam_ssids
  → wait for "Beacon spam started. Use 'stop' to end."
  → stop

Or with inline SSIDs:

start_beacon_spam "SSID1" "SSID2" "SSID3"
  → wait for "Beacon spam started. Use 'stop' to end."
  → stop
7. PCAP Capture
// Radio mode (no prerequisites):
start_pcap radio
  → wait for "PCAP radio capture started -> ..."
  → stop → "PCAP saved: ... (N frames, M drops)"

// Net mode (requires WiFi connection):
wifi_connect <SSID> [password]
  → wait for "SUCCESS"
start_pcap net
  → wait for "PCAP net capture started -> ..."
  → stop → "PCAP saved: ... (N frames, M drops)"
8. Bluetooth Locate
scan_bt → parse device list → show scrollable list
→ user taps device → scan_bt <MAC> → continuous RSSI updates
→ stop

Adapting for Smaller Screens (CoreS3)

When porting from Tab5 (1280x720) to CoreS3 (320x240):

  • Reduce tile grid: 2x3 instead of 3x4. Tile size ~100x80.
  • Use smaller fonts: lv_font_montserrat_14 for body, lv_font_montserrat_18 for titles (instead of 20/28).
  • Popups should be nearly full-screen (280x200) since the display is small.
  • Scrollable lists are essential -- use lv_table or lv_list with small row heights.
  • Consider a single UART (no Kraken dual-UART mode) to keep complexity low.
  • The home button at top should be compact (icon only, no text).
  • Tab bar (UART1/UART2/INTERNAL) may not fit; use a dropdown or eliminate tabs for single-UART configs.

Checklist for New Screens

  1. Create show_<feature>_page() function
  2. Build UI: container, title, content area, back button
  3. Send UART command(s)
  4. Start background monitor task if response is continuous
  5. Parse UART response using line-by-line accumulation pattern
  6. Update UI inside bsp_display_lock()/unlock() from background tasks
  7. Implement cleanup: set monitoring = false, send "stop", delete LVGL objects, free memory
  8. Wire up the back/home button to call cleanup and return to parent screen

© C5Lab, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 1 other file in .github/skills/janos-uart-app of C5Lab/M5MonsterC5-CardputerADV.

  • SKILL.md
  • commands-reference.md

Open the folder on GitHubat commit ad750dd

Compare with similar skills

Janos Uart App next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Janos Uart App compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Janos Uart App this skillC5Lab/M5MonsterC5-CardputerADV232—~4.7kAutomated safety check: PassMIT
RuView Hardware Setupruvnet/RuView97k—~1.8kAutomated safety check: NotesMIT
Esp32 Firmware Engineeralxv2016/folloup-sticky1161 repos~3.8kAutomated safety check: PassGPL-3.0
RuView mmWave Radar Setupruvnet/RuView97k—~907Automated safety check: NotesMIT
Embedded DebugFastLED/FastLED7.5k—~1.4kAutomated safety check: PassMIT
Auto EmbeddedDunCanYounG-1/MICU-auto-embedded253—~1.6kAutomated safety check: PassCC-BY-NC-4.0

Similar skills

  • Brings a RuView CSI sensing node online by building ESP32-S3 or ESP32-C6 firmware, flashing the board, provisioning WiFi and checking the serial output.

    97k GitHub stars~1.8k tokensUpdated today
    DevelopmentAuto-check: notes
  • Esp32 Firmware Engineer

    alxv2016/folloup-sticky

    ESP32 firmware engineering for ESP-IDF projects. An agent skill from alxv2016/folloup-sticky.

    116 GitHub starsUsed in 1 repo~3.8k tokens
    DevelopmentAuto-check passed
  • Sets up and runs 60 GHz and 24 GHz mmWave radar sensing on ESP32 boards in RuView, alone or fused with WiFi CSI.

    97k GitHub stars~907 tokensUpdated today
    DevelopmentAuto-check: notes
  • Embedded Debug

    FastLED/FastLED

    Firmware crash analysis, stack trace decoder, and register dump interpreter for ESP32/ARM/AVR platforms.

    7.5k GitHub stars~1.4k tokensUpdated today
    DevelopmentAuto-check passed
  • Auto Embedded

    DunCanYounG-1/MICU-auto-embedded

    全平台嵌入式 AI 开发框架(对标 Trellis):把 RIPER-5 五阶段协议 + 四文件记忆 + 分层架构门禁 + Scout/Builder/Verifier 多 Agent + 24 个工具调用技能(build/flash/debug/serial/can/modbus/visa/static/memory/rtos/scons),做成『装进工程、项目级 hook…

    253 GitHub stars~1.6k tokensUpdated yesterday
    DevelopmentAuto-check passed
  • Embedded Cpp14 Misra

    BlueAndi/Pixelix

    A skill your agent uses when writing, reviewing, or refactoring C/C++ firmware code in this repository (src/, lib/, test/) — creating or editing .h/.hpp/.cpp files, applying MISRA-oriented and…

    443 GitHub stars~2k tokensUpdated today
    DevelopmentAuto-check passed

Works with

Categories

Questions about Janos Uart App

What does Janos Uart App do?

Build LVGL touchscreen applications that communicate with JanOS ESP32C5 firmware over UART. Janos Uart App is an agent skill from C5Lab/M5MonsterC5-CardputerADV. Build LVGL touchscreen applications that communicate with JanOS ESP32C5 firmware over UART.

When should I use Janos Uart App?

Janos Uart App fits situations like: creating screens for Tab5; any ESP-IDF device that sends UART commands like scannetworks.

How do I install Janos Uart App in Claude Code?

Run `npx skills add C5Lab/M5MonsterC5-CardputerADV --skill janos-uart-app -a claude-code`. Or copy the skill folder (.github/skills/janos-uart-app in C5Lab/M5MonsterC5-CardputerADV) into .claude/skills/janos-uart-app in your project. Claude Code loads it when a task matches its description.

How do I install Janos Uart App in Codex?

Run `npx skills add C5Lab/M5MonsterC5-CardputerADV --skill janos-uart-app -a codex`. Or copy the skill folder (.github/skills/janos-uart-app in C5Lab/M5MonsterC5-CardputerADV) into .agents/skills/janos-uart-app in your project. Codex loads it when a task matches its description.

Can I use Janos Uart App in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add C5Lab/M5MonsterC5-CardputerADV --skill janos-uart-app -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/janos-uart-app, .gemini/skills/janos-uart-app, .github/skills/janos-uart-app and .opencode/skills/janos-uart-app in your project.

What does Janos Uart App need to run?

SKILL.md names no scripts, command-line tools or credentials: Janos Uart App is instructions for the agent only.

Does Janos Uart App access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Janos Uart App safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Janos Uart App use?

Janos Uart App is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Janos Uart App use?

About 4.7k tokens (SKILL.md is roughly 19k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Janos Uart App?

Skills that share tags, products or a category with Janos Uart App: RuView Hardware Setup (ruvnet/RuView, 97k stars), Esp32 Firmware Engineer (alxv2016/folloup-sticky, 116 stars), RuView mmWave Radar Setup (ruvnet/RuView, 97k stars) and Embedded Debug (FastLED/FastLED, 7.5k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Janos Uart App?

C5Lab (a GitHub organization) maintains it in C5Lab/M5MonsterC5-CardputerADV, which has 232 GitHub stars. The repository was last updated on September 28, 2026.

Source: C5Lab/M5MonsterC5-CardputerADV on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.