lenso-cli
The CLI for authoring Plugins and changing an App through its plugins/
directory.
Install
# or
The Cargo and npm packages use independent version lines.
Author one Plugin
The generated project is ordinary typed Rust in src/lib.rs. The portable SDK
owns Wasm Component lowering, WIT, Capability descriptors, schema projection,
and Process wire dispatch at compile time; target-specific generated files are
not checked into the Plugin project.
By default, one editable src/lib.rs produces both portable Wasm and trusted
Process implementations. dev builds only the fastest declared local
implementation (Process for a multi-output Rust project); use
--implementation wasm|process|all when selecting or comparing a path.
File notifications with debounce drive --watch, with bounded polling only as
a platform fallback. check and pack still build every declared
implementation, and pack places both in
one V3 .lenso-plugin Release; the Host selects one implementation before Plan
resolution and never falls back after startup. Legacy single-output projects
remain readable.
Author one Web Plugin
# In another terminal, call one of the printed HTTP routes.
This path generates a linked native Rust Plugin with #[lenso::plugin] and a
typed #[endpoint] implementation. Its starter operations demonstrate both
#[post] and body-carrying #[query] requests, typed success responses, and
RFC 9457 Problem responses. The generated test uses EndpointTest, so the
Plugin is exercised without opening a socket.
lenso plugin dev builds a temporary native Host, mounts the generated Plugin
through Web Ingress, prints its real listener address and route table, and emits
request ID, method, path, status, and latency for each request. Add --watch to
rebuild and restart after source changes.
Web Plugins are linked into a Host and mounted through its web root slot;
they are not portable Agent Tool bundles, so the generated README does not
direct users to lenso plugin pack.
pack writes one portable .lenso-plugin archive, then extracts, validates,
and reopens its exact contents. plugins add accepts that archive and legacy
Bundle directories. A
receiving Host independently validates those bytes again during installation.
check and dev use development artifacts; pack is the
release-profile proof and remains the only distribution build.
New Plugins and catalog Releases use the canonical namespaced Plugin ID v1
grammar (company.uppercase) and exact Semantic Versions. Existing
unnamespaced projects remain readable with an explicit migration warning; see
docs/migration-plugin-authoring.md.
Author a Host in TypeScript
The initial TypeScript Host authoring path
adds lenso app build for static defineHost declarations and verified Plugin
bundles. Hosts stay closed unless exact extension releases are admitted, with
Instance limits and optional effective-configuration ceilings. The same authority
is consumed by check, configure, and installation. lenso app prepare turns that
output plus explicit precompiled target artifacts and notices into a new,
digest-locked directory with a generated host.js, same-cohort resolver, and
Instance-addressed selected Plugin artifacts. The coordinated Bun runtime branch
assembles and recovers the admitted Generation and preserves named dependency
imports; released artifact cohorts are not included yet.
Change an App
The current Host supplies useful defaults and a generated Host Catalog. An App
owner writes only differences under plugins/:
Configuration lives at plugins/<plugin-id>/<instance>.toml; an empty file
enables package defaults. <instance>.disabled is the explicit absence marker.
Optional structured files live beside it under
plugins/<plugin-id>/<instance>/; app check validates the bounded regular-file
tree before the Host snapshots it into a Generation.
Named single-dependency choices live in plugins/.dependencies.json and are
changed through plugins bind. They preserve exact provider intent, including
explicit absence for optional requirements, across unrelated installations.
Use plugins bind --file ... --preview to validate and display a complete
migration before publishing it atomically.
Installed non-embedded behavior carries one exact plugin.lenso-plugin Bundle
inside its Plugin directory.
Catalog installation always requires an exact version. Downloaded archive and
manifest digests are checked before candidate resolution; admitted archives are
retained under .lenso/plugin-store/ so update and rollback never depend on a
mutable remote. There is no implicit latest-version selection or runtime
fallback.
The Host Catalog at .lenso/host-catalog.json is generated and locked to the
current Host build. It is read-only execution authority, not App intent.
app check, app show, and run derive the App directly; there is no Plan
file for an App owner to generate or manage.
Runtime Drivers and Execution Adapters remain separate because they implement Host mechanics, not application behavior.
App commands
The CLI keeps its authoring and maintenance roots static: plugin, plugins,
app, run, and doctor. Any other root command is validated against the
current App and forwarded unchanged to .lenso/host. The Host's selected
lenso.terminal.command aggregate and lenso.terminal.cli surface own dynamic
catalog discovery, help, argument parsing, execution, and the Generation lease.
For example, a Host with a selected Session command provider may expose
lenso sessions list and lenso sessions show --help. Removing that provider
removes those paths without changing this CLI. Static maintenance roots remain
reserved and cannot be shadowed by App commands.