中文
Create your first plugin

Create your first plugin

Generate an independent Go project and verify node execution

This tutorial creates a Windows Process plugin. A workflow triggers its in port, and a successful invocation continues through done. Prepare Python 3.10+, PowerShell 7, Go, and the Yotta source or development tools matching your host. Use the Go version required by that release's go.mod.

Obtain a fixed SDK

For an unpublished development version, run this in the Yotta repository:

task plugins:export-sdk

Keep the returned version and proxy values. They identify an immutable development SDK and a local Go module proxy, not a public release. Configure your development shell, substituting those values:

$env:GOPROXY = '<proxy from the export>,https://proxy.golang.org,direct'
$env:GONOSUMDB = 'github.com/yottaapp/yotta'

Append to existing GONOSUMDB entries instead of replacing them. For an available released SDK, pin that release and follow its distribution instructions.

Create a project

Run in the Yotta repository. The output directory must not already exist:

python scripts/create-plugin.py `
  --output E:/projects/my-yotta-plugin `
  --module example.com/my-team/my-yotta-plugin `
  --namespace https://plugins.example.com/publishers/my-team `
  --slug my-plugin `
  --name 'My plugin' `
  --sdk-version '<version from the export>'

The sample namespace is for local experiments. Use the publisher namespace belonging to your author account before preparing a marketplace release. The Go module path is separate from that publisher identity.

Add --with-panel --panel-port 18760 to generate a counter panel with button interaction. Select an unused companion port.

Set-Location E:/projects/my-yotta-plugin
go mod tidy
./build.ps1 -Action Check
./build.ps1 -Action Build

Implement the node

plugin.json contains package metadata. cmd/node/main.go owns invocation logic, and cmd/package/main.go declares contracts, ports, configuration and target requirements. Optional panel code lives in internal/paneldefinition, cmd/companion and cmd/package/panel.go. Preserve the pinned go.mod and go.sum.

The guest sequence is NewGuest → ReceiveInvocation → business logic → Succeed or Fail. Standard output carries protocol frames; diagnostics go to standard error. Workflow configuration is declared in the contract schema and read from invocation.ConfigJson; it is separate from build metadata in plugin.json.

Each declared effect needs exactly one matching guest.Record per invocation. Record the real succeeded, failed or cancelled outcome with the contract's EffectId before returning. Calling Succeed without the record causes runtime.journal_failed.

Use authoring.Builtins() for the SDK's exact types and DataInputPort / DataOutputPort for ports. Inputs use value envelopes in invocation.Inputs; InlineJSON reads inline content, and ReplaceInlineJSON preserves the type when replacing it. Output names and types must match the contract.

For host targets, declare ConfiguredTargetSpec and required host features, then use OpenTarget, Invoke and Drop. Use the fixed SDK contracts for kinds, operations and payloads. Declare error contracts and translations, preserve cancellation, and release invocation resources. Put continuous work in a companion.

Verify execution

Run Check, then follow packaging. Import the .ynp under Settings → Plugins and restart the App. Add the node, connect Run started's started port to in, and confirm execution reaches done. For a panel project, open its panel and confirm one click increments the counter once.

Add business tests for valid inputs, boundaries, failures and cancellation. The Yotta repository's cmd/plugin-management-smoke can verify import, reopening a profile and a real run with a built host in a fresh test root. Its starter journey assumes an in trigger and no required configuration; other plugins need a matching journey. Never use an active user profile for smoke tests or equate compilation with successful execution.