Plugin Quickstart
Start with liyan plugin init, build and pack an independent plugin, import it into Desktop, review permissions, and ask an AI to call plugin.ping. No PR, integration into LiyanLabs, official catalog registration, or official publication CI is required. Distribute a package matching the user's device platform for local import.
For business tools, continue with the Feishu reference project and add read-only team.botInfo. For Capsule UI, use the science-data reference later on this page. Projects have their own go.mod; identity, tools, and implementation changes stay in your project without rebuilding the host.
The Feishu example retains its existing device-local configuration and message adapter. Channels for new platforms and new Agent Runtimes still require host extensions. See capability types.
Prerequisites
Use a LiyanLabs Desktop / Runner version containing these features and Go 1.25 or later. The minimal template needs no Feishu account or business credentials. Copying Feishu additionally requires Git, its specified Go toolchain, and Python 3 for the resource-editing script. The host CLI and Runner use Rust; Go implements the template and reference plugin.
Local tool providers have no implementation-language allowlist: Rust, Go, Python, and Node.js can implement the same contract. Stdio alone is insufficient. The program must consume the private bootstrap, implement the specified stdio MCP initialization, tool discovery, and calls, and match the declared tool catalog. A configuration registration entrypoint has its own registration protocol. Stdout carries protocol frames only.
An entrypoint must name a bundled program that can launch directly on the target device. Runner does not launch through a shell or locate interpreters on the user's PATH. Current pack collects declared programs and resources; it does not automatically collect arbitrary scripts, interpreters, or pip/npm dependencies. Python / Node.js authors must deliver an executable artifact containing the required runtime and dependencies. Plain python main.py or node index.js projects do not yet have turnkey packaging support. The Go example does not imply official templates or verified execution on every platform for other languages.
Get the repository only when copying Feishu or building the CLI from source. Skip this step when using Desktop's bundled CLI to create the minimal plugin:
For an existing checkout, run git submodule update --init --recursive at its root. Building the CLI uses these submodules. The plugin development commands below use Bash: a terminal on macOS / Linux, or Git Bash on Windows. Run blocks marked PowerShell in PowerShell. Keep the same terminal session so the plugin_cli variable remains available.
Get and Run the CLI
The command is liyan, or liyan.exe on Windows. This executable is also Desktop's Rust Runner. Installing Desktop does not automatically add it to your terminal PATH. Choose one route below, then check its help.
Use the Program Bundled with Desktop
Use a matching Desktop build containing the plugin subcommand. The default macOS installation:
For Beta or RC, use LiyanLabs Beta.app or LiyanLabs RC.app; use the actual path for a custom installation. The Stable Linux deb defaults to /opt/LiyanLabs/resources/liyan; other channels use resources/liyan inside their installation directory. For AppImage, first extract it with its --appimage-extract option, then use squashfs-root/resources/liyan in the extracted directory.
On Windows, choose “Open file location” on the Desktop shortcut to find the installation directory, then enter it in PowerShell:
In Windows Git Bash, use the POSIX path to that same file, for example plugin_cli="/c/your-installation-directory/resources/liyan.exe", then invoke "$plugin_cli".
Build from Source
If the bundled program does not yet include these commands, build from current source. This requires Rust stable and a native C/C++ build toolchain: Visual Studio C++ Build Tools for the Windows MSVC target, Command Line Tools on macOS, or a C compiler and linker on Linux. From the checkout root acquired above:
Windows PowerShell:
These paths assume the default native target. If you explicitly configure a Cargo build target, find the executable in runner/target/<target>/debug/. The Cargo package remains liyanlabs-cli; its executable is liyan.
Check Availability and Set PATH
plugin --help must list init, validate, pack, and doctor. If the file is missing, check the path. If plugin is unrecognized, use a Desktop / Runner build containing the feature or build from source. A version number alone does not establish command availability.
The agent-ready template also requires init to create skills/local-tools-setup/SKILL.md and skills/local-tools-usage/SKILL.md. If your CLI has the older template, update the matching Desktop / Runner or build the current CLI as above. Capabilities at this source commit do not establish availability in an older packaged release.
This tutorial invokes the full "$plugin_cli" path, so a global command is optional. To run liyan directly, add its directory to the current Bash terminal's PATH:
PowerShell:
init / validate / pack require no running Desktop, login, or device connection. doctor and real chat calls require an online, authenticated, matching Desktop / Runner. Desktop manages its own connection; plugin development does not require starting another daemon or manually running connect.
Create Your First Local Plugin
Use the terminal where you set plugin_cli. These examples target Windows x64 and Apple Silicon Mac; the program and pack target must match the execution device. See Build and Pack for other targets.
Windows PowerShell:
macOS Bash:
The template creates plugin.json, configuration.json, tools.json, an icon, an independent Go program, a project README, and declared setup/usage skills/*/SKILL.md files. The setup Skill enables AI-assisted initialization after installation; the usage Skill describes actual tool calls. It implements plugin.ping, returning pong; configuration has no credential fields. init does not compile the program. Validation before building fails because the entrypoint is missing.
Before packing, edit plugin.json: set your own stable name (for example, com.example.my-tools), author.name, and extensions["com.liyanlabs"].displayName. Keep the host extension namespace com.liyanlabs. The template's example provider label needs no host registration. Keep 1.0.0 for the first version.
An agent can edit the JSON directly. Windows PowerShell can also write UTF-8 without BOM explicitly:
Use that same identity in later chat requests. A provider label is not plugin identity; the host isolates identical labels across installations.
Windows PowerShell:
Apple Silicon Mac:
The output directory must not exist yet. Validation should report status: "valid" and packing status: "packed". Distribute release-1.0.0/package.tar.gz; it contains the executable, declarations, and resources.
- Start and sign in to Desktop on the installation device. Open Plugins → Import local plugin and select the archive, or select the already-built project directory.
- Check name, version, and device; confirm installation, review local execution and tool-read permissions, and enable the plugin.
- Open initialization and choose AI assistance or manual configuration. Save a real device profile, including for the empty schema. The minimal template needs no business credentials, Feishu registration, or incoming-message binding; an empty configuration cannot be skipped.
- In a conversation using that device, ask:
Call com.example.my-tools's plugin.ping and report the tool's actual response.Substitute your actual plugin identity. - Check the tool-call record and returned
pong. Validation, a catalog entry, or an AI answeringpongwithout a call do not establish execution.
That real call completes the minimal local development flow. Change both tools.json and the implementation when adding tools. After changing an imported version, bump its version, rebuild, repack, and import again; re-enable after update. Later sections cover updates and diagnostics.
Implement Your Business Tools
First establish a real plugin.ping call. Ordinary tool development needs only this independent project, without a LiyanLabs service stack, database changes, or official signing credentials.
For example, add this read-only element to the complete tools array:
This is one element, not a replacement for the whole file. Keep top-level schema: "liyanlabs.plugin-tools/1" and tools. Implement parsing and validation of arguments.text, then return content: [{"type":"text","text":"the supplied text"}] and isError: false. The template uses go:embed for tool/configuration resources; rebuild after editing them.
Preserve private bootstrap, MCP initialization, discovery and the request loop when adding business logic. Rust, Python or Node.js implementations must satisfy the entire contract and deliver a directly executable artifact. A language-independent boundary does not make arbitrary stdio programs or bare scripts compatible. See tool protocol and runtime artifacts.
Complete First-use Acceptance
Manual steps: initialization → manual configuration → approve requested access → Connect → open the secure configuration window → save natively → check configuration. Save even an empty profile. Users may deny access; the agent must report that state without bypassing it. Ordinary local tools need no incoming-message Agent binding.
AI assistance follows the packaged setup Skill: read status, collect permission answers, request native configuration, wait for actual completion, check and call. Never request secrets in chat or equate a prepared connection request with completed configuration. If a coding agent cannot operate Desktop, deliver the archive's absolute path and the exact native import/confirmation steps. Continue verification from actual state; do not report the entire task complete after packing.
Troubleshooting and Recovery
Record the failing stage, command/operation, exit code or safe error, plugin version and target. Never include secrets, bootstrap or device signature tokens. Doctor observes prior sessions; discoveryVerified: false alone does not establish a broken package. Business success requires a real call.
Copy the Feishu Project
From the repository root, copy into an independent directory outside the checkout:
The reference includes:
Name, Identity, and Icon
Edit these fields in plugin.json, and set your author and version. Identity, the displayed name, and the icon have separate purposes:
Keep the host extension namespace com.liyanlabs, the provider label feishu, and the existing Channel declarations. Separate installations may share labels: complete installation bindings isolate configuration and processes. Labels must be unique within one package.
The reference includes a Feishu image. Replace assets/icon.png to use your own PNG, JPEG or WebP, at most 256 KiB and 1–1024 pixels on each side. Declare a package-relative path with a lowercase .png, .jpg, .jpeg or .webp extension, without links, remote URLs or absolute paths. The image is public presentation metadata; programs and credentials remain on the device. Increment your version and repack after changing presentation. Lists, details and settings navigation then use the new release's name and icon.
Both display fields are optional: an omitted name shows the identity and an omitted icon uses the generic mark. The next script writes this tutorial's name and icon declarations.
Add a Tool
Copy the existing bot identity query and give it a new name and description. This reads the configured application's bot, without reading a personal Feishu account or sending messages:
For new business operations, change the Go implementation too. Declare readOnly truthfully; writes require host approval. Editing generated tools.json alone is insufficient: discovery names, input schemas, and read-only classification must match every declaration. Drift rejects the whole catalog.
Build and Pack
For an Apple Silicon Mac:
Validation reports status: "valid", pluginKey: "com.liyanlabs.team-feishu", target, and digest. Packing reports status: "packed", archive size, and digest. Digests depend on content; do not copy a fixed example value.
pack creates package-manifest.json and package.tar.gz. The authored file remains plugin.json; the generated liyanlabs.plugin-package/2 manifest records file roles, sizes, hashes, and entrypoints. Choose a new output directory outside the project; do not include an earlier archive in a new package. Validation never executes plugin code.
Build for the actual Runner. On Windows, change both provider and registration entrypoints to bin/liyanlabs-plugin-feishu.exe and build that executable. Save discovery output as UTF-8 without BOM; older PowerShell > may produce UTF-16. Cross-compilation alone does not establish platform client acceptance.
The Feishu example retains its working business implementation and configuration flow. If you do not need Feishu, use the minimal local plugin above.
Install and Configure
- In Desktop Plugins, click Import local plugin, then choose the project directory or generated
package.tar.gz. Its name and version are read automatically fromplugin.json; there is no identifier to enter. Review the imported plugin in the catalog. - Check identity, version, and device; finish installation and package activation confirmation. Programs and Skills stay on that Runner. Declarations, hashes, the public icon, and installation metadata go to the server.
- Review local program execution and business-read permissions. Format validation grants no execution permission.
- Open configuration and create a named profile. Scan registration runs in the Desktop native window; an existing application can supply region, App ID, and App Secret. Keep credentials out of AI messages and the project.
- Enable incoming-message consent and choose an Agent separately if needed. Reading bot identity does not require incoming messages.
Package activation, setup completion, and connectivity are separate states. configuration.json drives the native prompt. Registration emits only contracted verification links and configuration results; secure storage stays private to the device. AI setup uses the package's setup Skill without granting permissions automatically.
Invoke and Diagnose
In a conversation using that device, give the AI a bounded read-only task:
The model-facing name may contain a host-generated installation prefix; the plugin receives the original team.botInfo. A call and actual bot response establish execution. Static validation or completed setup do not.
Doctor is optional diagnostics, not a prerequisite for creation, installation or use. When you have the installation operation/API's installation UUID, pass it below; do not substitute plugin identity, release UUID or device UUID. Without that UUID, use the configuration panel and a real chat call for acceptance rather than blocking on doctor:
Dev has a separate channel home:
Doctor connects through the current channel's private diagnostic capability to its authenticated Runner. It reports device state, package confirmation/integrity, and observed sessions/configuration/discovery. It neither reads credentials, starts plugins, nor requests Feishu APIs. configurationObserved: false or discoveryVerified: false may mean no prior call or a busy session, rather than missing configuration. Doctor is not a business-health probe. Without a current Desktop connection it returns plugin_diagnostics_unavailable, never a fabricated success.
See development and debugging for drift, setup failures, and offline recovery.
Update and Uninstall
Bump version after changes, rebuild, export tools, validate and pack, then import the new version on the original device. Published identity/version content is immutable. Re-enable after update or repair; configuration is release/schema-bound and must meet the new version's requirements. Do not bypass confirmation through edited hashes, database state, or old credential bindings.
Uninstall through Plugins. It revokes old processes and requests while other same-label installations retain their own lifecycle. Offline devices make the capability unavailable, with no automatic device switch or server execution. Public third-party download-market publication is outside this stage; distribute matching-platform local packages for user import.
Capsule Client UI
Use plugins/science-data/ as the UI reference. Its independent provider queries PubChem, ChEBI and ChEMBL; client/web and client/native supply React and React Native Capsule views. The current installation graph loads them through apply(ctx, config), with styles, resource subscriptions and cleanup owned by ctx.effect.
Declare id, platform, package-relative entry, files and inject under extensions["com.liyanlabs"].clientModules. Build separate Web/native JavaScript factory registrations, keeping the platform's React and @liyanlabs/plugin-ui external and declared. Build the program and client files before using the same liyan plugin validate / pack commands. Follow the concrete build commands in plugins/science-data/README.md.
Copy science-data outside the repository and customize its plugin identity for local import. Provider and both UI entries form one package; neither official catalog registration nor update-science-data-catalog.mjs is required. With $plugin_cli set, run from the repository root on Windows x64:
Client builds require Node.js and exactly esbuild 0.27.4. The frontend directory above must have dependencies installed. Third parties can instead run npm install --prefix <tool-directory> --save-exact --no-audit --no-fund esbuild@0.27.4 and set SCIENCE_DATA_ESBUILD_ROOT to that absolute directory, without installing the host frontend. Bash uses export SCIENCE_DATA_ESBUILD_ROOT="/absolute/tool-directory"; choose the actual device's executable name and pack target. Type imports are erased during building; runtime dependencies come from declared platform injection. Do not bundle another React instance.
After import, installation, empty configuration and permission review, open the Science data Capsule from the workbench menu, select this installation's connection, and query PubChem for aspirin. Check actual molecule records and the structure image returned by Runner; merely opening the view proves neither query nor image execution. The native entry ships in the same package, but desktop acceptance does not establish phone/tablet acceptance.
UI code runs directly in the client JavaScript realm, so the user must trust its author. ctx.resources shares address-based sources and aborts on last release; ctx.connections.list returns public connection states; ctx.tools.call invokes only currently authorized read-only tools on the exact online Runner. UI acquires no operational credentials or server execution authority. Update, disable, uninstall, permission revocation and offline devices withdraw old modules.
Ask an AI to Develop
Give the agent this page together with the following task. Establish the minimal local flow before adding business tools; no host PR is a prerequisite.
For the Feishu business example: