@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.
- package/dist/.nodetool-build-stamp +1 -1
- package/dist/_skills/LICENSE-iart-motion-design-skills +21 -0
- package/dist/_skills/README.md +211 -0
- package/dist/_skills/api-agents/SKILL.md +58 -0
- package/dist/_skills/api-apps/SKILL.md +54 -0
- package/dist/_skills/api-assets/SKILL.md +66 -0
- package/dist/_skills/api-collections/SKILL.md +33 -0
- package/dist/_skills/api-games/SKILL.md +81 -0
- package/dist/_skills/api-media/SKILL.md +131 -0
- package/dist/_skills/api-memory/SKILL.md +72 -0
- package/dist/_skills/api-models/SKILL.md +78 -0
- package/dist/_skills/api-scripts/SKILL.md +79 -0
- package/dist/_skills/api-settings/SKILL.md +49 -0
- package/dist/_skills/api-sketches/SKILL.md +61 -0
- package/dist/_skills/api-storyboards/SKILL.md +94 -0
- package/dist/_skills/api-timelines/SKILL.md +151 -0
- package/dist/_skills/api-web/SKILL.md +57 -0
- package/dist/_skills/api-workflows/SKILL.md +123 -0
- package/dist/_skills/beat-sync-editing/SKILL.md +208 -0
- package/dist/_skills/caption-titles/SKILL.md +94 -0
- package/dist/_skills/color-motion/SKILL.md +185 -0
- package/dist/_skills/commercial-beat-sheet/SKILL.md +338 -0
- package/dist/_skills/elevenlabs-audio-prompting/SKILL.md +163 -0
- package/dist/_skills/explainer-storyboard/SKILL.md +63 -0
- package/dist/_skills/flux-2-klein-prompting/SKILL.md +107 -0
- package/dist/_skills/frame-composition/SKILL.md +291 -0
- package/dist/_skills/game-direction/SKILL.md +99 -0
- package/dist/_skills/gpt-image-2-prompting/SKILL.md +161 -0
- package/dist/_skills/hailuo-prompting/SKILL.md +107 -0
- package/dist/_skills/kling-video-prompting/SKILL.md +188 -0
- package/dist/_skills/launch-commercial/SKILL.md +267 -0
- package/dist/_skills/launch-kit/SKILL.md +120 -0
- package/dist/_skills/logo-reveal/SKILL.md +225 -0
- package/dist/_skills/manimgx/SKILL.md +123 -0
- package/dist/_skills/minimax-h3-prompting/SKILL.md +134 -0
- package/dist/_skills/motion-ad/SKILL.md +281 -0
- package/dist/_skills/motion-background/SKILL.md +145 -0
- package/dist/_skills/motion-curves/SKILL.md +302 -0
- package/dist/_skills/motion-direction/SKILL.md +259 -0
- package/dist/_skills/motion-graphics/SKILL.md +217 -0
- package/dist/_skills/motion-principles/SKILL.md +255 -0
- package/dist/_skills/music-video-treatment/SKILL.md +40 -0
- package/dist/_skills/nano-banana-pro-prompting/SKILL.md +133 -0
- package/dist/_skills/native-game/SKILL.md +310 -0
- package/dist/_skills/native-game-reference/SKILL.md +879 -0
- package/dist/_skills/nodetool-3d-scene/SKILL.md +110 -0
- package/dist/_skills/nodetool-api-reference/SKILL.md +338 -0
- package/dist/_skills/nodetool-app-builder/SKILL.md +291 -0
- package/dist/_skills/nodetool-browser-agent/SKILL.md +119 -0
- package/dist/_skills/nodetool-chat-cli/SKILL.md +184 -0
- package/dist/_skills/nodetool-custom-node-developer/SKILL.md +294 -0
- package/dist/_skills/nodetool-deployment/SKILL.md +195 -0
- package/dist/_skills/nodetool-js-scripting/SKILL.md +223 -0
- package/dist/_skills/nodetool-model-provider-config/SKILL.md +348 -0
- package/dist/_skills/nodetool-rag-indexing/SKILL.md +153 -0
- package/dist/_skills/nodetool-sketch/SKILL.md +138 -0
- package/dist/_skills/nodetool-skill-author/SKILL.md +125 -0
- package/dist/_skills/nodetool-troubleshooter/SKILL.md +370 -0
- package/dist/_skills/nodetool-video-post/SKILL.md +149 -0
- package/dist/_skills/nodetool-workflow-builder/SKILL.md +295 -0
- package/dist/_skills/product-commercial/SKILL.md +132 -0
- package/dist/_skills/qwen-image-prompting/SKILL.md +122 -0
- package/dist/_skills/script-video/SKILL.md +106 -0
- package/dist/_skills/seedance-2-prompting/SKILL.md +194 -0
- package/dist/_skills/seedream-prompting/SKILL.md +117 -0
- package/dist/_skills/short-film/SKILL.md +123 -0
- package/dist/_skills/stable-audio-prompting/SKILL.md +130 -0
- package/dist/_skills/storyboard-core/SKILL.md +716 -0
- package/dist/_skills/timeline-edit-ops/SKILL.md +736 -0
- package/dist/_skills/trailer-template/SKILL.md +291 -0
- package/dist/_skills/ugc-video/SKILL.md +186 -0
- package/dist/_skills/veo-3-prompting/SKILL.md +140 -0
- package/dist/_skills/video-audio-continuity/SKILL.md +90 -0
- package/dist/_skills/video-clone/SKILL.md +96 -0
- package/dist/_skills/video-workflow/SKILL.md +119 -0
- package/dist/_skills/wan-2-6-prompting/SKILL.md +107 -0
- package/dist/app-build/bridge.d.ts.map +1 -1
- package/dist/app-build/bridge.js +44 -17
- package/dist/app-build/bridge.js.map +1 -1
- package/dist/capabilities/apps.d.ts.map +1 -1
- package/dist/capabilities/apps.js +55 -13
- package/dist/capabilities/apps.js.map +1 -1
- package/dist/capabilities/apps.specs.d.ts.map +1 -1
- package/dist/capabilities/apps.specs.js +5 -3
- package/dist/capabilities/apps.specs.js.map +1 -1
- package/dist/capabilities/game-asset-browser.d.ts.map +1 -1
- package/dist/capabilities/game-asset-browser.js +6 -1
- package/dist/capabilities/game-asset-browser.js.map +1 -1
- package/dist/capabilities/game.d.ts +1 -1
- package/dist/capabilities/game.d.ts.map +1 -1
- package/dist/capabilities/game.js +71 -56
- package/dist/capabilities/game.js.map +1 -1
- package/dist/capabilities/game.specs.js +1 -1
- package/dist/capabilities/game.specs.js.map +1 -1
- package/dist/capabilities/game3d.d.ts.map +1 -1
- package/dist/capabilities/game3d.js +14 -19
- package/dist/capabilities/game3d.js.map +1 -1
- package/dist/capabilities/gameAssertions.d.ts +52 -0
- package/dist/capabilities/gameAssertions.d.ts.map +1 -0
- package/dist/capabilities/gameAssertions.js +32 -0
- package/dist/capabilities/gameAssertions.js.map +1 -0
- package/dist/capabilities/models.d.ts.map +1 -1
- package/dist/capabilities/models.js +9 -0
- package/dist/capabilities/models.js.map +1 -1
- package/dist/capabilities/storyboards.d.ts.map +1 -1
- package/dist/capabilities/storyboards.js +36 -11
- package/dist/capabilities/storyboards.js.map +1 -1
- package/dist/capabilities/storyboards.specs.d.ts.map +1 -1
- package/dist/capabilities/storyboards.specs.js +11 -1
- package/dist/capabilities/storyboards.specs.js.map +1 -1
- package/dist/capabilities/workflows.d.ts.map +1 -1
- package/dist/capabilities/workflows.js +1 -0
- package/dist/capabilities/workflows.js.map +1 -1
- package/dist/capabilities/workflows.specs.d.ts.map +1 -1
- package/dist/capabilities/workflows.specs.js +4 -3
- package/dist/capabilities/workflows.specs.js.map +1 -1
- package/dist/evals/surfaces/game.d.ts.map +1 -1
- package/dist/evals/surfaces/game.js +29 -1
- package/dist/evals/surfaces/game.js.map +1 -1
- package/dist/game-authoring.d.ts +120 -0
- package/dist/game-authoring.d.ts.map +1 -1
- package/dist/game-build-integrity.d.ts +12 -0
- package/dist/game-build-integrity.d.ts.map +1 -0
- package/dist/game-build-integrity.js +78 -0
- package/dist/game-build-integrity.js.map +1 -0
- package/dist/game-examples.d.ts +44 -3
- package/dist/game-examples.d.ts.map +1 -1
- package/dist/game-examples.js +60 -10
- package/dist/game-examples.js.map +1 -1
- package/dist/system-skills.d.ts +1 -1
- package/dist/system-skills.js +1 -1
- package/dist/tools/builtin-tools.d.ts.map +1 -1
- package/dist/tools/builtin-tools.js +2 -0
- package/dist/tools/builtin-tools.js.map +1 -1
- 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.
|