@nodetool-ai/agents 0.8.4-a24.2 → 0.8.4

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 (135) 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/app-build/bridge.d.ts.map +1 -1
  78. package/dist/app-build/bridge.js +44 -17
  79. package/dist/app-build/bridge.js.map +1 -1
  80. package/dist/capabilities/apps.d.ts.map +1 -1
  81. package/dist/capabilities/apps.js +55 -13
  82. package/dist/capabilities/apps.js.map +1 -1
  83. package/dist/capabilities/apps.specs.d.ts.map +1 -1
  84. package/dist/capabilities/apps.specs.js +5 -3
  85. package/dist/capabilities/apps.specs.js.map +1 -1
  86. package/dist/capabilities/game-asset-browser.d.ts.map +1 -1
  87. package/dist/capabilities/game-asset-browser.js +6 -1
  88. package/dist/capabilities/game-asset-browser.js.map +1 -1
  89. package/dist/capabilities/game.d.ts +1 -1
  90. package/dist/capabilities/game.d.ts.map +1 -1
  91. package/dist/capabilities/game.js +71 -56
  92. package/dist/capabilities/game.js.map +1 -1
  93. package/dist/capabilities/game.specs.js +1 -1
  94. package/dist/capabilities/game.specs.js.map +1 -1
  95. package/dist/capabilities/game3d.d.ts.map +1 -1
  96. package/dist/capabilities/game3d.js +14 -19
  97. package/dist/capabilities/game3d.js.map +1 -1
  98. package/dist/capabilities/gameAssertions.d.ts +52 -0
  99. package/dist/capabilities/gameAssertions.d.ts.map +1 -0
  100. package/dist/capabilities/gameAssertions.js +32 -0
  101. package/dist/capabilities/gameAssertions.js.map +1 -0
  102. package/dist/capabilities/models.d.ts.map +1 -1
  103. package/dist/capabilities/models.js +9 -0
  104. package/dist/capabilities/models.js.map +1 -1
  105. package/dist/capabilities/storyboards.d.ts.map +1 -1
  106. package/dist/capabilities/storyboards.js +36 -11
  107. package/dist/capabilities/storyboards.js.map +1 -1
  108. package/dist/capabilities/storyboards.specs.d.ts.map +1 -1
  109. package/dist/capabilities/storyboards.specs.js +11 -1
  110. package/dist/capabilities/storyboards.specs.js.map +1 -1
  111. package/dist/capabilities/workflows.d.ts.map +1 -1
  112. package/dist/capabilities/workflows.js +1 -0
  113. package/dist/capabilities/workflows.js.map +1 -1
  114. package/dist/capabilities/workflows.specs.d.ts.map +1 -1
  115. package/dist/capabilities/workflows.specs.js +4 -3
  116. package/dist/capabilities/workflows.specs.js.map +1 -1
  117. package/dist/evals/surfaces/game.d.ts.map +1 -1
  118. package/dist/evals/surfaces/game.js +29 -1
  119. package/dist/evals/surfaces/game.js.map +1 -1
  120. package/dist/game-authoring.d.ts +120 -0
  121. package/dist/game-authoring.d.ts.map +1 -1
  122. package/dist/game-build-integrity.d.ts +12 -0
  123. package/dist/game-build-integrity.d.ts.map +1 -0
  124. package/dist/game-build-integrity.js +78 -0
  125. package/dist/game-build-integrity.js.map +1 -0
  126. package/dist/game-examples.d.ts +44 -3
  127. package/dist/game-examples.d.ts.map +1 -1
  128. package/dist/game-examples.js +60 -10
  129. package/dist/game-examples.js.map +1 -1
  130. package/dist/system-skills.d.ts +1 -1
  131. package/dist/system-skills.js +1 -1
  132. package/dist/tools/builtin-tools.d.ts.map +1 -1
  133. package/dist/tools/builtin-tools.js +2 -0
  134. package/dist/tools/builtin-tools.js.map +1 -1
  135. package/package.json +19 -19
