Skip to content
Lenso
English
Esc
navigateopen⌘Jpreview
On this page

Optional file conventions

Author CLI commands and Agent Tools in Rust or TypeScript while keeping optional dependencies isolated.

Requires the local Engine-enabled CLI and matching support packages described in Local App development. The examples here are implemented locally; they are not a registry release announcement.

A file takes effect when support is selected

An application selects a support Plugin; that Plugin supplies filename matching and lowering. Other Plugins can include cli.rs, Console pages or Agent Tool entries without forcing every consumer to adopt those surfaces. Engine owns generic processing; each support Plugin owns its interpretation.

A simple Plugin has one Cargo.toml or package.json. Heavy optional dependencies need independently buildable surface packages declared through surfaces metadata or a composite plugin.json. Unselected independent surfaces are not parsed, installed, compiled or bundled. Dependencies already imported by the core or included in its Cargo workspace remain in that build. File naming alone cannot remove a dependency that the core already requires.

Generic Engine processors can handle other languages, but App runtime support still depends on the selected SDK, execution Adapter and Host admission.

CLI commands

lenso app create my-cli --cli
cd my-cli
lenso app dev -- hello --name Ada
# After stopping development:
lenso app build
lenso app start --from dist -- hello --name Ada

The scaffold includes app/local.hello/cli.ts:

import { command } from '@lenso/cli';
export default command({
  name: 'hello',
  description: 'Say hello',
  args: { name: { type: 'string', default: 'world' } },
  run({ args, output }) { output.text(`Hello, ${args.name}!`); },
});

For an existing App, lenso app add @lenso/cli adopts the CLI support bundled with the executable. It is not a marketplace lookup. A bare App-local directory can contain only cli.ts or cli.rs; reusable packages should keep explicit identities. Generated path-based identities change when their paths change.

Rust cli.rs can use the selected support’s macro:

use lenso_cli_support::command;

/// Say hello from Rust
#[command(name = "hello-rust")]
async fn hello(#[arg(long, default = "world")] name: String)
    -> anyhow::Result<String>
{
    Ok(format!("Hello, {name}!"))
}

One annotated function generates the entry factory. Typed arguments use FromStr; Option<T> is optional and bool is a flag. Rust source requires Cargo. Programmatic command builders and the underlying terminal Provider remain available. Exercise terminal Stream commands through the App, rather than standalone Request-only plugin dev.

Agent Tool entries

After explicitly adopting matching Agent Tool convention support, a Plugin may provide agent/tools.ts:

import { tool, tools } from '@lenso/agent-tool-sdk';
import * as schema from '@lenso/agent-tool-sdk/schema';

export default tools([
  tool({
    name: 'greet', description: 'Greet a person.',
    input: schema.object({ name: schema.string() }), output: schema.string(),
  }, ({ name }) => ({ ok: true, value: `Hello, ${name}!` })),
]);

The Agent repository owns packages/agent-tool-convention and executable examples/app-tools / examples/app-tools-rust fixtures. Rust entries use #[lenso_agent_tool_sdk::tool_provider] with #[tool] methods. Use the matching fixture for its exact SDK dependencies and generated registration.

Compilation produces ordinary Tool providers. A consuming Agent must install and select the provider and explicitly grant tool policy. Discovery does not start an Agent, choose a Model or authorize execution. The local fixture proof covers a real Turn, allowed execution, denial before execution, and provider removal. It currently relies on a local Bun Adapter fix; public installation requires released dependencies containing that fix.

For browser surfaces and backend service adapters, continue with App Console. For an ordinary provider or consumer, keep using Plugin authoring.

Last updated on September 19, 2026

Was this page helpful?