SolarOS

SolarOS 4.13.4 manual · app

SolarOS Embedded Apps

This document covers foreground applications registered in SolarOS. Availability depends on the selected firmware flavor and board capabilities. The apps command shows the app set compiled into the running image.

Exit behavior:

agent

Native Responses/Chat-Completions LLM client and SolarOS agent control plane. It streams model text directly to the active shell and exposes typed system-status, storage-listing, job-listing, display-discovery, and optional Python/Lua execution tools. agent tools shows risk, policy, and runtime availability.

Configure the full endpoint and model, then ask a question:

agent config endpoint https://api.openai.com/v1/responses
agent config model gpt-model
agent config key api-key
agent config reasoning medium
agent config tools confirm
agent config max-tools 16
agent
agent list
agent resume SLOT
agent ask How much memory is free on this device?
agent script python -c "print(6 * 7)"
agent script lua /script.lua argument

Bare agent and agent new open a new foreground prompt loop. Completed turns are saved, and agent list plus agent resume SLOT restore a selected transcript after leaving the app or rebooting. agent delete SLOT removes one conversation without changing provider credentials. Responses uses its saved provider continuation ID; Chat Completions uses bounded local history. Slots are 1 to 3 on internal flash or 1 to 8 on SD; the oldest is reused when full. agent ask performs one unsaved request but likewise waits for Esc or the app-exit key after completion, so display-shell output is not immediately replaced by the shell screen.

Use agent config key clear for an endpoint that does not require bearer authentication. agent status shows configuration, request counters, HTTP status, reasoning effort, duration, traffic, and internal-RAM/PSRAM measurements from the last request. The API key itself is never printed. A Chat-Completions-compatible endpoint can still be configured explicitly.

The agent permits 16 sequential tool calls by default, followed by a separately reserved final provider turn. agent config max-tools COUNT stores a per-request limit from 1 through 32 in NVS. The final turn advertises no tools after that budget is consumed, so the model concludes from the collected results instead of failing on one more tool request. Output is bounded to 16 KiB, protocol buffers and queues prefer PSRAM, and the foreground worker uses a declared 16 KiB internal stack. Full builds can reuse that worker for bounded Python or Lua source/file execution. The manual script path captures at most 4095 output bytes, has a 30-second deadline, and supports cancellation with Esc or the app-exit key. Model-generated source is capped at 640 bytes and captures 383 output bytes.

The storage registry includes bounded listing, sensitive text-file reads, and text-file replacement. Reads and writes are capped at 3072 bytes and paths below .ssh are unavailable to protect SSH identity files.

The default confirm policy runs read-only tools automatically and shows the exact arguments of sensitive, mutating, disruptive, and script calls before waiting for a local y/N decision. off disables tools, readonly excludes all protected risk classes, and explicit all allows every available tool without prompting. See Native Agent Service for the provider contract and current limits.

Controls:

aplay

Play audio files through the default registered playback endpoint. WAV and MP3 are supported when an output device is present. MP3 decoding is provided by the shared, device-independent audio codec service. aplay prints the source details, plays the file once through the shared background audio player, and then returns to the prompt without clearing existing terminal output. It can be launched from display, UART, USB CDC, Telnet, and other port shells.

Usage:

aplay [-v volume] file.wav|file.mp3

Controls:

arecord

Record a registered capture endpoint to a WAV file. The default is the first compatible input; -i selects a specific stream such as adc0.capture. This requires a registered input device, but not built-in board audio. With -d, recording stops after the specified number of seconds. Without -d, recording continues until app-exit, the storage fills, or the WAV size limit is reached. It can be launched from display, UART, USB CDC, Telnet, and other port shells.

Usage:

arecord [-d seconds] [-i capture-stream] file.wav

Controls:

recorder

Interactive GUI/TUI counterpart to arecord. Recorder writes PCM WAV files so the channel count, sample rate, and resolution travel with the recording and the result can be played immediately. It accepts any registered signed-16-bit PCM capture stream. On the Waveshare board it initially selects audio0.capture. Mono/stereo output, 8/16-bit file resolution, and sample rates from 8 kHz through 48 kHz are converted from the selected stream as necessary.

Usage:

recorder [--tui] [file.wav]

The optional path supplies the initial recording folder and filename. The Setup view can edit the filename or select another destination directory with the shared file browser. When the filename is empty, each recording gets a unique local-time name such as rec-260810-113045.wav; a numeric suffix avoids overwriting a file created in the same second. Recorder remembers its selected input, folder, format, hardware input gain, output volume, and visualizer in .recorder/settings.bin on the current storage root. An explicit path argument overrides the remembered folder. The filename is not remembered, so reopening Recorder cannot accidentally reuse a one-off name.

Recorder selects its graphical interface on a graphical shell and its text interface on a port shell. --tui forces the text interface even when the launching shell has graphics.

