Skip to content

Latest commit

 

History

History
136 lines (109 loc) · 5.36 KB

File metadata and controls

136 lines (109 loc) · 5.36 KB

limb host CLI

limb is the host-side half of a limb device: a Rust library and one thin CLI for discovering devices, moving raw pixels and PCM, managing device-carried memory, and installing sandboxed WebAssembly reflexes.

Install the per-user I/O broker after building the CLI:

limb daemon install
limb daemon status
limb list

limbd owns the authenticated UDP gate-notification socket and arbitrates local consumers. It keeps no idle connection to a device, runs no model, and stores no conversation state. Pairing tokens are reloaded on every local request, so pairing or revoking a device does not require a daemon restart.

limb listen is deliberately one transcription cycle, not an assistant. Run it first, then use the device's physical gate gesture. The daemon accepts that gate epoch, drains the device's bounded pre-roll buffer, and sends gated PCM to the selected host-side STT provider. The command emits the first final transcript, closes the gate early, and exits. limb listen --follow keeps the same local subscription across multiple physical gate cycles.

To form a speech loop, choose any command that accepts one speech NDJSON line on stdin and writes its response text to stdout:

limb watch --on-speech 'your-agent --once'

watch holds one --follow subscription for its complete lifetime, invokes that command after each final transcript, and sends its stdout through limb say. The subscription stays present while the command runs and while playback completes, so there is no receive gap between turns. The command owns the model, context, and conversation lifetime; limb remains only the gated pipe.

Exactly one local speech consumer may subscribe to a device. A second listen, watch, or channel account fails immediately with LISTEN_ALREADY_RUNNING and identifies the current owner. An STT, stream, or control failure closes only its gate epoch; the daemon and subscription remain available for the next physical gesture. Use limb daemon clients to inspect ownership and limb daemon logs for broker failures. --direct retains the legacy device-polling path for old firmware and raw diagnostic capture. Integrations may pass listen --consumer NAME; limb list and limb daemon clients then report that stable owner instead of only a child process id.

The device never connects to a speech cloud. Gated PCM travels only from the device to a paired host; the host-side limb listen command chooses an STT provider. Likewise, limb say chooses a host-side TTS provider and sends only the resulting raw PCM to the device. ListenAI is the default provider, not a binding. Edit providers.toml to replace it, or use whisper-local without sending audio to a cloud.

For an incremental text producer, limb say --stream - keeps one provider session and one device audio lease open. Each non-empty stdin line is sent as the next text chunk while PCM is fetched and played concurrently; closing stdin finishes synthesis.

Reflex toolchain

Create a minimal behavior-neutral C project, edit its source and explicit manifest, then compile and audit it locally:

mkdir my-reflex && cd my-reflex
limb reflex init --name my-reflex
limb reflex build
limb reflex check

Every project has the fixed layout reflex.c, manifest.json, and the generated build/reflex.wasm. init creates a .gitignore containing /build/, or preserves an existing file and adds that rule. From another directory, pass only the project root: limb reflex build path/to/reflex.

build invokes a locally installed LLVM clang and wasm-ld; it never downloads a compiler. Set LIMB_CLANG and LIMB_WASM_LD, or pass --clang and --wasm-ld, when the tools are outside PATH. The command fixes the wasm32 freestanding linker flags and writes the output only after checking the ABI 1 import, lifecycle exports, memory bounds, module size, and manifest. check performs the same audit without device discovery. limb push repeats the audit before it opens a device connection.

The generated header exposes only the numeric limb.call syscall. It does not add rendering primitives, fonts, codecs, networking, or a behavior template.

Build and inspect the complete command reference:

cargo build --release -p limb
target/release/limb --help

Tagged CI runs also produce standalone archives for macOS arm64, macOS x86-64, and static Linux x86-64 (musl).

Store a ListenAI API key without putting it in shell history or a process list:

limb config set-credential listenai

The command reads the secret from a terminal prompt and stores it in a user-only credential file. LISTENAI_API_KEY overrides the stored value for ephemeral use.

See providers.md for the registry format and provider exit paths. See FIRST-CONTACT.md for the clean-environment and physical-device acceptance record.

Applications can use liblimb directly without shelling out:

use liblimb::{ConfigStore, ControlClient, Discovery};
use std::time::Duration;

# async fn inspect() -> liblimb::Result<()> {
let config = ConfigStore::discover()?;
let device = Discovery::new(Duration::from_secs(2))
    .resolve("limb-a1b2c3.local", &config)
    .await?;
let token = config.token(&device.id)?;
let mut control = ControlClient::connect(
    device,
    token.as_ref().map(|record| record.token.as_str()),
)
.await?;
println!("{}", control.describe().await?);
# Ok(())
# }