PageSourceSearch

https://docs.hyperspin-fe.com/assets/js/bb0c0ea3.98f71024.js

js hyperspin-fe.com collected 2026-10-03 22:24:48 UTC 14,974 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkhyperspin_docs=self.webpackChunkhyperspin_docs||[]).push([[613],{28453:(e,n,t)=>{t.d(n,{R:()=>l,x:()=>o});var r=t(96540);const s={},i=r.createContext(s);function l(e){const n=r.useContext(i);return r.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:l(e.components),r.createElement(i.Provider,{value:n},e.children)}},67069:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>l,metadata:()=>r,toc:()=>a});const r=JSON.parse('{"id":"plugins/quick-start","title":"Quick Start Guide","description":"Build a small executable plugin, install it locally, and confirm HyperHQ can talk to it.","source":"@site/docs/plugins/quick-start.md","sourceDirName":"plugins","slug":"/plugins/quick-start","permalink":"/docs/plugins/quick-start","draft":false,"unlisted":false,"editUrl":"https://github.com/HyperSpin-LLC/HyperSpin-Docs/tree/main/docs/plugins/quick-start.md","tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"sidebar_position":2},"sidebar":"pluginSidebar","previous":{"title":"HyperHQ Plugin Developer Onboarding","permalink":"/docs/plugins/onboarding"},"next":{"title":"HyperHQ Plugin Developer Guide","permalink":"/docs/plugins/developer-guide"}}');var s=t(74848),i=t(28453);const l={sidebar_position:2},o="Quick Start Guide",d={},a=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Step 1: Create the Plugin Folder",id:"step-1-create-the-plugin-folder",level:2},{value:"Step 2: Add a Manifest",id:"step-2-add-a-manifest",level:2},{value:"Step 3: Build the Executable",id:"step-3-build-the-executable",level:2},{value:"Step 4: Connect and Authenticate",id:"step-4-connect-and-authenticate",level:2},{value:"Step 5: Test in HyperHQ",id:"step-5-test-in-hyperhq",level:2},{value:"Common Issues",id:"common-issues",level:2},{value:"Plugin doesn't appear",id:"plugin-doesnt-appear",level:3},{value:"Authentication fails",id:"authentication-fails",level:3},{value:"Plugin starts but does nothing",id:"plugin-starts-but-does-nothing",level:3},{value:"Next Steps",id:"next-steps",level:2}];function c(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",mermaid:"mermaid",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"quick-start-guide",children:"Quick Start Guide"})}),"\n",(0,s.jsx)(n.p,{children:"Build a small executable plugin, install it locally, and confirm HyperHQ can talk to it."}),"\n",(0,s.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"HyperHQ installed and running"}),"\n",(0,s.jsx)(n.li,{children:"A language/runtime supporting your target operating system"}),"\n",(0,s.jsxs)(n.li,{children:["For Linux, follow the ",(0,s.jsx)(n.a,{href:"/docs/linux/release-requirements#plugins-and-templates",children:"plugin release requirements"}),". Windows executable examples below need a Linux build and matching manifest entry."]}),"\n",(0,s.jsx)(n.li,{children:"A Socket.IO client library for your language"}),"\n",(0,s.jsx)(n.li,{children:"Basic JSON knowledge"}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"Official starter docs are available for:"}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Template"}),(0,s.jsx)(n.th,{children:"Best For"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"../templates/go-starter",children:"Go Starter"})}),(0,s.jsx)(n.td,{children:"Small self-contained binaries"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"../templates/csharp-starter",children:"C# Starter"})}),(0,s.jsx)(n.td,{children:".NET integrations on Windows or Linux"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"../templates/python-starter",children:"Python Starter"})}),(0,s.jsx)(n.td,{children:"Fast prototypes and scripts"})]})]})]}),"\n",(0,s.jsx)(n.h2,{id:"step-1-create-the-plugin-folder",children:"Step 1: Create the Plugin Folder"}),"\n",(0,s.jsx)(n.p,{children:"HyperHQ loads one plugin per folder. For a local install, that folder goes under your HyperSpin install directory:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-text",metastring:'title="Folder layout"',children:"HyperSpin/\r\n\u2514\u2500\u2500 plugins/\r\n    \u2514\u2500\u2500 my-plugin/\r\n        \u251c\u2500\u2500 plugin.json\r\n        \u251c\u2500\u2500 MyPlugin.exe    # Windows package\r\n        \u251c\u2500\u2500 MyPlugin        # Linux package\r\n        \u251c\u2500\u2500 icon.png        # optional\r\n        \u2514\u2500\u2500 README.md       # optional\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Use the HyperSpin root shown in Settings, Paths. Default plugin roots are ",(0,s.jsx)(n.code,{children:"C:/ProgramData/Hyper
1Spin/plugins/"})," on Windows and ",(0,s.jsx)(n.code,{children:"~/HyperSpin/plugins/"})," on Linux. Use your configured root for a custom installation."]}),"\n",(0,s.jsxs)(n.p,{children:["The folder name should be stable. The plugin ID inside ",(0,s.jsx)(n.code,{children:"plugin.json"})," must be unique. If you ship multiple platform builds, list them with ",(0,s.jsx)(n.code,{children:"executableProviders"})," so HyperHQ can launch the right file."]}),"\n",(0,s.jsx)(n.mermaid,{value:'flowchart TD\r\n    Folder["Create plugin folder"] --\x3e Manifest["Add plugin.json"]\r\n    Manifest --\x3e Build["Build executable"]\r\n    Build --\x3e Install["Copy folder to HyperSpin/plugins"]\r\n    Install --\x3e Launch["Open HyperHQ"]\r\n    Launch --\x3e Test["Run the plugin Test action"]\r\n\r\n    style Folder fill:#06b6d4,stroke:#0891b2,stroke-width:2px,color:#000\r\n    style Manifest fill:#a9aeff,stroke:#8b92ff,stroke-width:2px,color:#000\r\n    style Test fill:#10b981,stroke:#059669,stroke-width:2px,color:#fff'}),"\n",(0,s.jsx)(n.h2,{id:"step-2-add-a-manifest",children:"Step 2: Add a Manifest"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",metastring:'title="plugin.json"',children:'{\r\n  "id": "my-plugin",\r\n  "name": "My Plugin",\r\n  "version": "1.0.0",\r\n  "author": "Your Name",\r\n  "type": "executable",\r\n  "description": "Adds a focused workflow to HyperHQ.",\r\n  "executable": "MyPlugin.exe",\r\n  "executableProviders": {\r\n    "windows": "MyPlugin.exe",\r\n    "linux": "MyPlugin"\r\n  },\r\n  "communication": {\r\n    "preferred": "socketio",\r\n    "fallback": "stdio",\r\n    "socketio": {\r\n      "enabled": true\r\n    }\r\n  },\r\n  "capabilities": [\r\n    {\r\n      "name": "game-import",\r\n      "description": "Import games from an external source",\r\n      "required": false\r\n    }\r\n  ],\r\n  "permissions": [\r\n    {\r\n      "type": "network",\r\n      "scope": "external-api",\r\n      "description": "Connect to the configured service"\r\n    }\r\n  ],\r\n  "settings": [\r\n    {\r\n      "key": "enabled",\r\n      "label": "Enabled",\r\n      "type": "boolean",\r\n      "defaultValue": true\r\n    }\r\n  ],\r\n  "actions": [\r\n    {\r\n      "id": "sync_games",\r\n      "label": "Sync Games",\r\n      "description": "Run the import workflow"\r\n    }\r\n  ]\r\n}\n'})}),"\n",(0,s.jsx)(n.p,{children:"Keep the manifest honest. If a plugin needs network access, filesystem access, credentials, or process launching, say so clearly."}),"\n",(0,s.jsx)(n.h2,{id:"step-3-build-the-executable",children:"Step 3: Build the Executable"}),"\n",(0,s.jsx)(n.p,{children:"Use the command that matches your template or language:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",metastring:'title="Go on Linux"',children:"go build -o MyPlugin\n"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-powershell",metastring:'title="Go on Windows"',children:"go build -o MyPlugin.exe\n"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",metastring:'title="C# on Linux x64"',children:"dotnet publish -c Release -r linux-x64 --self-contained true -p:PublishSingleFile=true\n"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-powershell",metastring:'title="C# on Windows x64"',children:"dotnet publish -c Release -r win-x64 --self-contained -p:PublishSingleFile=true\n"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",metastring:'title="Python"',children:"pip install pyinstaller\r\npyinstaller --onefile --name MyPlugin plugin.py\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Build Python executables on the target operating system. Set ",(0,s.jsx)(n.code,{children:"executableProviders"})," to the actual output filename. For C#, this depends on the project assembly name. Preserve required files from the publish directory."]}),"\n",(0,s.jsx)(n.h2,{id:"step-4-connect-and-authenticate",children:"Step 4: Connect and Authenticate"}),"\n",(0,s.jsx)(n.p,{children:"When HyperHQ launches an executable plugin, it provides the connection details through environment variables."}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Variable"}),(0,s.jsx)(n.th,{children:"Purpose"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"HYPERHQ_PLUGIN_ID"})}),(0,s.jsx)(n.td,{children:"Plugin ID from the manifest"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"HYPERHQ_AUTH_CHALLENGE"})}),(0,s.jsx)(n.td,{children:"One-time challenge used to authenticate"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"HYPERHQ_SOCKET_PORT"})}),(0,s.jsx)(n.td,{children:"Local Socket.IO port"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"HYPERHQ_PLUGIN_NAME"})}),(0,s.jsx)(n.td,{children:"Display name from the manifest"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"HYPERHQ_PLUGIN_VERSION"})}),(0,s.jsx)(n.td,{children:"Version from the manifest"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"PLUGIN_SETTINGS"})}),(0,s.jsx)(n.td,{children:"Serialized plugin settings for the current launch"})]})]})]}),"\n",(0,s.jsx)(n.p,{children:"For stdio-mode plugins, HyperHQ sends JSON requests over stdin/stdout instead. Socket.IO is the better default for real-time progress and longer workflows."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-javascript",metastring:'title="Generic Socket.IO flow"',children:"import { io } from 'socket.io-client';\r\n\r\nconst pluginId = process.env.HYPERHQ_PLUGIN_ID || 'my-plugin';\r\nconst challenge = process.env.HYPERHQ_AUTH_CHALLENGE;\r\nconst port = process.env.HYPERHQ_SOCKET_PORT || '52789';\r\nconst socket = io(`http://localhost:${port}`, { reconnection: true });\r\n\r\nsocket.on('connect', () => {\r\n  socket.emit('authenticate', { pluginId, challenge });\r\n});\r\n\r\nsocket.on('authenticated', (response) => {\r\n  if (!response.success) {\r\n    console.error('Authentication failed:', response.error);\r\n    return;\r\n  }\r\n\r\n  sessionToken = response.sessionToken;\r\n});\r\n\r\nsocket.on('request', async (message) => {\r\n  const result = await handleRequest(message);\r\n\r\n  socket.emit('response', {\r\n    id: message.id,\r\n    type: 'response',\r\n    data: result\r\n  });\r\n});\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Notice the URL uses the default Socket.IO namespace. Do not append ",(0,s.jsx)(n.code,{children:"/plugin"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"step-5-test-in-hyperhq",children:"Step 5: Test in HyperHQ"}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsx)(n.li,{children:"Restart HyperHQ."}),"\n",(0,s.jsxs)(n.li,{children:["Open ",(0,s.jsx)(n.strong,{children:"Settings -> Plugins"}),"."]}),"\n",(0,s.jsx)(n.li,{children:"Find your plugin."}),"\n",(0,s.jsx)(n.li,{children:"Run the test action."}),"\n",(0,s.jsx)(n.li,{children:"Check plugin logs if authentication or launch fails."}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"common-issues",children:"Common Issues"}),"\n",(0,s.jsx)(n.h3,{id:"plugin-doesnt-appear",children:"Plugin doesn't appear"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Check ",(0,s.jsx)(n.code,{children:"plugin.json"})," is valid JSON."]}),"\n",(0,s.jsxs)(n.li,{children:["Make sure the folder is under the correct ",(0,s.jsx)(n.code,{children:"plugins/"})," directory."]}),"\n",(0,s.jsxs)(n.li,{children:["Confirm ",(0,s.jsx)(n.code,{children:"id"}),", ",(0,s.jsx)(n.code,{children:"name"}),", ",(0,s.jsx)(n.code,{children:"version"}),", ",(0,s.jsx)(n.code,{children:"type"}),", and ",(0,s.jsx)(n.code,{children:"executable"})," are present."]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"authentication-fails",children:"Authentication fails"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Read ",(0,s.jsx)(n.code,{children:"HYPERHQ_AUTH_CHALLENGE"})," from the environment."]}),"\n",(0,s.jsxs)(n.li,{children:["Connect to the port in ",(0,s.jsx)(n.code,{children:"HYPERHQ_SOCKET_PORT"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["Use the default namespace: ",(0,s.jsx)(n.code,{children:"http://localhost:${port}"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["Emit ",(0,s.jsx)(n.code,{children:"authenticate"})," immediately after the Socket.IO connection opens."]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"plugin-starts-but-does-nothing",children:"Plugin starts but does nothing"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Confirm it listens for ",(0,s.jsx)(n.code,{children:"request"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["Respond with ",(0,s.jsx)(n.code,{children:"response"}),", not ",(0,s.jsx)(n.code,{children:"plugin:response"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["Include the original request ",(0,s.jsx)(n.code,{children:"id"})," in every response."]}),"\n",(0,s.jsxs)(n.li,{children:["Send ",(0,s.jsx)(n.code,{children:"statusUpdate"})," during long operations."]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"next-steps",children:"Next Steps"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Read the ",(0,s.jsx)(n.a,{href:"./socketio-guide",children:"Socket.IO Guide"})," for the full event contract."]}),"\n",(0,s.jsxs)(n.li,{children:["Use the ",(0,s.jsx)(n.a,{href:"./api-reference",children:"API Reference"})," when you need request payloads."]}),"\n",(0,s.jsxs)(n.li,{children:["Start from a ",(0,s.jsx)(n.a,{href:"../templates/overview",children:"template"})," if you want complete working code."]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.