Tab switches between Record and Setup. The Record view uses the shared cassette widget by default; V cycles through Cassette, Oscilloscope, and Spectrum. R starts recording, Space pauses or resumes, S stops and finalizes the WAV header, and P plays the most recent or selected recording. M starts or stops monitoring: it continuously streams the selected input to the default output and visualizer. Monitoring can remain enabled when recording starts and can be toggled while the WAV writer continues. Up/Down changes monitor and playback volume. The cassette reels move during recording and playback, but remain still during monitoring. Oscilloscope and Spectrum remain live during monitoring. Active visualizers are presented on the 40 ms app tick (nominally 25 frames per second), independently of the audio block rate.

Setup selects the capture stream, recording folder, mono/stereo conversion, sample rate, 8/16-bit WAV resolution, input gain, and output volume. Enter on Folder opens the WAV-filtered browser. D selects its current directory as the recording folder; Enter on a WAV file plays it and returns to Record. Input gain is not a generic stream multiplier: Recorder enables it only when the selected capture stream belongs to an audio device that advertises hardware input-gain control. Thus audio0.capture on the Waveshare controls the ES7210 microphone gain, while an unrelated generic stream shows Input gain: n/a. The hardware gain is system-wide; Recorder does not add hidden digital amplification to the saved PCM.

The text interface exposes the same setup values, browser, transport keys, monitoring, pause behavior, and playback path. Recorder is resumable: capture, monitoring, or playback continues while its UI session is in the background, and closing the app stops the worker and finalizes an active recording.

funcgen

Audio-only function generator built on the shared real-time Synth service. It emits signed 16-bit stereo PCM and can use the default playback device or an explicitly selected runtime playback stream, including an attached LEDC PWM audio expansion.

Usage:

funcgen [--tui]

The graphical interface shows the exact generated PCM in the shared oscilloscope widget. The remaining controls select sine, square, triangle, saw, pulse, or noise output; frequency from 20 through 8000 Hz; amplitude; pulse width; a repeating linear sweep; sweep end frequency; sweep time; and playback stream. The TUI exposes the same controls. --tui forces it on a graphical shell.

Controls:

The output is off initially. Frequency is capped below the selected stream's Nyquist limit during rendering. A sweep moves linearly from Frequency to Sweep end during Sweep time, then repeats without resetting oscillator phase. Suspending the UI leaves an active generator running; closing it stops the Synth worker and releases the stream.

All controls can be targeted by the shared control-binding system while Funcgen is active:

The durable foreground state and oscilloscope storage use PSRAM when present. Only the bounded oscillator/render state, Synth worker stack, and PCM block remain in internal SRAM.

player

Interactive WAV/MP3 player and the user-facing counterpart to aplay. player keeps a persistent playlist under .player on the current storage root. Opening an audio file from Files adds it to that playlist, selects it, and starts playback. Missing files remain listed so removable media can be reattached.

Usage:

player [--tui] [file.wav|file.mp3]

Player selects its graphical interface on a graphical shell and its text interface on a port shell. --tui forces the text interface even when the launching shell has graphics.

On a graphical session, Tab switches between Play and Playlist. The Play tab uses the top two-thirds for a cassette visualizer by default; V cycles through Cassette, Oscilloscope, and Spectrum. The cassette reels turn only while audio plays and show track progress when duration is known. Left/Right plays the previous or next track in the playlist ring, Enter plays or stops, Space pauses or resumes, and Up/Down adjusts volume. On the Playlist tab, Up/Down selects, Enter starts the track and returns to Play, A opens the WAV/MP3 file browser, and Delete removes the selected playlist entry.

The text interface is one playlist screen: Up/Down selects, Enter plays or stops, Space pauses or resumes, A opens the filtered file browser, Delete removes an entry, and Esc exits. Its bottom status line shows the playing, paused, or stopped state with elapsed and total time. Playback follows the resumable app while another foreground session is selected and stops when Player closes. End of file advances to the next playlist entry.

WAV playback converts the file's mono/stereo channel count and sample rate to the selected output stream. A mono recording therefore plays through a fixed stereo device without changing the recording stored on disk.

calc

Scientific calculator and function plotter. On a graphical display, calc opens an expression list beside a Cartesian plot. From UART, USB CDC, Telnet, or any other text-only shell, the same command opens a scientific REPL without the plot pane. calc --tui forces that REPL even when graphics are available.

The expression engine supports +, -, *, /, %, powers with ^, parentheses, scientific notation, and implicit multiplication such as 2pi or 2(x + 1). Built-ins include sin, cos, tan, their inverse functions, sqrt, abs, exp, ln, log, floor, ceil, round, min, max, pow, and atan2. Trigonometric input is in radians; rad(degrees) and deg(radians) convert explicitly. Constants are pi and e.

Rows can hold scalar calculations, variables, one-argument functions, or plots:

a = 2
f(x) = sin(x) / x
f(pi / a)
y = f(x)

For a one-off shell calculation, use:

