@nodetool-ai/agents 0.8.4-a24.3 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/dist/.nodetool-build-stamp +1 -1
  2. package/dist/_skills/LICENSE-iart-motion-design-skills +21 -0
  3. package/dist/_skills/README.md +211 -0
  4. package/dist/_skills/api-agents/SKILL.md +58 -0
  5. package/dist/_skills/api-apps/SKILL.md +54 -0
  6. package/dist/_skills/api-assets/SKILL.md +66 -0
  7. package/dist/_skills/api-collections/SKILL.md +33 -0
  8. package/dist/_skills/api-games/SKILL.md +81 -0
  9. package/dist/_skills/api-media/SKILL.md +131 -0
  10. package/dist/_skills/api-memory/SKILL.md +72 -0
  11. package/dist/_skills/api-models/SKILL.md +78 -0
  12. package/dist/_skills/api-scripts/SKILL.md +79 -0
  13. package/dist/_skills/api-settings/SKILL.md +49 -0
  14. package/dist/_skills/api-sketches/SKILL.md +61 -0
  15. package/dist/_skills/api-storyboards/SKILL.md +94 -0
  16. package/dist/_skills/api-timelines/SKILL.md +151 -0
  17. package/dist/_skills/api-web/SKILL.md +57 -0
  18. package/dist/_skills/api-workflows/SKILL.md +123 -0
  19. package/dist/_skills/beat-sync-editing/SKILL.md +208 -0
  20. package/dist/_skills/caption-titles/SKILL.md +94 -0
  21. package/dist/_skills/color-motion/SKILL.md +185 -0
  22. package/dist/_skills/commercial-beat-sheet/SKILL.md +338 -0
  23. package/dist/_skills/elevenlabs-audio-prompting/SKILL.md +163 -0
  24. package/dist/_skills/explainer-storyboard/SKILL.md +63 -0
  25. package/dist/_skills/flux-2-klein-prompting/SKILL.md +107 -0
  26. package/dist/_skills/frame-composition/SKILL.md +291 -0
  27. package/dist/_skills/game-direction/SKILL.md +99 -0
  28. package/dist/_skills/gpt-image-2-prompting/SKILL.md +161 -0
  29. package/dist/_skills/hailuo-prompting/SKILL.md +107 -0
  30. package/dist/_skills/kling-video-prompting/SKILL.md +188 -0
  31. package/dist/_skills/launch-commercial/SKILL.md +267 -0
  32. package/dist/_skills/launch-kit/SKILL.md +120 -0
  33. package/dist/_skills/logo-reveal/SKILL.md +225 -0
  34. package/dist/_skills/manimgx/SKILL.md +123 -0
  35. package/dist/_skills/minimax-h3-prompting/SKILL.md +134 -0
  36. package/dist/_skills/motion-ad/SKILL.md +281 -0
  37. package/dist/_skills/motion-background/SKILL.md +145 -0
  38. package/dist/_skills/motion-curves/SKILL.md +302 -0
  39. package/dist/_skills/motion-direction/SKILL.md +259 -0
  40. package/dist/_skills/motion-graphics/SKILL.md +217 -0
  41. package/dist/_skills/motion-principles/SKILL.md +255 -0
  42. package/dist/_skills/music-video-treatment/SKILL.md +40 -0
  43. package/dist/_skills/nano-banana-pro-prompting/SKILL.md +133 -0
  44. package/dist/_skills/native-game/SKILL.md +310 -0
  45. package/dist/_skills/native-game-reference/SKILL.md +879 -0
  46. package/dist/_skills/nodetool-3d-scene/SKILL.md +110 -0
  47. package/dist/_skills/nodetool-api-reference/SKILL.md +338 -0
  48. package/dist/_skills/nodetool-app-builder/SKILL.md +291 -0
  49. package/dist/_skills/nodetool-browser-agent/SKILL.md +119 -0
  50. package/dist/_skills/nodetool-chat-cli/SKILL.md +184 -0
  51. package/dist/_skills/nodetool-custom-node-developer/SKILL.md +294 -0
  52. package/dist/_skills/nodetool-deployment/SKILL.md +195 -0
  53. package/dist/_skills/nodetool-js-scripting/SKILL.md +223 -0
  54. package/dist/_skills/nodetool-model-provider-config/SKILL.md +348 -0
  55. package/dist/_skills/nodetool-rag-indexing/SKILL.md +153 -0
  56. package/dist/_skills/nodetool-sketch/SKILL.md +138 -0
  57. package/dist/_skills/nodetool-skill-author/SKILL.md +125 -0
  58. package/dist/_skills/nodetool-troubleshooter/SKILL.md +370 -0
  59. package/dist/_skills/nodetool-video-post/SKILL.md +149 -0
  60. package/dist/_skills/nodetool-workflow-builder/SKILL.md +295 -0
  61. package/dist/_skills/product-commercial/SKILL.md +132 -0
  62. package/dist/_skills/qwen-image-prompting/SKILL.md +122 -0
  63. package/dist/_skills/script-video/SKILL.md +106 -0
  64. package/dist/_skills/seedance-2-prompting/SKILL.md +194 -0
  65. package/dist/_skills/seedream-prompting/SKILL.md +117 -0
  66. package/dist/_skills/short-film/SKILL.md +123 -0
  67. package/dist/_skills/stable-audio-prompting/SKILL.md +130 -0
  68. package/dist/_skills/storyboard-core/SKILL.md +716 -0
  69. package/dist/_skills/timeline-edit-ops/SKILL.md +736 -0
  70. package/dist/_skills/trailer-template/SKILL.md +291 -0
  71. package/dist/_skills/ugc-video/SKILL.md +186 -0
  72. package/dist/_skills/veo-3-prompting/SKILL.md +140 -0
  73. package/dist/_skills/video-audio-continuity/SKILL.md +90 -0
  74. package/dist/_skills/video-clone/SKILL.md +96 -0
  75. package/dist/_skills/video-workflow/SKILL.md +119 -0
  76. package/dist/_skills/wan-2-6-prompting/SKILL.md +107 -0
  77. package/dist/analysis/audio-dsp.d.ts +1 -60
  78. package/dist/analysis/audio-dsp.d.ts.map +1 -1
  79. package/dist/analysis/audio-dsp.js +3 -190
  80. package/dist/analysis/audio-dsp.js.map +1 -1
  81. package/dist/app-build/bridge.d.ts.map +1 -1
  82. package/dist/app-build/bridge.js +44 -17
  83. package/dist/app-build/bridge.js.map +1 -1
  84. package/dist/capabilities/analysis.d.ts.map +1 -1
  85. package/dist/capabilities/analysis.js +9 -35
  86. package/dist/capabilities/analysis.js.map +1 -1
  87. package/dist/capabilities/apps.d.ts.map +1 -1
  88. package/dist/capabilities/apps.js +55 -13
  89. package/dist/capabilities/apps.js.map +1 -1
  90. package/dist/capabilities/apps.specs.d.ts.map +1 -1
  91. package/dist/capabilities/apps.specs.js +5 -3
  92. package/dist/capabilities/apps.specs.js.map +1 -1
  93. package/dist/capabilities/assets.d.ts.map +1 -1
  94. package/dist/capabilities/assets.js +10 -6
  95. package/dist/capabilities/assets.js.map +1 -1
  96. package/dist/capabilities/game-asset-browser.d.ts.map +1 -1
  97. package/dist/capabilities/game-asset-browser.js +6 -1
  98. package/dist/capabilities/game-asset-browser.js.map +1 -1
  99. package/dist/capabilities/game.d.ts +1 -1
  100. package/dist/capabilities/game.d.ts.map +1 -1
  101. package/dist/capabilities/game.js +71 -56
  102. package/dist/capabilities/game.js.map +1 -1
  103. package/dist/capabilities/game.specs.js +1 -1
  104. package/dist/capabilities/game.specs.js.map +1 -1
  105. package/dist/capabilities/game3d.d.ts.map +1 -1
  106. package/dist/capabilities/game3d.js +14 -19
  107. package/dist/capabilities/game3d.js.map +1 -1
  108. package/dist/capabilities/gameAssertions.d.ts +52 -0
  109. package/dist/capabilities/gameAssertions.d.ts.map +1 -0
  110. package/dist/capabilities/gameAssertions.js +32 -0
  111. package/dist/capabilities/gameAssertions.js.map +1 -0
  112. package/dist/capabilities/models.d.ts.map +1 -1
  113. package/dist/capabilities/models.js +9 -0
  114. package/dist/capabilities/models.js.map +1 -1
  115. package/dist/capabilities/project-scope.d.ts +8 -0
  116. package/dist/capabilities/project-scope.d.ts.map +1 -1
  117. package/dist/capabilities/project-scope.js +16 -0
  118. package/dist/capabilities/project-scope.js.map +1 -1
  119. package/dist/capabilities/storyboards.d.ts.map +1 -1
  120. package/dist/capabilities/storyboards.js +36 -11
  121. package/dist/capabilities/storyboards.js.map +1 -1
  122. package/dist/capabilities/storyboards.specs.d.ts.map +1 -1
  123. package/dist/capabilities/storyboards.specs.js +11 -1
  124. package/dist/capabilities/storyboards.specs.js.map +1 -1
  125. package/dist/capabilities/workflows.d.ts.map +1 -1
  126. package/dist/capabilities/workflows.js +1 -0
  127. package/dist/capabilities/workflows.js.map +1 -1
  128. package/dist/capabilities/workflows.specs.d.ts.map +1 -1
  129. package/dist/capabilities/workflows.specs.js +4 -3
  130. package/dist/capabilities/workflows.specs.js.map +1 -1
  131. package/dist/codeact/nodetool-api.d.ts.map +1 -1
  132. package/dist/codeact/nodetool-api.js +8 -2
  133. package/dist/codeact/nodetool-api.js.map +1 -1
  134. package/dist/evals/surfaces/game.d.ts.map +1 -1
  135. package/dist/evals/surfaces/game.js +29 -1
  136. package/dist/evals/surfaces/game.js.map +1 -1
  137. package/dist/game-authoring.d.ts +120 -0
  138. package/dist/game-authoring.d.ts.map +1 -1
  139. package/dist/game-build-integrity.d.ts +12 -0
  140. package/dist/game-build-integrity.d.ts.map +1 -0
  141. package/dist/game-build-integrity.js +78 -0
  142. package/dist/game-build-integrity.js.map +1 -0
  143. package/dist/game-examples.d.ts +44 -3
  144. package/dist/game-examples.d.ts.map +1 -1
  145. package/dist/game-examples.js +60 -10
  146. package/dist/game-examples.js.map +1 -1
  147. package/dist/system-skills.d.ts +1 -1
  148. package/dist/system-skills.js +1 -1
  149. package/dist/tools/builtin-tools.d.ts.map +1 -1
  150. package/dist/tools/builtin-tools.js +2 -0
  151. package/dist/tools/builtin-tools.js.map +1 -1
  152. package/dist/tools/external-mcp-tools.d.ts +6 -0
  153. package/dist/tools/external-mcp-tools.d.ts.map +1 -1
  154. package/dist/tools/external-mcp-tools.js +15 -4
  155. package/dist/tools/external-mcp-tools.js.map +1 -1
  156. package/package.json +19 -19