@@ -0,0 +1,153 @@
1
+ ---
2
+ name: nodetool-rag-indexing
3
+ description: "Build NodeTool document ingestion, vector indexing, retrieval, and RAG pipelines. Use when documents must be chunked into a vector collection and searched by meaning, or when an answer should come from the user's own documents. To find a stored image, video or file by name or tag, use asset_search instead."
4
+ featured: true
5
+ ---
6
+
7
+ # Index documents and answer from them
8
+
9
+ A **collection** is a named vector store. Indexing splits documents into
10
+ chunks, embeds each chunk with the collection's embedding model and stores it.
11
+ Retrieval embeds the question with the same model and returns the closest
12
+ chunks, which a language model answers from.
13
+
14
+ ```
15
+ INDEX: documents → text → chunks → vector.IndexTextChunk → collection
16
+ QUERY: question → vector.HybridSearch / QueryText → context → Agent → answer
17
+ ```
18
+
19
+ ## Search what is already indexed
20
+
21
+ Two tools are on the agent's belt in every chat:
22
+
23
+ - `list_collections` returns each collection the user can access, with its
24
+ metadata (including `embedding_model`).
25
+ - `query_collection {collection, query, n_results?}` returns the closest chunks
26
+ as `{id, document, score}`. `n_results` defaults to 5.
27
+
28
+ Answer from the returned chunks and say which chunk ids the answer used. An
29
+ empty result means the collection holds nothing close, not that the topic is
30
+ unknown.
31
+
32
+ The `vector_index`, `vector_batch_index`, `vector_text_search`,
33
+ `vector_hybrid_search`, `vector_recursive_split_and_index` and
34
+ `vector_markdown_split_and_index` tools act only on a collection a host binds
35
+ to the run. A chat binds none, so they return an error there. Index through the
36
+ nodes below instead.
37
+
38
+ ## Index through nodes
39
+
40
+ All vector nodes are in the `vector` namespace.
41
+
42
+ | Node | Takes | Does |
43
+ |---|---|---|
44
+ | `vector.Collection` | `name`, `embedding_model` | Gets or creates the collection and outputs a `{type: "collection", name}` ref |
45
+ | `vector.IndexTextChunk` | `collection`, `document_id`, `text`, `metadata` | Upserts one chunk. The same `document_id` overwrites |
46
+ | `vector.IndexString` | `collection`, `text`, `document_id`, `metadata` | Upserts one string |
47
+ | `vector.IndexImage`, `vector.IndexEmbedding` | | Index an image or a precomputed embedding |
48
+ | `vector.QueryText` | `collection`, `text`, `n_results` | Vector search. Outputs `ids`, `documents`, `metadatas`, `distances` |
49
+ | `vector.HybridSearch` | `collection`, `text`, `n_results`, `k_constant`, `min_keyword_length` | Vector plus keyword search, fused by reciprocal rank. Adds `scores` |
50
+ | `vector.QueryImage` | `collection`, `image`, `n_results` | Image search |
51
+ | `vector.GetDocuments`, `vector.Peek`, `vector.Count` | `collection` | Inspect what is stored |
52
+ | `vector.RemoveOverlap` | `documents` | Removes text repeated between overlapping chunks |
53
+
54
+ The embedding model is set once, on `vector.Collection`'s `embedding_model`,
55
+ and stored in the collection's metadata. Index and query nodes take only the
56
+ collection, so indexing and search always use the same model. The shipped
57
+ example uses the Ollama model `nomic-embed-text`. Changing the model means a
58
+ new collection.
59
+
60
+ For a few chunks, `run_node` is enough: `run_node {node_type:
61
+ "vector.Collection", inputs: {name, embedding_model}}` once, then
62
+ `vector.IndexTextChunk` with `collection: {type: "collection", name}` per
63
+ chunk. For a folder of documents, build a workflow and run it.
64
+
65
+ ### Index workflow
66
+
67
+ 1. **List files.** A Code node with `await workspace.list(dir)`, or
68
+ `nodetool.document.ListDocuments {folder, pattern, recursive}`.
69
+ 2. **Load text.** `nodetool.document.LoadDocumentFile {path}` for text and
70
+ Markdown. For PDFs use `lib.pdf.ExtractText` or `lib.pdf.ExtractMarkdown`.
71
+ 3. **Chunk.** There is no chunking node. Use a Code node, starting from the
72
+ "Chunk Text" snippet, and record the list with
73
+ `await output("chunks", chunks)`. Read a document input with
74
+ `await media.text(inputs.document)`.
75
+ 4. **Fan out.** `nodetool.control.ForEach` emits each chunk on `output` and its
76
+ position on `index`. Build a unique `document_id` from the file name and the
77
+ index, for example with `nodetool.text.Template`.
78
+ 5. **Index.** `vector.IndexTextChunk` with the collection ref, the chunk as
79
+ `text`, the id as `document_id`, and `{source: <file name>}` as `metadata`.
80
+
81
+ Validate with `validate_workflow`, then run it. Indexing with a hosted
82
+ embedding model is billed per token, so confirm the size of the corpus with the
83
+ user before indexing a large folder.
84
+
85
+ | Content | Chunk size | Overlap |
86
+ |---|---|---|
87
+ | Technical docs | 200–500 tokens | about 50 tokens |
88
+ | Prose | 300–600 tokens | about 75 tokens |
89
+ | Code | 100–300 tokens | about 25 tokens |
90
+
91
+ ### Query workflow
92
+
93
+ `StringInput` (question) → `vector.HybridSearch {collection, n_results: 5}` →
94
+ a Code node joining `documents` into one context string → `nodetool.text.Prompt`
95
+ or `Template` with the context and the question → `nodetool.agents.Agent` with a
96
+ system prompt that limits it to the context → `Output`.
97
+
98
+ The shipped example **Chat With Your Documents** builds a collection, indexes
99
+ three documents and answers from them. Load it with `get_example_workflow
100
+ {package_name: "nodetool-base", example_name: "Chat With Your Documents"}` and
101
+ adapt it rather than starting from nothing.
102
+
103
+ ## Storage backends
104
+
105
+ The workflow nodes and tools are the same on every backend. The server picks
106
+ one at start from `NODETOOL_VECTOR_PROVIDER`:
107
+
108
+ | Value | Store | Configuration |
109
+ |---|---|---|
110
+ | `sqlite-vec` (default) | Local SQLite file | `VECTORSTORE_DB_PATH` to move it |
111
+ | `pinecone` | Pinecone | `PINECONE_API_KEY`, optional `PINECONE_ENVIRONMENT`, `PINECONE_CONTROLLER_HOST` |
112
+ | `supabase` | Postgres with pgvector | `SUPABASE_URL` and `SUPABASE_KEY` or `SUPABASE_SERVICE_ROLE_KEY`, plus `packages/vectorstore/sql/supabase-migration.sql` applied to the project |
113
+
114
+ Any other value stops the server with an error. These are server environment
115
+ variables, set by whoever runs the server, not by the agent.
116
+
117
+ ## From a shell or over HTTP
118
+
119
+ For a person with a shell, the `nodetool collections` CLI manages collections
120
+ on the local server:
121
+
122
+ ```bash
123
+ nodetool collections create handbook --embedding-model nomic-embed-text --embedding-provider ollama
124
+ nodetool collections index handbook ./docs/*.md
125
+ nodetool collections query handbook "refund policy" -n 5
126
+ nodetool collections list
127
+ nodetool collections delete handbook --yes
128
+ ```
129
+
130
+ `POST /api/collections/<name>/index` takes one text file as a
131
+ `multipart/form-data` upload in the `file` field, chunks it and indexes it into
132
+ an existing collection that has an embedding model. Plain text, Markdown, HTML,
133
+ CSV and JSON are accepted. PDFs, Office files and images need an indexing
134
+ workflow.
135
+
136
+ ```bash
137
+ curl -X POST http://localhost:7777/api/collections/handbook/index \
138
+ -H "Authorization: Bearer $TOKEN" \
139
+ -F "file=@./docs/refunds.md"
140
+ ```
141
+
142
+ ## Pitfalls
143
+
144
+ - **A collection with no embedding model** cannot be searched. Create it with
145
+ one.
146
+ - **Chunks too large** dilute the context. **Chunks too small** split
147
+ sentences. Keep 10–20% overlap.
148
+ - **Reused `document_id`s** overwrite each other. Include the file name in the
149
+ id.
150
+ - **Querying before indexing** returns nothing.
151
+ - **Node names**: `vector.IndexTextChunk`, `vector.QueryText`,
152
+ `vector.HybridSearch`. There is no `vector.chroma.*` or `vector.faiss.*`, and
153
+ no `nodetool.text.Chunk`.
@@ -0,0 +1,138 @@
1
+ ---
2
+ name: nodetool-sketch
3
+ description: "Build or edit a NodeTool sketch (image document): layers, blend modes, placed images, generation briefs, version history."
4
+ featured: true
5
+ ---
6
+
7
+ # Work a NodeTool sketch
8
+
9
+ A sketch is an **image document**: a canvas, a stack of layers, and the bindings
10
+ that say where a layer's picture comes from. It is the surface for composited
11
+ stills, masks, overlays and the guided image brief. One finished image with no
12
+ layers to keep is `generate_image`, not a sketch.
13
+
14
+ The document is layers and references. **Headless tools never read or write
15
+ pixels.** Painting happens in an open editor (the `ui_sketch_*` tools below),
16
+ generation happens in a workflow run or through the image tools. An image lands
17
+ on a layer by reference, so nothing inlines a bitmap.
18
+
19
+ ## The loop
20
+
21
+ 1. **Find it.** `list_sketches`, then `get_sketch`. New one:
22
+ `create_sketch {name, width?, height?, background_color?, project_id?}` gives a
23
+ blank canvas (1024×1024, `#ffffff` by default).
24
+ 2. **Edit the stack.** `edit_sketch {image_document_id, ops: [...]}`. Operations
25
+ run in order against the stored document and the result is saved. An open
26
+ editor picks the change up live.
27
+ 3. **Validate.** `validate_sketch {image_document_id}` or an inline `document`.
28
+ 4. **Snapshot** before a destructive pass with `create_sketch_version`.
29
+
30
+ ## `edit_sketch` ops
31
+
32
+ | Op | Does |
33
+ |---|---|
34
+ | `add_layer` | `{name?, type?: "raster"\|"mask", index?, image?, x?, y?, width?, height?}`. An `image` field makes this one op instead of two |
35
+ | `remove_layer`, `rename_layer`, `duplicate_layer`, `reorder_layer` | Stack management |
36
+ | `select_layer` | Sets the active layer |
37
+ | `set_layer_props` | `opacity`, `blendMode`, visibility, lock |
38
+ | `set_layer_image` | Points a layer at an asset id, an `asset://` locator, a `data:` URL or an http(s) URL |
39
+ | `resize_canvas` | Positive integer width and height |
40
+ | `set_setup` | The generation brief: `brief`, `use_case`, `variations` (1..8), `stage`. Renders nothing |
41
+
42
+ `target` is a layer id, a layer name, or `"active"`. Layer index 0 is the
43
+ bottom of the stack. `use_case` is one of `product`, `portrait`, `key-art`,
44
+ `social`, `logo`, `concept`, `texture`, and it also sets the canvas size.
45
+ `stage` is where the guided flow resumes: `idea`, `useCase`, `review`, `look`,
46
+ or `done` for the plain editor.
47
+
48
+ An asset id that resolves to nothing is refused rather than stored, because a
49
+ stored one shows up as an empty layer.
50
+
51
+ With the sketch open in a browser, the `ui_sketch_*` tools act on the live
52
+ canvas, and only they touch pixels: `ui_sketch_get_state`,
53
+ `ui_sketch_place_image`, `ui_sketch_stroke`, `ui_sketch_fill`,
54
+ `ui_sketch_gradient`, `ui_sketch_draw_shape`, `ui_sketch_adjust_layer`,
55
+ `ui_sketch_transform`, `ui_sketch_crop`, `ui_sketch_merge_down`,
56
+ `ui_sketch_flatten_visible`, `ui_sketch_get_layer_image`,
57
+ `ui_sketch_generate` and `ui_sketch_render_to_asset`.
58
+
59
+ ## Vector layers
60
+
61
+ The editor imports self-contained SVG files as vector layers. Each layer keeps
62
+ its SVG source in the document. Use the vector inspector to edit SVG source,
63
+ download it, or rasterize the layer for painting. Moving and transforming a
64
+ vector layer preserves its source. Rasterization is undoable. Example sketches
65
+ open with vector layers.
66
+
67
+ SVG scripts, embedded HTML, animations, external images, and stylesheets are
68
+ removed on import. Use presentation attributes for fills, strokes, and text.
69
+ The headless stack operations can preserve existing vector layers. Creating or
70
+ editing SVG source currently requires the editor.
71
+
72
+ ## The guided brief
73
+
74
+ `set_setup` writes the one-line brief. `refine_image_brief {image_document_id,
75
+ provider?, model?}` expands it into the five fields an image model needs
76
+ (subject, composition, lighting, style words, and what to leave out) and stops
77
+ at the review step. It creates no layer and starts no generation. It is the
78
+ cheap text pass a person edits before anything is rendered.
79
+
80
+ Once the fields read right, put pixels on a layer in two calls:
81
+ `generate_image` saves the result as an asset and returns its `asset://` URI,
82
+ then `edit_sketch` with `add_layer {image}` or `set_layer_image {target, image}`
83
+ places it. Generation spends provider money, so confirm the count with the user
84
+ before rendering several `variations`.
85
+
86
+ To use the finished composite in a workflow, `nodetool.sketch.RenderSketch`
87
+ takes a `sketch` and flattens it to an `image` and a `mask`.
88
+
89
+ ## What `validate_sketch` catches
90
+
91
+ Duplicate layer ids, an active or mask layer the stack lacks, unknown blend
92
+ modes, opacities and transforms that cannot render, generation bindings pointing
93
+ at missing layers, unknown binding kinds and statuses, canvas settings that
94
+ disagree with the stored ones, and fields a schema round trip would strip. Layer
95
+ bitmaps stay opaque to it.
96
+
97
+ ## Versions
98
+
99
+ `list_sketch_versions`, `get_sketch_version` (read a snapshot without restoring),
100
+ `create_sketch_version`, `restore_sketch_version`, `delete_sketch_version`.
101
+ A restore snapshots the pre-restore state first, so it is undoable, then
102
+ re-validates against today's schema: an old document may fail what it used to
103
+ pass.
104
+
105
+ These snapshot the whole document. The per-layer generation takes are a
106
+ different thing, and they record one generated image on one layer.
107
+
108
+ ## Verify from a shell
109
+
110
+ These are the `nodetool` CLI. From a NodeTool checkout the same commands run
111
+ as `npm run dev:nodetool -- <command>`.
112
+
113
+ ```bash
114
+ nodetool sketch validate <image_document_id|sketch.json> --json
115
+ nodetool sketch debug sketch.json \
116
+ --interact '[{"tool":"add_layer","input":{"name":"Shadow"}},
117
+ {"tool":"set_layer_props","input":{"target":"Shadow","opacity":0.4,"blendMode":"multiply"}}]'
118
+ nodetool sketch versions list <id> --save-type manual --limit 10
119
+ ```
120
+
121
+ A path on disk wins over an id. `debug` runs the static check, then each
122
+ `--interact` step against the headless `ui_sketch_*` bridge, and validates what
123
+ the session left behind. A failing step is recorded and the script continues.
124
+ Pixels, painting, rendering, generation and asset I/O are not simulated.
125
+
126
+ ## Where a sketch is used
127
+
128
+ - A mini app shows one with the **Sketch** widget, which takes a
129
+ `{type: "sketch", id}` reference, and collects one with the **Sketch Pad**
130
+ input. See `nodetool-app-builder`.
131
+ - A mini app resource of `kind: "sketch"` lets the app read or edit it.
132
+
133
+ ## Reference
134
+
135
+ In a NodeTool checkout, these repository sources go further:
136
+
137
+ - `docs/harnesses.md` § nodetool sketch validate / debug
138
+ - `docs/harnesses.md` § nodetool sketch versions
@@ -0,0 +1,125 @@
1
+ ---
2
+ name: nodetool-skill-author
3
+ description: "Write or revise a NodeTool skill: a user skill row through create_skill, or a shipped system skill under packages/system-skills. Use when instructions should persist across sessions."
4
+ featured: true
5
+ ---
6
+
7
+ # Author a NodeTool skill
8
+
9
+ A skill is a named set of instructions an agent loads when its description
10
+ matches the task. Write one when the same direction would otherwise be repeated
11
+ every session. Do not write one for a single job: do the job.
12
+
13
+ ## Which kind
14
+
15
+ | | User skill | System skill |
16
+ |---|---|---|
17
+ | Lives in | A row in the user's account | `packages/system-skills/<name>/SKILL.md` in the build |
18
+ | Written by | `create_skill`, `update_skill`, `delete_skill` | A file in a pull request |
19
+ | Scope | That user | Every install, on day one, with no seeding migration |
20
+ | Editable at runtime | Yes | No. Immutable, and `create_skill`, `update_skill` and renames refuse a shipped name. A user row that already held the name before the skill shipped still shadows it |
21
+
22
+ A repository skill under `.claude/skills/` is a third thing: it directs the
23
+ coding agent working on the NodeTool repository, not the agent inside the
24
+ product — the engineering loop, not a product surface. Its maintenance rules
25
+ are in a checkout's `.claude/README.md`, § Maintaining skills.
26
+
27
+ A skill that teaches a product surface is a system skill even when the coding
28
+ agent also wants it. `packages/system-skills/<name>` holds the one copy and
29
+ `.claude/skills/<name>` is a symlink to it, so the product and the repository
30
+ read the same document. Write a second copy under `.claude/skills/` and the
31
+ two drift; `npm run check:agents-docs` fails on one.
32
+
33
+ ## The contract
34
+
35
+ A system skill is one Markdown document with frontmatter:
36
+
37
+ ```markdown
38
+ ---
39
+ name: my-skill
40
+ description: When to use this
41
+ ---
42
+
43
+ The instructions.
44
+ ```
45
+
46
+ A user skill has the same three parts as separate `create_skill` fields:
47
+ `{name, description, content}`. `content` is the body only. Do not put
48
+ frontmatter in it.
49
+
50
+ - `name` is a lowercase slug, `a-z0-9-` only, at most 64 characters. It cannot
51
+ contain `anthropic` or `claude`. A user's names must be unique per user.
52
+ - `description` is one bounded line, at most 1024 characters, with no markup.
53
+ **It is the only part always in context**, so write it as *when to use this*,
54
+ not as what the skill contains. A description that does not name the trigger
55
+ means the skill never loads.
56
+ - `featured: true` is for a shipped skill only. It puts the skill in the
57
+ catalog that every turn carries. Every other shipped skill is found with
58
+ `list_skills({query})`, so feature a skill only when a turn needs it before
59
+ its first call: the entry point of a product surface, or a craft skill that
60
+ work on that surface always reads.
61
+ - The body must be non-empty. Frontmatter is parsed as scalar `key: value`
62
+ pairs, not full YAML, and the fence is the first `---` line after the opening
63
+ one, so a `---` rule inside the body survives.
64
+ - `##` headings organize the body for the reader. `load_skill` returns the
65
+ whole document in one piece, so a section does not save context.
66
+
67
+ Confirm the parse by listing it back: `list_skills` shows name and description,
68
+ `load_skill {name}` returns the full instructions.
69
+
70
+ ## Write it so it fires and so it holds
71
+
72
+ - **Lead with the result, then the loop.** The reader is mid-task and will act
73
+ on the first thing that looks like an instruction.
74
+ - **Name tools exactly.** A renamed tool in a skill is a failure a model cannot
75
+ recover from. Check each call against the live schema or the capability
76
+ registry before writing it.
77
+ - **State what a tool refuses**, not only what it accepts. Most skill failures
78
+ are a call made with a field the tool drops.
79
+ - **Point at the neighbour** rather than restating it. A craft skill quotes a
80
+ call, the contract skill owns it.
81
+ - **Do not add checkpoints or deliverables** the user did not ask for. An
82
+ example in a skill is an illustration, not a requirement on the next request.
83
+
84
+ ## Shipping a system skill
85
+
86
+ One directory holding a `SKILL.md` whose frontmatter `name` matches the
87
+ directory. Nothing imports these files, so `packages/system-skills` is not a
88
+ workspace: `stageSystemSkills` in `scripts/bundle-backend.mjs` copies every
89
+ directory into `_skills/` beside the bundled `server.mjs`, and
90
+ `scripts/verify-backend-bundle.mjs` fails a build that misses one. A new
91
+ directory ships with no other change.
92
+
93
+ Discovery checks `NODETOOL_SYSTEM_SKILLS_DIR` first, and when it is set nothing
94
+ else is searched. Otherwise it uses `_skills/` beside the bundle, else
95
+ `packages/system-skills` on the way up. Only `SKILL.md` is read: a
96
+ skill ships as one document, so material that would have been a `references/`
97
+ file belongs in a `##` section of the body.
98
+
99
+ Symlink the new directory into `.claude/skills/<name>` when the repository's
100
+ coding agent should reach it too.
101
+
102
+ Two follow-ups a new system skill usually needs:
103
+
104
+ - Check the tool names yourself. `packages/agents/tests/shipped-skill-names.test.ts`
105
+ reads snake_case calls out of every shipped skill and checks them against the
106
+ registry, but only names with a known verb prefix (`add_`, `create_`, `get_`,
107
+ `list_` and so on). Names such as `web_search`, `request_secret` or
108
+ `find_model` pass unchecked, and so do node types. A skill
109
+ whose body names timeline calls can also go in that test's `SKILL_NAMES`,
110
+ which matches them exactly against the capability specs and `edit_timeline`'s
111
+ op list.
112
+ - A skill that guides one model line goes in `MODEL_PROMPTING_SKILLS`
113
+ (`packages/agents/src/model-prompting-skills.ts`) so `find_model` attaches it
114
+ to a matching route. `packages/agents/tests/model-prompting-skills.test.ts`
115
+ checks that table against the skills on disk, the model ids the shipped
116
+ provider manifests name, and the capability registry.
117
+
118
+ ## Reference
119
+
120
+ In a NodeTool checkout, these repository sources go further:
121
+
122
+ - `packages/system-skills/README.md` — the shipped set, and how one job
123
+ routes across it.
124
+ - `packages/agents/src/system-skills.ts` — loader and discovery rules.
125
+ - `packages/protocol/src/skill-document.ts` — the parser and the validators.