calc -e "sqrt(2)^2"

Text REPL commands:

Graphical controls:

chat

Tabbed provider-neutral conversation client. The Channels tab lists gateway and radio conversations. Enter selects a conversation and opens its bounded shared history on the Chat tab, which also contains the message/command input. The app opens and remains useful offline; network or radio transport jobs connect independently.

Usage:

chat [gateway|meshcore|link|conversation-id]

With no selector, Chat opens a unified view and initially selects the newest unread conversation. A provider name filters the list. A decimal conversation ID opens exactly that conversation.

The background gateway-sync job owns the gateway transport connection, retries, and joined-channel replay. Each join sends the greatest stable message ID retained for that room as its cursor; the gateway replays only newer messages. Requested membership and server-confirmed membership are separate, connection-scoped states. The shared messaging service owns queued outbound messages and gateway-sync consumes only gateway requests. Start it explicitly with job start gateway-sync, just like email-sync. Closing or suspending chat does not disconnect an already-running synchronizer. Incoming messages remain in the shared bounded messaging store and publish bounded notifications to the universal inbox; reopening the app replays retained conversations from every provider. With SD storage, full messages are retained under /.messages/messages.bin. On internal flash, Chat restores the compact message copy already retained in /.inbox/messages.bin, so it consumes no second flash ring. Both backends deduplicate transport replays by stable message identity and keep linked Inbox read state aligned.

Unlike email-sync, gateway-sync takes no interval argument: it waits for Wi-Fi and reconnects with exponential backoff while remaining in the running state.

Gateway setup and room lifecycle use gateway status, gateway configure, gateway connect, gateway disconnect, gateway rooms, gateway join, gateway leave, and gateway delete. Gateway synchronization runs only under the gateway-sync job name. Selecting a known gateway room in the Channels tab requests a join automatically and opens it after the server confirms joined.

Conversation rows show provider, unread, and security state. Outbound rows show queued/sending/sent/delivered/failed state. Use /new CONTACT_ID to open a direct conversation with the contact's preferred endpoint. Sending to a discovered endpoint asks for a second Enter confirmation; blocked endpoints cannot be messaged.

The conversation header reports the selected provider's state. Gateway uses disconnected, connecting, and connected; connectionless MeshCore and Link providers use stopped, starting, ready, and error.

In-app commands:

/help
/new contact-id
/status
/quit

Controls:

clock

Full-screen graphical seven-segment clock, alarm countdown, and stopwatch. The countdown is serviced in the background, so it continues when the Clock session is suspended. It works without RTC hardware while SolarOS remains powered. With a wired RTC interrupt, the RTC alarm or countdown is also armed and explicit light sleep can wake for it.

Usage:

clock
clock -a mm:ss
clock -s

Controls:

com

Serial terminal for a bidirectional byte-stream port. Display-keyboard or port-shell input is forwarded to the selected port, and received bytes are drawn in the active terminal. The port may be a UART or a virtual port such as a peer-bound SolarOS Link stream.

Usage:

com [--autobaud] [--hex] [port]

The port defaults to uart0. For example, com gps connects to an existing runtime UART bus named gps, while com vser0 opens a Link stream previously created with link stream create. The selected port remains claimed by the app until the session exits. com works from both display and port shells; when launched from a port shell, its terminal output is returned through that same port. The input/output shell port and selected COM port must be different.

--autobaud is available only for UART buses. It samples the RX signal for three seconds before opening the terminal. Send a repeating 0x55 or 0xaa pattern during that interval. A reliable measurement is matched to a standard UART rate and applied to the current bus connection without overwriting the saved baud setting. UART input forwarding begins when sampling completes. If measurement fails, the configured rate is kept.

--hex displays received bytes as eight-byte offset, hexadecimal, and ASCII rows instead of interpreting them as terminal text. Both options can be used together.

Examples:

com --hex gps
com --autobaud --hex uart0
com vser0

Controls:

curl

HTTP client for quick text downloads and diagnostics. It can print response data to the terminal or save it to a file.

Usage:

curl [-L] [-o file] URL

Controls:

webradio

Stream a direct MP3 URL through the default registered audio output. On a graphical display shell, WebRadio opens a two-tab media-player GUI. On UART, USB CDC, Telnet, SSH, and other text shells, it opens a station-list TUI.

The catalog is stored as .solar/webradio/catalog.bin on the current storage root and starts with the Nightride, Chillsynth, Datawave, Spacesynth, Darksynth, Horrorsynth, EBSM, and Rekt streams. Catalog changes survive reboot. On first use after an upgrade, WebRadio moves an older NVS catalog to this file and removes the large NVS blob. reset restores the initial list.

Usage:

webradio
webradio --tui
webradio https://stream.nightride.fm/nightride.mp3
webradio list
webradio add MyStation https://example.net/live.mp3
webradio remove MyStation
webradio reset