@@ -0,0 +1,110 @@
1
+ ---
2
+ name: nodetool-3d-scene
3
+ description: "Build, edit, validate or render a NodeTool 3D model: glTF primitives, transforms, lights, material colors, generated meshes, and headless Blender renders. For a playable 3D game, use native-game."
4
+ featured: true
5
+ ---
6
+
7
+ # Work a NodeTool 3D model
8
+
9
+ A 3D model is a `.glb` or `.gltf` **asset**, addressed by its asset id. The
10
+ capabilities edit the stored glTF in place and save it back over the same asset,
11
+ so the id stays valid and an open editor reloads it.
12
+
13
+ For a playable game, 2D or 3D, use `native-game`: it authors 3D games with
14
+ `dimension: "3d"`. For a 3D clip inside a cut, build the model here and place it
15
+ on a timeline.
16
+
17
+ ## The loop
18
+
19
+ 1. **Find it.** `list_model3ds` returns asset id, name, content type and size.
20
+ Nothing to start from: `create_model3d {name, ops?}` makes an empty glTF
21
+ scene and can apply the whole scene in the same call.
22
+ 2. **Read it.** `get_model3d {model_id}` lists every object with its uuid, name,
23
+ type, visibility, transform and material color, plus the scene's world-space
24
+ bounds. Call this before editing, for the uuids.
25
+ 3. **Edit.** `edit_model3d {model_id, ops: [...]}`. Operations run in order.
26
+ Anything they do not name — meshes, textures, skins, animations — is kept, so
27
+ an imported model survives an edit.
28
+ 4. **Validate.** `validate_model3d {model_id | document}`.
29
+ 5. **Render**, when a picture is asked for. `render_model3d {model_id}` goes
30
+ through headless Blender, honors scene cameras and lights, and stores a PNG
31
+ asset. It needs Blender on the server and is not offered on the cloud
32
+ profile. `engine` is `eevee` (default, fast) or `cycles` (slower);
33
+ `camera_mode` is `auto`, `scene` or `orbit`. A Cycles render blocks the call,
34
+ so pass `background: true` to get a `generation_id` at once and collect the
35
+ PNG with `await_generation`.
36
+
37
+ ## A real mesh
38
+
39
+ The ops add primitives only. For an object with real geometry, generate one:
40
+ `run_node` with `nodetool.model3d.TextTo3D {model, prompt}` or
41
+ `nodetool.model3d.ImageTo3D {model, image}` returns a `model_3d` output. Read
42
+ `get_node_info` first for the `model` field's shape. These call a paid
43
+ provider, so confirm with the user before generating. The other
44
+ `nodetool.model3d.*` nodes (`Decimate`, `RepairMesh`, `FormatConverter`,
45
+ `Transform3D`, …) and the `nodetool.blender.*` nodes process a mesh inside a
46
+ workflow.
47
+
48
+ ## `edit_model3d` ops
49
+
50
+ | Op | Fields |
51
+ |---|---|
52
+ | `add_object` | `kind`: `box`, `sphere`, `plane`, `cylinder`, `torus`, `directionalLight`, `pointLight`. Optional `name` |
53
+ | `delete_object` | `target` |
54
+ | `set_transform` | `position`, `rotation` (Euler **degrees**), `scale`, each `[x, y, z]` |
55
+ | `set_visibility` | `visible` |
56
+ | `rename_object` | `target`, `name` |
57
+ | `set_material_color` | `color` as a CSS hex string, meshes only |
58
+ | `select_object` | `target`, or `null` to clear |
59
+
60
+ `target` is a uuid or a name. Object ids are stamped into
61
+ `node.extras.nodetool_id`, because glTF addresses nodes by array index and a
62
+ delete renumbers them. Duplicate names make addressing ambiguous, which
63
+ `validate_model3d` warns about.
64
+
65
+ `delete_object` keeps the file valid: an animation left with no channels is
66
+ removed, and so is a skin that lost a joint, which leaves its mesh in the bind
67
+ pose. `set_material_color` recolors only the named object, copying a material
68
+ or mesh it shares with another object first.
69
+
70
+ These are the `ui_3d_*` verbs with no editor open. The operations, the units and
71
+ the addressing live in `@nodetool-ai/model3d`, shared with the browser editor, so
72
+ a model built headlessly opens there unchanged. Headlessly, a light is a
73
+ `directionalLight` or `pointLight` and a material can only be recolored.
74
+ Light settings, other material fields and parenting need the open editor:
75
+ `ui_3d_set_light`, `ui_3d_set_material`, `ui_3d_set_parent`.
76
+
77
+ ## No camera headlessly
78
+
79
+ `ui_3d_frame_scene` and `ui_3d_capture_view` need a WebGL context. Without one,
80
+ `get_model3d`'s world-space bounds are what answer "how big is this and where is
81
+ it". Use `render_model3d` when an actual picture is required.
82
+
83
+ ## What `validate_model3d` catches
84
+
85
+ The glTF version, references that resolve to nothing (node, mesh, accessor,
86
+ material, buffer, skin, camera, skin joint, animation target and sampler), a
87
+ node with two parents, a cycle in the node hierarchy, a node carrying both a
88
+ matrix and TRS fields, an accessor with an unknown type or reading past its
89
+ buffer view, a buffer view reading past its buffer, an undeclared light, and an
90
+ extension this build cannot honor. It warns on an empty scene, geometry with no
91
+ light, and duplicate names. It only reads the document, and it handles
92
+ hierarchies of any depth.
93
+
94
+ ## On a timeline
95
+
96
+ A `model3d` layer is the one kind `preview_timeline_frame` cannot draw on its
97
+ own canvas. The preview pass collects every 3D layer across the requested
98
+ instants, groups them by glTF plus the options that fix a renderer, and hands
99
+ each group to one headless Chromium page. Two fields on the layer's report say
100
+ what the pixels do not: `camera` (the pose it was drawn with, authored camera
101
+ folded with the animated channels) and `animation_time_sec` (the glTF
102
+ animation's own clock, not timeline time). With no Chrome on the host the group
103
+ is left out and reported as a `model3d_unavailable` degradation.
104
+
105
+ ## Reference
106
+
107
+ In a NodeTool checkout, these repository sources go further:
108
+
109
+ - `docs/harnesses.md` § 3D scene tools
110
+ - `docs/harnesses.md` § 3D clips in preview_timeline_frame
@@ -0,0 +1,338 @@
1
+ ---
2
+ name: nodetool-api-reference
3
+ description: "Integrate with NodeTool over REST, tRPC, MsgPack WebSocket, MCP, or the OpenAI-compatible Chat API, including the document surfaces and workflow execution."
4
+ ---
5
+
6
+ You help users integrate with NodeTool's HTTP + WebSocket server (default `http://localhost:7777`). Start it with `nodetool serve` (flags: `--host`, `--port`).
7
+
8
+ # Surfaces
9
+
10
+ | Surface | Path prefix | Use case |
11
+ |---------|-------------|----------|
12
+ | **REST** | `/api/...` | Workflows, assets, collections, models, bundles, health |
13
+ | **tRPC** | `/trpc/...` | The document surfaces: timelines, storyboards, sketches, scripts, applications, JS scripts, projects, skills, settings |
14
+ | **OpenAI-compatible** | `/v1/...` | Chat completions + model list |
15
+ | **WebSocket** | `/ws` | Run/cancel/stream jobs, live chat, live editor tools |
16
+ | **MCP** | `/mcp` | Agent tools over streamable HTTP, for Claude Desktop and CLI agents |
17
+
18
+ Auth is controlled by environment variables, not CLI flags (§ Authentication).
19
+
20
+ **Pick the right surface.** REST covers workflows, assets and the portable
21
+ bundles. Everything that is a *document* someone edits (a timeline sequence, a
22
+ storyboard, a sketch, a script, a mini app, a JS script) is a tRPC router, and
23
+ the REST routes for those kinds cover only import, export and build. An
24
+ integration that reads or writes a document calls tRPC, or calls the agent
25
+ capability of the same name over `/mcp`.
26
+
27
+ # Authentication
28
+
29
+ The server picks its auth mode from `SUPABASE_URL` and `SUPABASE_KEY` alone. It
30
+ reads neither `AUTH_PROVIDER` nor `NODETOOL_SERVER_MODE`.
31
+
32
+ | Mode | Enabled by | Accepted credentials |
33
+ |------|------------|----------------------|
34
+ | Local | Default, with the Supabase variables unset | Loopback connections run as user `"1"` with no token. `NODETOOL_TRUST_LOCALHOST=false` turns that off. Sources in `NODETOOL_TRUST_LOCAL_NETWORKS` (comma-separated CIDRs) also run as user `"1"` with no token. A bearer equal to `SERVER_AUTH_TOKEN` runs as user `"1"`. A token minted by `nodetool deploy users-add` runs as that API user. Anything else gets `401`. |
35
+ | Supabase | `SUPABASE_URL` and `SUPABASE_KEY` both set | Every non-public request needs a valid Supabase JWT. `SERVER_AUTH_TOKEN`, `NODETOOL_TRUST_LOCAL_NETWORKS` and API-user tokens are ignored. Loopback is trusted only with `NODETOOL_TRUST_LOCALHOST=true`. |
36
+
37
+ In both modes, an access token (`ntk_…`) created in **Settings → MCP → Connect
38
+ an agent remotely** authenticates as the person who created it. Send any token
39
+ as `Authorization: Bearer <token>`. A WebSocket client that cannot set headers
40
+ passes `?api_key=<token>` on the `/ws` URL.
41
+
42
+ # REST Endpoints
43
+
44
+ ## Workflows
45
+
46
+ ```bash
47
+ # List workflows
48
+ curl http://localhost:7777/api/workflows \
49
+ -H "Authorization: Bearer TOKEN"
50
+
51
+ # Get a workflow
52
+ curl http://localhost:7777/api/workflows/<id> \
53
+ -H "Authorization: Bearer TOKEN"
54
+
55
+ # Export helpers
56
+ curl http://localhost:7777/api/workflows/<id>/dsl-export # TypeScript DSL
57
+ curl http://localhost:7777/api/workflows/<id>/export-bundle # .nodetool bundle (zip)
58
+ ```
59
+
60
+ Run a saved workflow over REST. This is the route `run_workflow`,
61
+ `debug_workflow` and `nodetool debug` use. The editor runs over WebSocket
62
+ instead (§ WebSocket API).
63
+
64
+ ```bash
65
+ curl -X POST http://localhost:7777/api/workflows/<id>/run \
66
+ -H "Authorization: Bearer TOKEN" \
67
+ -H "Content-Type: application/json" \
68
+ -d '{"params": {"prompt": "a red fox"}}'
69
+ # Same body, returns the full debug report (summary and verdict) instead of the run row
70
+ curl -X POST http://localhost:7777/api/workflows/<id>/debug ...
71
+ ```
72
+
73
+ The body also takes `background: true` to return a job id at once, and
74
+ `interactive: true` to park on escalations as a debug session (below).
75
+
76
+ ## Documents (tRPC)
77
+
78
+ The routers under `/trpc`, one per document kind:
79
+ `timeline`, `storyboards`, `sketch`, `scripts`, `applications`, `jsScripts`,
80
+ `documents`, `workflows`, `projects`, `assets`, `collections`, `jobs`, `runs`,
81
+ `appRuns`, `appInstances`, `resources`, `models`, `customProviders`, `nodes`,
82
+ `memories`, `messages`, `threads`, `settings`, `skills`, `storage`, `packs`,
83
+ `costs`, `credits`, `files`, `fonts`, `games`, `integrations`, `triggers`,
84
+ `externalMcp`, `agentAccess`, `users`, `worker`, `workspace`.
85
+
86
+ Each follows the same shape: `list`, `get`, `create`, `update` (compare-and-swap
87
+ on `updated_at`), `delete`, plus sub-routers. Whole-document snapshots are
88
+ `timeline.versions`, `sketch.documentVersions` and `jsScripts.documentVersions`
89
+ (`sketch.versions` is a different thing: the per-layer generation takes).
90
+ `applications` also carries `publish`, `released`, `deploy`, `budget` and
91
+ `usage`, because publishing an app locks in the current graph of every workflow
92
+ it runs and caps what it may spend. Read the router in
93
+ `packages/websocket/src/trpc/routers/` for the exact procedure names rather than
94
+ guessing them. `/trpc/healthz` answers without auth.
95
+
96
+ An agent reaches the same data through the capability tools, which need no
97
+ client: `list_timelines`, `get_storyboard`, `edit_sketch`, `save_js_script`,
98
+ `edit_app`, and so on.
99
+
100
+ ## Document REST routes
101
+
102
+ The REST side of the document kinds is import, export and build.
103
+
104
+ ```bash
105
+ # Mini apps
106
+ curl http://localhost:7777/api/applications/:id/export-bundle # app + every bound graph
107
+ curl -X POST http://localhost:7777/api/applications/import-bundle
108
+ curl -X POST http://localhost:7777/api/applications/build # {prompt|spec, provider, model, ...}
109
+ curl -X POST http://localhost:7777/api/applications/debug
110
+ curl http://localhost:7777/api/applications/examples
111
+ curl -X POST http://localhost:7777/api/applications/examples/:slug/install
112
+
113
+ # Timelines and storyboards
114
+ curl http://localhost:7777/api/timelines/:id/export-zip
115
+ curl -X POST http://localhost:7777/api/timelines/import-zip
116
+ curl http://localhost:7777/api/storyboards/:id/export-zip
117
+ curl -X POST http://localhost:7777/api/timelines/:id/isolate-subject
118
+
119
+ # Native games: the published revision as a zip (target=web or tauri)
120
+ curl -o game.zip 'http://localhost:7777/api/games/:id/export-zip?target=tauri'
121
+ # Compile the desktop executable on this machine; streams cargo output as NDJSON (refused on hosted servers)
122
+ curl -N -X POST http://localhost:7777/api/games/:id/build-executable
123
+
124
+ # JS scripts
125
+ curl -X POST http://localhost:7777/api/js-scripts/:id/run
126
+ ```
127
+
128
+ A build or an interactive debug runs for minutes, so those routes accept
129
+ `poll: true`, return a session id, and are read at
130
+ `GET /api/debug/sessions/:id` until they settle. Cancel with
131
+ `POST /api/debug/sessions/:id/cancel`.
132
+
133
+ ## Collections (RAG)
134
+
135
+ ```bash
136
+ # Upload a text file into a collection (multipart, field name "file")
137
+ curl -X POST http://localhost:7777/api/collections/<name>/index \
138
+ -H "Authorization: Bearer TOKEN" \
139
+ -F "file=@notes.md"
140
+ ```
141
+
142
+ The route indexes text only: plain text, Markdown, HTML, CSV and JSON. It
143
+ returns `415` for PDFs, Office files and images, which need an indexing
144
+ workflow. The collection must have an embedding model.
145
+
146
+ ## Models
147
+
148
+ ```bash
149
+ # OpenAI-compatible model list
150
+ curl http://localhost:7777/v1/models -H "Authorization: Bearer TOKEN"
151
+ ```
152
+
153
+ ## Storage / Assets
154
+
155
+ ```bash
156
+ # Asset bytes are served under /api/storage/...
157
+ curl http://localhost:7777/api/storage/<path>
158
+ ```
159
+
160
+ ## Health
161
+
162
+ ```bash
163
+ curl http://localhost:7777/health # liveness (no auth)
164
+ curl http://localhost:7777/ready # readiness
165
+ curl http://localhost:7777/api/health # detailed health
166
+ ```
167
+
168
+ # Chat API (OpenAI-Compatible)
169
+
170
+ ## HTTP
171
+
172
+ ```bash
173
+ # Chat completion
174
+ curl -X POST http://localhost:7777/v1/chat/completions \
175
+ -H "Authorization: Bearer TOKEN" \
176
+ -H "Content-Type: application/json" \
177
+ -d '{
178
+ "model": "gpt-5.4",
179
+ "messages": [
180
+ {"role": "system", "content": "You are a helpful assistant."},
181
+ {"role": "user", "content": "Hello!"}
182
+ ],
183
+ "stream": false
184
+ }'
185
+
186
+ # Streaming (Server-Sent Events)
187
+ curl -X POST http://localhost:7777/v1/chat/completions \
188
+ -H "Authorization: Bearer TOKEN" \
189
+ -H "Content-Type: application/json" \
190
+ -d '{"model": "gpt-5.4", "messages": [{"role": "user", "content": "Hi"}], "stream": true}'
191
+ ```
192
+
193
+ ## Python Client (OpenAI SDK)
194
+
195
+ ```python
196
+ import openai
197
+
198
+ client = openai.OpenAI(api_key="TOKEN", base_url="http://localhost:7777/v1")
199
+
200
+ response = client.chat.completions.create(
201
+ model="gpt-5.4",
202
+ messages=[{"role": "user", "content": "Hello!"}],
203
+ )
204
+ print(response.choices[0].message.content)
205
+
206
+ # Streaming
207
+ stream = client.chat.completions.create(
208
+ model="gpt-5.4",
209
+ messages=[{"role": "user", "content": "Hello!"}],
210
+ stream=True,
211
+ )
212
+ for chunk in stream:
213
+ if chunk.choices[0].delta.content:
214
+ print(chunk.choices[0].delta.content, end="")
215
+ ```
216
+
217
+ ## JavaScript Client
218
+
219
+ ```typescript
220
+ const response = await fetch("http://localhost:7777/v1/chat/completions", {
221
+ method: "POST",
222
+ headers: {
223
+ Authorization: "Bearer TOKEN",
224
+ "Content-Type": "application/json",
225
+ },
226
+ body: JSON.stringify({
227
+ model: "gpt-5.4",
228
+ messages: [{ role: "user", content: "Hello!" }],
229
+ stream: false,
230
+ }),
231
+ });
232
+ const data = await response.json();
233
+ console.log(data.choices[0].message.content);
234
+ ```
235
+
236
+ # WebSocket API — Running Jobs
237
+
238
+ **Endpoint**: `ws(s)://<host>/ws`. Messages are an envelope `{ command, data }`.
239
+ The server replies in MsgPack until the client sends `set_mode` with
240
+ `"text"`. A JSON client sends that first, or `JSON.parse` fails on every reply.
241
+ Identity comes from the connection's credential (§ Authentication), not from
242
+ fields in the request body.
243
+
244
+ ```typescript
245
+ const socket = new WebSocket("ws://localhost:7777/ws?api_key=<token>");
246
+
247
+ socket.onopen = () => {
248
+ socket.send(JSON.stringify({ command: "set_mode", data: { mode: "text" } }));
249
+ // Start a workflow run
250
+ socket.send(JSON.stringify({
251
+ command: "run_job",
252
+ data: {
253
+ type: "run_job_request",
254
+ workflow_id: "<id>",
255
+ job_type: "workflow",
256
+ params: { input_name: "value" },
257
+ job_id: "<id>",
258
+ },
259
+ }));
260
+ };
261
+
262
+ socket.onmessage = (event) => {
263
+ const msg = JSON.parse(event.data);
264
+ switch (msg.type) {
265
+ case "job_update":
266
+ console.log(`Job ${msg.status}`); // running | completed | failed | cancelled | suspended
267
+ if (msg.result) console.log("Result:", msg.result);
268
+ break;
269
+ case "node_update":
270
+ console.log(`Node ${msg.node_name}: ${msg.status}`);
271
+ break;
272
+ case "node_progress":
273
+ console.log(`Progress: ${msg.progress}/${msg.total}`);
274
+ break;
275
+ case "output_update":
276
+ console.log(`Output ${msg.output_name}:`, msg.value);
277
+ break;
278
+ case "chunk":
279
+ process.stdout.write(msg.content);
280
+ break;
281
+ case "log_update":
282
+ console.log(`[${msg.severity}] ${msg.content}`);
283
+ break;
284
+ }
285
+ };
286
+ ```
287
+
288
+ ## Job Control Commands
289
+
290
+ ```typescript
291
+ socket.send(JSON.stringify({ command: "cancel_job", data: { job_id: "...", workflow_id: "..." } }));
292
+ socket.send(JSON.stringify({ command: "get_status", data: { job_id: "..." } }));
293
+ socket.send(JSON.stringify({ command: "reconnect_job", data: { job_id: "...", workflow_id: "..." } }));
294
+
295
+ // Stream input into a running node, then close the stream
296
+ socket.send(JSON.stringify({ command: "stream_input", data: { job_id: "...", input: "name", value: "data", handle: "..." } }));
297
+ socket.send(JSON.stringify({ command: "end_input_stream", data: { job_id: "...", input: "name", handle: "..." } }));
298
+ ```
299
+
300
+ There is no pause or resume. An unknown command returns `Unknown command`.
301
+
302
+ # Server Message Types
303
+
304
+ | Type | Key fields | Purpose |
305
+ |------|-----------|---------|
306
+ | `job_update` | `status`, `result`, `error`, `cost` | Job lifecycle |
307
+ | `node_update` | `node_id`, `node_name`, `status`, `error`, `result` | Node lifecycle |
308
+ | `node_progress` | `progress`, `total`, `chunk` | Progress tracking |
309
+ | `output_update` | `output_name`, `value`, `output_type` | Node output values |
310
+ | `log_update` | `content`, `severity` | Log messages |
311
+ | `chunk` | `content`, `done` | Streaming text |
312
+
313
+ # MCP
314
+
315
+ `/mcp` serves the agent capability tools over streamable HTTP, so an outside
316
+ agent drives NodeTool with the same calls the in-product agent uses. Reach it
317
+ three ways:
318
+
319
+ - `nodetool mcp install` configures a CLI agent (Claude Code, Codex).
320
+ - In a NodeTool checkout, `npm run build:mcpb` builds `dist/nodetool.mcpb`, a one-file bundle Claude
321
+ Desktop installs by drag-and-drop. It is a stdio-to-HTTP bridge against a
322
+ running server's `/mcp`, and it starts in offline mode when the server is
323
+ down, then hot-attaches when it appears.
324
+ - A deployed server is reached by pointing the client at `/mcp` with a token
325
+ minted in **Settings → MCP → Connect an agent remotely**.
326
+
327
+ # Server Management (CLI)
328
+
329
+ ```bash
330
+ nodetool serve # Start server (default 127.0.0.1:7777)
331
+ nodetool serve --host 0.0.0.0 # Bind all interfaces
332
+ nodetool serve --port 8080 # Custom port
333
+ nodetool workflows list # List saved workflows
334
+ nodetool workflows get <id> # Get workflow details
335
+ nodetool workflows run <id> # Run a workflow (uses the local DB)
336
+ nodetool jobs list # List execution jobs
337
+ nodetool secrets store OPENAI_API_KEY # Store an API key
338
+ ```