Developers

Genisys plugin format, version 1

Rendered from contracts/plugin.v1.md when this site is built. Try every part of it in the playground, then download the file and import it in the desktop Developer console.

A plugin is one JSON file (*.genisys-plugin.json) holding a manifest and the source of one ES module.

{
  "format": "genisys-plugin@1",
  "manifest": {
    "id": "word-tools",                    // ^[a-z][a-z0-9-]{1,40}$
    "name": "Word tools",                  // 1–60 chars
    "version": "1.0.0",                    // semver x.y.z
    "description": "Counts and cleans words.",
    "tools": [{
      "name": "word_count",                // ^[a-z][a-z0-9_]{1,40}$, unique in the plugin
      "description": "Count the words in a text.",
      "input": { "type": "object", "properties": { "text": { "type": "string" } }, "required": ["text"] },
      "risk": "read"                       // "read" | "act" (act = changes something outside Genisys)
    }],
    "permissions": { "hosts": ["api.example.com"] },   // https hosts ctx.fetch may reach; [] for none
    "skills": [{ "name": "tone-check", "description": "…", "instructions": "Markdown instructions" }]
  },
  "code": "export default { tools: { async word_count(input, ctx) { return { words: input.text.split(/\\s+/).filter(Boolean).length }; } } };"
}

App connections and automation actions

The optional manifest.app adds a REST connection to the existing Developer console, Connections catalog and Automations executor. Open Settings → Developer → Open developer console → App integrations → New app. Fill in the connection, upload a PNG logo and declare actions. A connection-only file uses tools: [], skills: [], permissions: { hosts: [] } and code: "export default {};"; the app actions execute through the authorized HTTP adapter. Plugins can retain ordinary sandbox tools and skills alongside their app declaration.

{
  "baseUrl": "https://api.example.com",
  "auth": "header:X-Api-Key",
  "logo": "",
  "secretLabel": "Scoped API key",
  "keyHelp": "Create an account-scoped key in your app settings.",
  "docs": "https://example.com/docs",
  "actions": [{
    "id": "list_items",
    "name": "List items",
    "description": "Read items visible to the connected account.",
    "method": "GET",
    "path": "/items/{collection}",
    "inputs": [{ "id": "collection", "label": "Collection ID", "in": "path", "required": true }]
  }]
}

baseUrl is a fixed public HTTPS origin without credentials, a port, path or query. The existing guarded fetcher enforces DNS, redirect and private-address restrictions. auth is bearer or a dedicated header:<name>; reserved headers are refused. Users enter keys through Connections into the existing vault. Saving a key reports unchecked until an actual provider verification exists; declarations do not supply OAuth enrollment.

An app declares 1–30 uniquely named actions. IDs match ^[a-z][a-z0-9_]{1,40}$; methods are GET/POST/PUT/PATCH/DELETE. Paths are relative, without queries or traversal, and each {field} requires a corresponding required path input. Inputs use id, label and in (path, query or body), with optional required, type (number/integer/boolean), long, json, list, row, name (body only) and placeholder. Non-GET bodies default to JSON; body: "form" is available in the manifest. GET has no body. Mutations always require action permission; GET can opt into risk: "act". Arbitrary headers, credentials, executable schemas and custom executors cannot be registered through this declaration.

The logo is empty or an inline PNG up to 64 KiB and 512 × 512 pixels. Remote pixels and SVG are refused. The same logo appears in Connections and workflow palettes/nodes, including nested actions and retry wrappers; bundled integrations retain their existing brand assets.

Only enabled, immutable production releases publish app connections/actions. Drafts and previews do not. Connection identity is developer.<plugin-id>.v<major>-<minor>-<patch> and action identity appends .<action-id>. A new version requires a new account binding; existing keys and saved workflow steps cannot silently acquire a changed endpoint or action. Rollback restores the prior binding. Disable/remove withdraws routing while retaining connection records and keys; old saved steps fail unavailable until their version is restored or edited. At most 200 production app connections are admitted; a refused promotion changes no release. Registration adds metadata, not permission, funding or provider acceptance. Local-only runs cannot send through these external actions. Import/export retains genisys-plugin@1 and legacy files without app remain compatible.

The module

export default { tools: { <name>: async (input, ctx) => output } } — one async function per manifest tool. The output must be JSON-serialisable (at most 100 KB as JSON). ctx:

  • ctx.log(...values) — appears in the console's logs (at most 200 lines per call).
  • ctx.fetch(url, { method, headers, body }) → { status, headers, text } — HTTPS only, only to permissions.hosts; the user grants each host once. Performed by Genisys through its SSRF-guarded fetcher; the plugin itself has no network.
  • ctx.stage — "test" | "preview" | "production".

Sandbox

Code runs in an isolated page with no Node, no file system, no network, no storage that outlives the call, and no access to Genisys; only ctx crosses the boundary. Each call has a 10 s limit. Calling a plugin tool from an agent is an integration action with target plugin:<id>, so it is asked for (or granted) like any other tool.

A released plugin's skills are offered to agents as <plugin-id>:<skill-name>: named in the project brief, listed by skill_list and loaded with skill_read, following the same stage rules as its tools. Skills are instructions only; they grant no permissions.

Stages

A plugin has an editable draft (stage test) and up to two frozen releases: a preview version and a production version, served at the same time.

  • test — the draft. Runs in the console's test runner and for test API keys.
  • preview — promoting the draft freezes its version (which must be new and higher than every frozen one) and serves it to agents in the chosen preview projects.
  • production — promoting preview copies that version to production: agents in all other projects and live API keys. Production keeps serving the old version until you promote a new one; rollback points production at any earlier frozen version. Disabling a plugin withdraws it from everyone but the console.

Harness protocol (desktop sandbox and web playground)

The host loads the harness page, then calls __genisys.start(callId, tool, inputJson, stage) and polls __genisys.poll(callId) → { state: "running" } | { state: "fetch", request } | { state: "done", output, logs } | { state: "error", message, logs }; a fetch is answered with __genisys.resolve(callId, responseJson). In an iframe the same calls travel as postMessage({ genisys: "start" | "poll" | "resolve", … }) and replies as { genisys: "state", callId, … }.