--tui forces the station-list TUI even on a graphical shell and can be combined with a direct stream URL. Catalog-management commands also accept it as a harmless interface override.

URLs are literal HTTP or HTTPS MP3 stream URLs. WebRadio does not translate station names or website addresses and does not discover streams from HTML pages. The initial implementation does not support playlists, HLS, or AAC.

Controls:

The app is available on Wi-Fi builds even when the board has no built-in audio hardware. Playback starts when a default output device has been registered, including an output supplied by a runtime-attached expansion.

Network reception and MP3 decoding feed an app-owned PCM jitter buffer. A separate playback worker consumes that buffer at the audio device's steady rate. Both workers continue while the resumable WebRadio session is suspended or another foreground app is selected. Closing WebRadio cancels the network operation through its bounded read timeout, stops both workers, and releases the audio device. The network worker exclusively owns the HTTP request during that shutdown.

The playback worker, not the decoder, publishes visualizer samples after each audio write. The widgets retain only the latest played block and may drop intermediate display frames, so buffering does not put the visualization ahead of the audio. WebRadio uses 256 scope samples and a 256-point SIMD-eligible FFT, grouped into 32 displayed frequency bands.

service.signal-widgets provides the reusable thread-safe signed-16-bit oscilloscope and spectrum components used by the graphical player. The widgets accept mono or interleaved multichannel PCM and own their snapshot storage; applications retain ownership of their audio streams.

help

Foreground browser for the package-aware SolarOS manual. The foldable tree groups the topics compiled for the current firmware and shows whether it is using the embedded copy or a verified downloaded revision. All groups start folded. The selection, scroll position, and fold state remain unchanged after a topic closes.

Usage:

help
help agent

Controls:

The maintenance forms help status, help update, and help reset remain shell operations. SD-capable builds show terminal-width-aware progress while downloading and extracting one exact-version signed manual archive. Use help command.status to open the shell status command page.

edit

Text editor for files on mounted storage. It supports cursor navigation, selection, clipboard operations, text-size changes, and syntax highlighting for known source files. The editor supports files up to 256 KiB on boards with PSRAM and 32 KiB on boards without PSRAM. Use hexedit for binary files.

Usage:

edit <file>

Controls:

hexedit

Two-pane binary editor for files on mounted storage. Each row shows a file offset, hexadecimal bytes, and their synchronized printable ASCII view. The number of bytes per row adapts to the terminal width. It uses the same 256 KiB PSRAM and 32 KiB internal-memory limits as edit.

Usage:

hexedit <file>

Controls:

launcher

Configurable native graphical launcher for display shells. It draws the configured grid, centers one icon in each occupied cell, and shows the selected icon larger with its title centered underneath. Arrow keys move between occupied cells, Enter opens the selection, and a pointer selects and opens items by point and click. Esc or the app-exit key returns to the shell.

Usage:

launcher [config.json]

Without an argument, Launcher reads launcher.json from the active storage root. The first run creates a usable default file there. A supplied path selects another configuration. Launcher reloads the file whenever a child application returns, so editing the configuration through a launcher item takes effect immediately.

The file is JSON. layout.columns and layout.rows define a grid from 1 by 1 through 8 by 8. Each item has a displayed name, an Open Iconic icon name, a SolarOS shell command, and a zero-based column and row. A cell can contain at most one item, and a configuration can contain up to 32 items:

{
  "layout": {"columns": 3, "rows": 2},
  "items": [
    {"name": "Files", "icon": "folder", "command": "files", "column": 0, "row": 0},
    {"name": "Manual", "icon": "book", "command": "help", "column": 1, "row": 0},
    {"name": "Wi-Fi", "icon": "wifi", "command": "wifi", "column": 2, "row": 0},
    {"name": "Sketch", "icon": "brush", "command": "sketch", "column": 0, "row": 1}
  ]
}

Icon names are the lowercase, hyphenated Open Iconic names, such as book, browser, brush, calculator, clock, cog, document, folder, home, musical-note, pencil, tablet, terminal, and wifi. Legacy numeric IDs from 0 through 222 remain accepted for existing configurations.

Commands use the normal SolarOS shell parser, so arguments, aliases, scripts, and application availability checks behave exactly as at the prompt. A launched foreground application returns to Launcher when it closes. A command that does not open an application returns to the shell so its output remains visible.

files

File manager inspired by Midnight Commander. Its normal mode provides two panes for copy, move, delete, and launch workflows on mounted storage. Launcher mode provides a minimal single-pane application menu suitable for a startup script.

Usage:

files [--launcher] [path]

files --launcher hides dot-prefixed entries, removes the message and function key bars, and expands one pane to the bottom of the terminal. Launcher mode is read-only: navigate with the arrows, open with Enter, refresh with r, move to the parent with Backspace, and exit with q or the app-exit key. To make a directory the startup menu, add a line such as this to /.shell/startup:

files --launcher /apps

File associations come from the installed app registry. Only apps compiled in the active firmware can be selected. Associations include images to view, WAV/MP3 to player, CSV to sheet, Python and Lua scripts to their runtimes, documents to reader (or writer when Reader is unavailable), and .gb ROMs to gameboy. Unknown files fall back to less or edit. A .sh file runs through the built-in SolarOS shell. In launcher mode, documents associated with Reader open as reader --pager for row-aware page navigation.

Controls:

ftp

Two-pane FTP file manager. The left pane is local mounted storage. The right pane is a remote FTP server. The app uses unencrypted IPv4 FTP and passive data connections.

Usage:

ftp HOST [PORT] [--user USER --password PASSWORD] [--remote PATH] [--local PATH]

Anonymous login is the default (anonymous with solaros@ as its password). Specify both --user and --password for an authenticated server. Passwords are plaintext on the network and remain in shell history when entered on the command line. Use FTP only on a trusted network.

Controls:

FTP is a resumable TUI on the display shell and VT100-compatible port shells. One operation runs at a time in its foreground worker. Existing destination files are replaced. A failed download removes its staging file and preserves an existing destination; a move does not delete its source unless the complete copy succeeds.

flash

Download verified SolarOS factory artifacts to SD and program another supported ESP board over UART. The browser refreshes the signed catalog on request and shows which board, flavor, and version artifacts are already cached. Its tree starts folded and retains its selection and fold state after operations. Delete removes a selected cached artifact after confirmation. The shell form accepts a named UART plus optional boot and reset GPIO pins.

flash
flash refresh
flash list
flash download BOARD FLAVOR [VERSION]
flash BOARD FLAVOR [version=VERSION] [port=uart0] [boot=PIN] [reset=PIN] [baud=RATE]

See Flash another ESP board for wiring, target-selection, security, storage, and verification details.

contacts

Provider-neutral address book for gateway and MeshCore identities. Contacts can carry multiple provider endpoints while retaining trust independently for each endpoint. A signed MeshCore advert creates a discovered endpoint: the signature proves possession of the advertised key, not the human identity behind it.

Open the searchable TUI:

contacts

The list is grouped by trust and provider. Press / to search, Enter to view the selected endpoint addresses, capabilities, last-seen times, and bounded provider metadata summary, and Esc or q to leave.

Use the shell surface for mutations:

contacts status
contacts list [all|discovered|trusted|blocked]
contacts show CONTACT_ID
contacts rename CONTACT_ID NAME
contacts trust CONTACT_ID [ENDPOINT_ID]
contacts block CONTACT_ID [ENDPOINT_ID]
contacts remove CONTACT_ID
contacts link TARGET_CONTACT_ID SOURCE_CONTACT_ID

Contact and endpoint identifiers autocomplete from live service snapshots. Linking moves the source endpoints to the target contact and removes the source record. When the 64-contact store is full, SolarOS may evict the oldest unpinned contact whose endpoints are all still discovered; trusted and blocked records are never automatically evicted.

The versioned store is CRC checked, uses two alternating headers and data copies, remains below 24 KiB, and normally lives at /.contacts/contacts.bin. If storage is unavailable, Contacts remains usable in volatile mode and contacts status reports the storage error.

inbox

Universal incoming-message browser for pages, chat notifications, mail, and other background producers. It reads the same shared inbox that supplies the status-bar unread count. Messages and read state survive reboot in the bounded /.inbox/messages.bin store; the service retains at most 64 entries and keeps the file below 32 KB even when internal flash is the only storage.

Each list item occupies exactly one terminal row: unread/priority markers, local reception date and time, a compact source (chat/general, email, or pocsag), and as much of the message body preview as fits the screen.

Notification sound is enabled by default on boards with audio. Press s in the Inbox or use inbox notify on, inbox notify off, or inbox notify test; the setting is persistent. Notification tones remain active while SolarOS is suspended.

Usage:

inbox

Controls:

email

Receive-only IMAPS client for the configured mailbox. The app shows the provider-specific message list while every newly synchronized message is also published to the universal inbox and its shared status-bar unread counter.

Configure and synchronize the account before opening the app:

wifi on
email configure imaps://imap.example.com user@example.com app-password INBOX
email sync
email

Controls:

The account configuration persists in NVS. The local message list is volatile and keeps the newest 32 synchronized messages. This first version displays a best-effort text preview; MIME attachments, encoded headers, sending, and server-side read flags are not implemented yet.

io

Interactive expansion I/O manager. Its default Layout view presents the board's connectors in their physical arrangement, followed by the existing pin, named-bus, and resource-claim views. It uses the same ownership and validation services as the gpio, i2c, spi, uart, midi, onewire, and expansion commands.

Usage:

io

Controls:

invaders

Graphical arcade shooter.

Usage:

invaders

Controls:

gameboy

Original Game Boy (DMG) emulator selected by the gameboy group on boards with PSRAM, SD storage, graphics, and a streaming display. Current integrated targets are SolarTerm, Freenove IPS, CL-32, T-LoRa-Pager, T-Deck Plus, ODROID-GO, Freenove PAL, and TTGO VGA32. The application loads a user-supplied ROM into PSRAM and writes battery-backed cartridge RAM beside it as a .sav file. Game Boy Color-only ROMs and ROMs larger than 4 MiB are rejected.

The emulator runs Peanut-GB at its fixed native frame frequency in a dedicated worker. Peanut-GB renders alternate LCD frames, producing a compact 160x144 INDEX2 raster at about 30 frames per second while still emulating every frame. A shared frame presenter owns display cadence, retains the newest submitted frame, and replaces stale pending frames instead of blocking emulation. TFT targets scale the four-color raster directly to RGB565. One-bit targets convert the latest frame through ordered dithering, then use their scan-synchronized mono path. The target selects a bounded presentation rate of 25 or 30 frames per second and reduces output scale when the driver's pixel-rate budget cannot sustain the larger raster. Runtime logs report emulation, presentation, replacement, timing rebase, audio block, peak level, and transfer timing.

Audio rendering runs in its own bounded worker, applies a Game Boy-local bounded gain for low-resolution DAC outputs, and holds exclusive speaker output while Game Boy is active. The Waveshare presenter temporarily requests the panel's 25.5 Hz HPM profile. Pausing, suspending, or exiting stops the workers and restores the previous display and audio policies. PAL builds run without audio because composite scanout owns I2S0; both the 384x288 raster and the centered 320x200 safe-area mode can fit the scaled Game Boy frame.

Usage:

gameboy <file.gb>

Controls:

Game Boy reads the generic SolarOS held-key state. BLE/PS/2 keyboards, fixed board buttons, gpio-keys, and ADC D-pads therefore remain active until release, and combinations such as diagonal movement or direction plus A/B work simultaneously. USB HID usages preserve the physical Z/X positions across keyboard layouts. Character-only inputs such as port-shell input retain the short button-pulse fallback. Analog joystick axes do not become Game Boy keys.

less

Terminal pager for text files. It preserves original text layout and is useful for quick file inspection.

Usage:

less <file>

Controls:

logic

On-device logic analyzer waveform viewer. It displays the latest capture made by the shared logic analyzer service or the SUMP job. With pin arguments it makes a new local capture before opening the viewer.

Usage:

logic
logic <pin[,pin...]> [rate-hz] [samples] [trigger=<pin>]

Examples:

logic
logic 1,2,3,17
logic 1,2 500000 8192
logic 1,2,3,17 10000 4096 trigger=1

trigger=<pin> waits for the next rising or falling edge on that runtime-safe GPIO before sampling. The trigger pin may be one of the captured data pins, as in the last example, or a separate GPIO that is not displayed as a channel.

Controls:

The app is compiled only for boards with graphics and runtime-safe GPIOs. While the SUMP job is running, the app remains a viewer and automatically reloads captures received from the host.

lua

Embedded Lua runtime. It can run an interactive REPL or execute .lua scripts from storage. Lua scripts can use SolarOS service bindings when the selected firmware includes the corresponding packages. Foreground scripts can consume touch coordinates, relative mouse motion, buttons, and joystick axes through solaros.input.

Usage:

lua
lua file.lua [args...]

Controls:

notes

Markdown-backed checklist and category manager. It stores unchecked and checked items and supports one level of category folding. A persistent bottom help bar shows the available controls, with status or text input directly above it.

Usage:

notes [file.md]

Controls:

plot

Graphical plotter for DAQ CSV files and live scalar streams. It is compatible with CSV generated by the daq job.

Usage:

plot <scalar-stream...> [--rate ms]
plot -f <file.csv> [column...]

Examples:

plot temperature humidity --rate 1000
plot -f /logs/env.csv temperature humidity

--rate is a best-effort live sampling interval in milliseconds. Rates below 25 ms request faster runtime ticks while the screen redraws no more often than once every 25 ms, so fast acquisition does not force an equally fast display refresh.

Controls:

playground

Browse the configured community catalog as a foldable category tree, search applications, and install, update, uninstall, or run Python and Lua scripts.

Usage:

playground
playground search QUERY...
playground install APP-ID [auto|flash|sd]
playground run APP-ID [ARG...]
playground delete
playground refresh
playground reload
playground source [repository-or-catalog-url|reset]
playground storage [flash|sd]

Press / to search, Enter to open an application, and use the actions shown in the bottom bar. Press i on an application in the catalog tree or details page to install it, and u to uninstall it after confirmation. Packages are verified by size and SHA-256 and installed under /playground/ on the permanently configured flash or sd storage. Community scripts run with the normal permissions of their runtime and are not sandboxed.

Catalog and application files are stored under /playground/ on the selected filesystem. playground delete recursively removes that entire directory, clears the loaded catalog from memory, and also removes the legacy hidden .solar/playground directory when present. Source and storage preferences are retained.

