name: yanzi-extension-dev
description: Build, inspect, edit, and install Yanzi extensions. Use when an agent needs to create or modify manifest.json, author C# or PowerShell extensions, call Yanzi's local extension HTTP API, or troubleshoot extension loading and execution.
Yanzi Extension Development
Use this skill when working on local extensions for Yanzi.
Quick Start
Yanzi stores runtime extensions under the app's Extensions/ directory. On Windows development/runtime environment, the actual path is %LOCALAPPDATA%\OpenQuickHost\Extensions\ (and configuration/storage files under %LOCALAPPDATA%\OpenQuickHost\). The Local Agent API authentication Token is located in %LOCALAPPDATA%\OpenQuickHost\appsettings.local.json under the "agentApiToken" field. Each extension lives in its own folder.
Two extension shapes are supported:
- JSON extension
- C# or PowerShell action extension
- Hosted view extension
For lightweight action extensions inside a single manifest.json, choose the runtime by task:
- use
runtime = csharpfor complex logic, JSON/HTTP/file processing, native WPF windows, P/Invoke, and strongly typed .NET APIs - use
runtime = powershellfor Windows automation, registry/service/process/scheduled-task/system-command work, clipboard/file automation, and tasks with existing PowerShell cmdlets entryMode = inlinescript.source
Minimum layout:
Extensions/
my-extension/
manifest.json
Script extension layout:
Extensions/
my-script/
manifest.json
main.ps1
Manifest Model
Common fields:
idnameversioncategorydescriptionkeywordsglobalShortcuthotkeyBehavior
JSON action fields:
openTargetqueryPrefixesqueryTargetTemplate
Script fields:
runtimeentryModeentryscript.sourcepermissions
Hosted view fields:
hostedView.typehostedView.titlehostedView.descriptionhostedView.inputLabelhostedView.inputPlaceholderhostedView.outputLabelhostedView.actionButtonTexthostedView.actionTypehostedView.emptyState
Web app fields:
app.typeapp.entryapp.singleInstanceapp.window.widthapp.window.heightapp.window.minWidthapp.window.minHeight
Read references/manifest.md when editing manifests.
Script Execution
Current script runtimes:
csharppowershell
Choose the runtime by task. C# is best for complex logic, native windows, P/Invoke, and strongly typed .NET APIs. PowerShell is often simpler and more reliable for Windows automation, registry/service/process/scheduled-task/system-command work, and tasks with existing cmdlets. If the task is essentially a cmd/bat command sequence, wrap it with PowerShell or use an external script entry instead of forcing C#.
Capability strategy:
- Prefer native language/system capabilities for feature implementation: C#/.NET/WPF/Windows APIs for complex app logic; PowerShell/cmdlets for system automation.
- Treat
YanziActionContextas a small host concierge API for input, launch metadata, extension directories, state, and local/cloud storage. - Do not invent host wrapper methods such as
context.SetTheme(),context.GetTheme(),context.OpenFilePicker(),context.ShowMessage(), orcontext.GetStateAsync<T>(). - For windows, dialogs, file pickers, clipboard, processes, registry, HTTP, system settings, and Win32 calls, write native C# directly unless the manifest/reference docs explicitly name a host API.
- The compiler injects the runtime namespace for
YanziActionContext; extension source should not add host runtime usings. The app assembly isYanzi; do not generate legacy product-name pack URIs, assembly references, resource paths, or assumed theme dictionaries.
Inline C# example:
{
"id": "csharp-echo",
"name": "C# 输入回显",
"runtime": "csharp",
"entryMode": "inline",
"permissions": [],
"script": {
"source": "public static class YanziAction\\n{\\n public static Task<string> RunAsync(YanziActionContext context)\\n {\\n return Task.FromResult(context.InputText);\\n }\\n}"
}
}
C# entry contract:
public static class YanziAction
{
public static Task<string> RunAsync(YanziActionContext context)
}
Entry file example:
{
"id": "script-clipboard",
"name": "读取剪贴板",
"runtime": "powershell",
"entry": "main.ps1",
"permissions": ["clipboard.read"]
}
PowerShell conventions:
param(...)must be the first statement- then set output encoding if needed
- write user-facing result to stdout
- write failure detail to stderr or throw
The host passes:
-InputText-ContextPath- env
YANZI_INPUT - env
YANZI_CONTEXT_PATH - env
YANZI_EXTENSION_ID - env
YANZI_EXTENSION_DIR - env
YANZI_LAUNCH_SOURCE
Read references/script-extensions.md when authoring scripts.
Local Agent API
Yanzi exposes a localhost HTTP API for extension CRUD. It is intended for same-machine agents.
Default:
- base URL:
http://127.0.0.1:53919 - header:
X-Yanzi-Token
Useful endpoints:
GET /healthGET /v1/extensionsGET /v1/extensions/templateGET /v1/extensions/{id}POST /v1/extensionsPUT /v1/extensions/{id}PATCH /v1/extensions/{id}/renamePATCH /v1/extensions/{id}/shortcutDELETE /v1/extensions/{id}
Read references/local-agent-api.md for request and response shapes.
Encoding Considerations
When communicating with the local agent API (especially using legacy clients like Windows PowerShell 5.1), requests with non-ASCII text (e.g. Chinese characters) may cause encoding issues (garbled characters / 乱码) because the client defaults to sending ANSI/GBK payload instead of UTF-8.
To prevent encoding issues:
- Always specify '; charset=utf-8' in the 'Content-Type' header (e.g. '"Content-Type": "application/json; charset=utf-8"').
- Manually encode the payload to a UTF-8 byte stream before sending it as the request body. For PowerShell:
$bodyBytes = [System.Text.Encoding]::UTF8.GetBytes($jsonPayload) Invoke-RestMethod -Uri "..." -Method Post -Headers $headers -Body $bodyBytes
Working Rules
- CRITICAL: When creating a NEW extension, you MUST use the Local Agent API (
POST /v1/extensions) rather than directly writing files to the disk. Creating extensions via the API ensures the host application correctly registers them and applies the "Recently Added" sorting boost (置顶排列) so the user sees them at the top of their list. After creation, you may edit the files directly. - CRITICAL: When using
ProcessStartInfoto call external processes (like ADB) from C# extensions, ensure that you explicitly setStandardOutputEncoding = System.Text.Encoding.UTF8;(andStandardErrorEncoding) and useReadToEndAsync()to prevent Chinese character garbling (中文乱码). - CRITICAL: If you execute
dotnet buildto compile the host application or an extension, you MUST automatically launch the compiled application (e.g.,Start-Processordotnet run) immediately afterwards, so the user doesn't have to restart it manually. - Prefer editing extension folders through the local API when you are acting as an external agent.
- When working inside the Yanzi codebase, update both the runtime behavior and the bundled skill docs if behavior changes.
- Prefer C# inline actions for new extensions unless the task is specifically Windows shell automation. For complex or large extensions, prefer multi-file format (e.g.
entryMode = entrypointing tomain.cs) over inline source to maintain code clarity. - For PowerShell extensions, keep files ASCII unless non-ASCII output is required; when Chinese text is required, ensure the file is written with BOM-compatible UTF-8 handling.
- When debugging inline scripts, prefer using the editor test flow first, then inspect
logs/host.loganddev-debug.logon the development machine. - C# extensions loaded via in-process AssemblyLoadContext persist in memory. If your extension registers global event hooks (e.g. keyboard/mouse hooks via Win32
SetWindowsHookEx), use astaticmanager to keep the hook alive and running in the background even afterRunAsynccompletes or the setting window closes.