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:

git clone --recurse-submodules https://github.com/ScienceOL/Liyan.git
cd Liyan

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:

plugin_cli="/Applications/LiyanLabs.app/Contents/Resources/liyan"
"$plugin_cli" version
"$plugin_cli" plugin --help

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:

$desktopDirectory = Read-Host 'Desktop installation directory'
$plugin_cli = Join-Path $desktopDirectory 'resources/liyan.exe'
& $plugin_cli version
& $plugin_cli plugin --help

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:

cargo build --locked --manifest-path runner/Cargo.toml -p liyanlabs-cli --target-dir runner/target
plugin_cli="$(pwd)/runner/target/debug/liyan"
"$plugin_cli" version
"$plugin_cli" plugin --help

Windows PowerShell:

cargo build --locked --manifest-path runner/Cargo.toml -p liyanlabs-cli --target-dir runner/target
$plugin_cli = (Resolve-Path 'runner/target/debug/liyan.exe').Path
& $plugin_cli version
& $plugin_cli plugin --help

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:

export PATH="$(dirname "$plugin_cli"):$PATH"
liyan plugin --help

PowerShell:

$env:Path = "$(Split-Path -Parent $plugin_cli);$env:Path"
liyan plugin --help

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:

$plugin_work_dir = Join-Path $env:TEMP ('liyan-local-plugin-' + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $plugin_work_dir | Out-Null
& $plugin_cli plugin init (Join-Path $plugin_work_dir 'local-tools') --template local-provider
Set-Location (Join-Path $plugin_work_dir 'local-tools')
$env:GOWORK = 'off'
New-Item -ItemType Directory -Path bin | Out-Null
go build -trimpath -o bin/provider.exe .

macOS Bash:

plugin_work_dir="$(mktemp -d)"
"$plugin_cli" plugin init "$plugin_work_dir/local-tools" --template local-provider
cd "$plugin_work_dir/local-tools"
mkdir -p bin
GOWORK=off go build -trimpath -o bin/provider .

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:

$manifest = Get-Content -LiteralPath plugin.json -Raw | ConvertFrom-Json
$manifest.name = 'com.example.my-tools'
$manifest.author.name = 'My Team'
$manifest.extensions.'com.liyanlabs'.displayName = 'My Local Tools'
[IO.File]::WriteAllText((Join-Path (Get-Location) 'plugin.json'), ($manifest | ConvertTo-Json -Depth 20), [Text.UTF8Encoding]::new($false))

Use that same identity in later chat requests. A provider label is not plugin identity; the host isolates identical labels across installations.

Windows PowerShell:

& $plugin_cli plugin validate .
& $plugin_cli plugin pack . --target windows-x64 --output (Join-Path $plugin_work_dir 'release-1.0.0')
& $plugin_cli plugin validate (Join-Path $plugin_work_dir 'release-1.0.0/package.tar.gz')

Apple Silicon Mac:

"$plugin_cli" plugin validate .
"$plugin_cli" plugin pack . --target darwin-arm64 --output "$plugin_work_dir/release-1.0.0"
"$plugin_cli" plugin validate "$plugin_work_dir/release-1.0.0/package.tar.gz"

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.

  1. 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.
  2. Check name, version, and device; confirm installation, review local execution and tool-read permissions, and enable the plugin.
  3. 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.
  4. 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.
  5. Check the tool-call record and returned pong. Validation, a catalog entry, or an AI answering pong without 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.

FileWhat to changeRequired boundary
plugin.jsonIdentity, version, presentation, resources and entrypointsPackage-relative paths; retain com.liyanlabs
tools.jsonComplete names, descriptions, input schemas and readOnlyMatch every discovered tool; implement every declaration
main.goParse tools/call's params.name and params.arguments, execute and return MCP contentNDJSON protocol only on stdout; logs on stderr
configuration.jsonNative configuration fieldsDevice-native secret entry; consume private bootstrap
bootstrap.goUsually preserve the template implementationNever fabricate installation, device, release or configuration
skills/*/SKILL.mdAccurate setup, usage and recoveryDeclare setup/usage purposes; instructions do not grant access

For example, add this read-only element to the complete tools array:

{
  "name": "local.echo",
  "description": "Return the supplied text from the selected local device.",
  "inputSchema": {
    "type": "object",
    "properties": { "text": { "type": "string", "maxLength": 1024 } },
    "required": ["text"],
    "additionalProperties": false
  },
  "readOnly": true
}

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

StageOperationRequired evidence
Createplugin init, customize identityManifest, source, configuration, tools and declared Skills exist
BuildBuild for the device, validate .valid, your pluginKey, correct target
PackPack and validate the archivepacked; directory/archive package digests agree
ImportDesktop selects archive or built projectYour name/version in the catalog; installation is still separate
InstallOpen that version and Install pluginEnabled and locally confirmed on the selected device
ConfigureAI/manual initializationSaved permission decisions and a real saved device profile
CheckCheck configuration, device onlineNo outstanding permission/configuration requirement; do not fabricate health
InvokeAsk chat on that device to call the toolActual tool-call record and returned pong or business result

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

SymptomRecovery
liyan not foundUse the acquired absolute path and check plugin --help; Desktop does not set PATH
init directory already existsChoose a new project directory; existing content is not overwritten
Missing/unlaunchable entrypointBuild first; use .exe on Windows; match OS/architecture and pack target
Pack output existsChoose a new output directory; published bytes remain immutable
Catalog entry but no installationOpen the imported plugin and install it
AI initialization unavailableInclude and declare a setup Skill; update old packages with a new version
Empty schema still unconfiguredSave a real empty device profile; do not fabricate a connection/version
Tool missing in chatCheck exact installation, confirmation, enabled state, device, configuration, permissions and complete discovery matching
plugin_diagnostics_unavailableUse doctor with the authenticated Desktop's channel home after connection
Local cache lostReimport the exact package on that device and repair; no server/device fallback
Old tools after editingBump version, rebuild, repack, import, update installation, re-enable and call again

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:

plugin_work_dir="$(mktemp -d)"
cp -R plugins/feishu "$plugin_work_dir/team-feishu"
cd "$plugin_work_dir/team-feishu"

The reference includes:

plugin.json                       Author manifest
assets/icon.png                   Bundled presentation icon
configuration.json                Configuration and native registration entrypoint
internal/provider/catalog.json    Feishu operation declarations
internal/provider/                Tools, authentication, and messages
cmd/liyanlabs-plugin-feishu/       Program entrypoint
skills/feishu-setup/SKILL.md        Setup instructions
skills/feishu-usage/SKILL.md        Usage instructions
tools.json                        Public catalog exported from implementation
go.mod / go.sum                   Independent build dependencies

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:

FieldTutorial valueUpdate rule
namecom.liyanlabs.team-feishuStable identity retained across updates
version1.0.0Published content is fixed; increment after changes
extensions["com.liyanlabs"].displayNameTeam FeishuAt most 128 Unicode characters; no blank-only names or control characters
extensions["com.liyanlabs"].iconassets/icon.pngImage inside the project, read automatically during import

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:

python3 - <<'CODE'
import copy, json
from pathlib import Path
manifest_path = Path("plugin.json")
manifest = json.loads(manifest_path.read_text())
manifest["name"] = "com.liyanlabs.team-feishu"
manifest["version"] = "1.0.0"
manifest["extensions"]["com.liyanlabs"]["displayName"] = "Team Feishu"
manifest["extensions"]["com.liyanlabs"]["icon"] = "assets/icon.png"
manifest["author"]["name"] = "Your Team"
manifest_path.write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + "\n")
catalog_path = Path("internal/provider/catalog.json")
catalog = json.loads(catalog_path.read_text())
assert not any(tool["name"] == "team.botInfo" for tool in catalog["tools"])
tool = copy.deepcopy(next(tool for tool in catalog["tools"] if tool["name"] == "bot.v3.info"))
tool["name"] = "team.botInfo"
tool["description"] = "Get this team's configured Feishu application's bot identity. Read only."
catalog["tools"].append(tool)
catalog_path.write_text(json.dumps(catalog, ensure_ascii=False, indent=2) + "\n")
CODE

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:

mkdir -p bin
GOWORK=off go build -trimpath -o bin/liyanlabs-plugin-feishu ./cmd/liyanlabs-plugin-feishu
./bin/liyanlabs-plugin-feishu --describe-tools > tools.json
"$plugin_cli" plugin validate .
"$plugin_cli" plugin pack . --target darwin-arm64 --output "$plugin_work_dir/release-1.0.0"
"$plugin_cli" plugin validate "$plugin_work_dir/release-1.0.0/package.tar.gz"

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.

DeviceGo targetpack target
Apple Silicon MacGOOS=darwin GOARCH=arm64darwin-arm64
Intel MacGOOS=darwin GOARCH=amd64darwin-x64
Linux x64 / ARM64GOOS=linux GOARCH=amd64 / arm64linux-x64 / linux-arm64
Windows x64 / ARM64GOOS=windows GOARCH=amd64 / arm64windows-x64 / windows-arm64

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

  1. In Desktop Plugins, click Import local plugin, then choose the project directory or generated package.tar.gz. Its name and version are read automatically from plugin.json; there is no identifier to enter. Review the imported plugin in the catalog.
  2. 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.
  3. Review local program execution and business-read permissions. Format validation grants no execution permission.
  4. 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.
  5. 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:

Use com.liyanlabs.team-feishu's team.botInfo to query the configured application's bot identity.
Read only; do not send messages or change configuration. Report the actual returned app name and status.

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:

"$plugin_cli" plugin doctor --installation '<installation-uuid>'

Dev has a separate channel home:

"$plugin_cli" plugin doctor --installation '<installation-uuid>' --home "$HOME/.liyanlabs-dev"

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:

$capsule_work_dir = Join-Path $env:TEMP ('liyan-capsule-' + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $capsule_work_dir | Out-Null
Copy-Item -LiteralPath 'plugins/science-data' -Destination (Join-Path $capsule_work_dir 'science-data') -Recurse
$env:SCIENCE_DATA_ESBUILD_ROOT = (Resolve-Path 'frontend').Path
Set-Location (Join-Path $capsule_work_dir 'science-data')
$manifest = Get-Content -LiteralPath plugin.json -Raw | ConvertFrom-Json
$manifest.name = 'com.example.local-science'
$manifest.author.name = 'My Team'
$manifest.extensions.'com.liyanlabs'.displayName = 'My Science Data'
$manifest.extensions.'com.liyanlabs'.localProviders[0].entrypoint.path = 'bin/liyanlabs-plugin-science-data.exe'
[IO.File]::WriteAllText((Join-Path (Get-Location) 'plugin.json'), ($manifest | ConvertTo-Json -Depth 20), [Text.UTF8Encoding]::new($false))
$env:GOWORK = 'off'
go build -trimpath -buildvcs=false -o bin/liyanlabs-plugin-science-data.exe ./cmd/liyanlabs-plugin-science-data
node client/build.mjs
& $plugin_cli plugin validate .
& $plugin_cli plugin pack . --target windows-x64 --output (Join-Path $capsule_work_dir 'release-1.0.0')
& $plugin_cli plugin validate (Join-Path $capsule_work_dir 'release-1.0.0/package.tar.gz')

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.

Create an independent LiyanLabs local plugin and prove a real call on my selected Desktop.
Check the liyan CLI and Go, then generate an independent project with plugin init.
Set my stable identity, author and display name; retain private bootstrap, protocol loop and setup/usage Skills.
Build plugin.ping, validate the project, pack for the actual device and validate the archive.
Read exit codes and real output at each step; investigate and repair failures before continuing.
Import through Desktop, install and confirm on the selected device, then save permissions and real configuration.
Save empty profiles too; enter secrets only natively. Do not edit the database or disable integrity/permission checks.
Use chat on that device to call plugin.ping and verify the actual pong tool result, then implement my business tools.
Keep input schemas, read/write effects and complete runtime discovery consistent with declarations.
For changed imported content, bump version, rebuild, repack, update installation and re-enable before retesting.
If your tools cannot operate Desktop, deliver the archive's absolute path and exact native confirmation steps.
Deliver source/archive paths, identity/version/target, build/validation output, installation/configuration state and real call evidence.
Do not report full completion without a real call. Add no community, PR, official CI or marketplace prerequisite.

For the Feishu business example:

Read the LiyanLabs plugin Quickstart and capability types in the overview.
Copy plugins/feishu into an independent project outside the checkout, using com.liyanlabs.team-feishu.
Add read-only team.botInfo in the business catalog, retaining the current Feishu Channel contract.
Build inside the project, export tools.json with --describe-tools, validate, pack, and verify the archive.
Do not modify host source or put credentials in packages, chat, logs, or ordinary Web forms.
Import on the user's selected Desktop, complete native setup and permission review, and invoke the new tool.
Report static validation, installation confirmation, and actual call evidence separately; identify unfinished steps.