The shell subcommands use the local catalog for browsing and installation: refresh downloads and saves it, reload loads that saved copy without network access, search prints matches, and install downloads and verifies an application by ID. run reads an installed application's own manifest, so it does not require a catalog reload. It launches the declared Python or Lua runtime without creating a Playground session. Installation also adds the app ID to the managed /.shell/playground aliases, so qr-share --file /notes/wifi.txt is equivalent to playground run qr-share --file /notes/wifi.txt. Uninstalling removes the generated alias. Arguments are forwarded unchanged to the selected script. Opening the TUI reloads the saved catalog automatically and does not refresh it. At the top-level catalog tree, Esc, q, and the app-exit key exit Playground.

playground storage shows the persistent catalog and default application storage. Set it with playground storage flash or playground storage sd. Without a saved preference, Playground selects SD when it is mounted and flash otherwise. Omitting the install target, or specifying auto, uses the selected setting.

See Playground for controls, storage layout, source selection, and the trust model.

python

Embedded MicroPython runtime. It can run an interactive REPL, .py scripts, or .mpy files from storage. Python scripts can use SolarOS service bindings when the selected firmware includes the corresponding packages. Foreground scripts can consume touch coordinates, relative mouse motion, buttons, and joystick axes through solaros.input.

Usage:

python
python file.py [args...]
python file.mpy [args...]

Controls:

reader

Graphical document reader for plain text, Markdown, and EPUB. It remembers reading position and zoom per opened file when storage is available.

Usage:

reader [--pager] <file.txt|file.md|file.epub|man:topic>

With --pager, Up and Down page instead of scrolling one layout row. Each forward page starts with the final visible row from the previous page, so mixed font sizes and wrapped Markdown retain a precise reading overlap.

Controls:

writer

Resumable graphical Markdown editor for PSRAM display boards. Inactive blocks are formatted like reader; the block containing the cursor and every block touched by a selection show their exact Markdown source. edit remains the portable text editor for port shells and boards without graphics or PSRAM.

Usage:

writer [file.md]

Without a path, Writer opens an untitled document and asks for a path on the first save. Existing files larger than 256 KiB are rejected without changing them. Saves use a synced same-directory staging file, backup rename, verified replacement, and rollback. Cursor, scroll anchor, and zoom metadata plus idle recovery snapshots live centrally under /.writer or the active persistent storage root. Writer offers a differing recovery snapshot when the document is opened again. Recovery uses R to recover, D to discard the snapshot, or C to cancel; the unsaved-changes dialog similarly uses S, D, and C.

Controls:

scp

SCP file transfer over SSH. It supports password or key authentication through the shared SSH transport and host lookup/known-host storage. When user@ is omitted, SCP uses the NVS-backed SolarOS identity user. Tab completion reads aliases from /.ssh/hosts, preserves an explicit user@ prefix, and appends : after a unique host match.

Usage:

scp [-P port] local [user@]host:remote
scp [-P port] local [user@]host:
scp [-P port] [user@]host:remote local
scp [-P port] [user@]host:remote-glob dir
scp [-P port] [user@]host:remote

Remote download paths can use * or ?. The local target must be an existing directory for remote wildcard downloads.

SCP runs inline in the shell. Its progress and result remain in the terminal scrollback, and usage errors or a completed transfer return directly to the prompt.

Controls:

sftpsync

Incremental file and directory synchronization over SSH. The SolarOS client uses the server's SFTP subsystem, so it works with a normal SSH server without requiring a matching remote program. It skips regular files whose size and modification time already match. It does not delete destination-only files.

Usage:

sftpsync [-r|-a] [-n] [-P port] local [user@]host:remote
sftpsync [-r|-a] [-n] [-P port] [user@]host:remote local

-r, -a, or --recursive enables directory traversal. -n or --dry-run prints the changes without writing them. -P selects a non-default SSH port. Password and key authentication, known hosts, and aliases in /.ssh/hosts are shared with ssh and scp. A local or remote directory operand names the directory to synchronize; its contents are updated below that path. Traversal is limited to eight nested directory levels. Symbolic links and other special file types are skipped. Active transfers show an updating progress bar for each changed file, followed by the aggregate file and byte counts.

Controls:

sheet

CSV viewer for small data tables. It is intended as a companion to daq logs and simple spreadsheet-like inspection.

Usage:

sheet <file.csv>

Controls:

ssh

Interactive SSH client. It supports password and key authentication, known hosts, hostname lookup through /.ssh/hosts, UTF-8 text, VT-style controls, and remote full-screen terminal applications. When user@ is omitted, SSH uses the NVS-backed SolarOS identity user. Tab completion reads aliases from /.ssh/hosts and preserves an explicit user@ prefix.

Usage:

ssh [user@]host [port]

On display shells, SSH owns a resumable terminal buffer. Switching to the SolarOS shell does not mix the local and remote scrollback, and switching back restores the SSH buffer. On UART and USB CDC port shells, SSH uses the shared port scrollback. Disconnecting returns directly to the local prompt. Remote terminal control sequences still work, including full-screen applications.

Controls:

synth

Open the native synthesizer and sound designer:

synth [--headless]

The app uses the same eight-voice fixed-point engine exposed to Python and Lua, but keyboard and MIDI events reach it directly. On a display, the default graphical interface provides the complete editor described below. --headless suppresses graphical rendering while keeping the same note keys, editing keys, published parameters, control bindings, and MIDI input active. This permits use from a port shell on a headless board after a playback device such as the LEDC PWM audio expansion has been attached. Its Play tab contains the waveform, envelope, volume, ADSR, and piano controls. The Wave tab is a graphical wavetable editor with selectable 16, 32, or 64-point resolution; edits reshape held notes immediately while the piano remains playable, and switching tabs does not rewrite the custom wavetable. The Filter tab adds a resonant low-pass response graph, cutoff, resonance, envelope amount, and an independent graphical ADSR filter envelope. The Oscillator 2 tab adds a second per-note source with waveform, octave, fine detune, and unity-safe mix controls. Both oscillators share the filter and envelopes. The Preset tab provides eight factory sounds and eight persistent user slots. User presets capture both oscillators, both envelopes, the filter, mono/poly mode, glide, and the complete custom wavetable. The Glide tab provides polyphonic or monophonic last-note playback, a hold mode for toggle-style piano keys, and portamento. Hold is session performance state and is not part of a preset. The display also reports active voices, output sample rate, and audio errors. The volume button changes the shared SolarOS speaker volume.

On display targets smaller than 240 pixels wide or 200 pixels high, Synth automatically replaces the full editor with a parameter HUD. The selected control gets a large value and level bar; waveform controls and the Wave tab retain compact graphs; Presets shows one slot at a time. Targets smaller than 112 by 56 pixels use a footer-free micro layout. Physical note keys and MIDI remain active. External parameter/control changes focus the changed parameter until the next local navigation action, which makes a 128-by-64 SH1106 or SSD1306 useful as a synthesizer appliance display. After attaching it as oled0, open Synth on that target with session create synth oled0. During active playing, compact displays defer visualization until note input is quiet so synchronous display transfers cannot take priority over new notes. MIDI notes highlight the matching pitch class on the on-screen piano just like physical note keys.

Controls:

For an external MIDI keyboard, create and start a named MIDI bus before opening Synth:

expansion bus create midi midi0 tx=gpio1 rx=gpio2
job start midi midi0
synth

MIDI Note On/Off, velocity, sustain (CC64), All Sound Off (CC120), and All Notes Off (CC123) are supported on all 16 channels.

Published parameters

While Synth is running, control parameters exposes these native continuous parameters:

These paths exist only while the app is active. Bindings remain configured when Synth is suspended or stopped and reconnect when it resumes. See man controls for control creation, soft pickup, and MIDI CC mappings.

telnet

Telnet client for classic TCP terminal sessions. It supports basic Telnet option negotiation, terminal type reporting, window size reporting, and raw mode.

Usage:

telnet host [port]
telnet -r host [port]

Controls:

view

Graphical image viewer. It supports the image formats compiled into the current firmware, including common PNG/JPEG/GIF/WebP paths and automatic animated GIF playback when the media package is enabled. Images are decoded as RGB on a negotiated indexed-color display and as grayscale on a one-bit display. In the default fit mode, JPEG color conversion writes display-sized output directly, so a large source photograph does not require a full-size RGB destination.

Usage:

view [-fit|-actual] <image>

Controls:

sketch

Pointer-driven graphical paint application. Its layout follows classic desktop paint programs: Save, Open, Import, and the sidebar controls share one aligned, equal-sized button grid; color and pattern choices are in the bottom bar. Sketch uses a compact four-color canvas and stores finished documents as interoperable indexed-color PNG files. Color TFTs show the native palette; one-bit displays use the existing dithered rendering path.

Usage:

sketch
sketch file.png

Sketch is intentionally not gated on a pointer hardware capability. If no ready absolute or relative pointer is registered when the app starts, a popup explains that a pointer can be attached at any time. Press Enter or Esc to dismiss it; the first attached pointer is accepted without restarting the app.

Controls:

web

Simple graphical web browser for lightweight HTML pages. It shares document and image rendering infrastructure with reader where possible. Embedded and direct PNG, JPEG, GIF, and WebP images retain color on indexed-color displays; one-bit displays keep the grayscale decode and dither path.

Usage:

web http://host/
web https://host/path

Controls:

Quick reference

Use apps to list applications installed in the current firmware. Start an app by entering its name and arguments. Use the app-exit key to return to the shell; resumable applications can also be switched through sessions. This page is the complete usage and controls reference for foreground applications.

Join us on: