agentweaver 0.1.16 → 0.1.17

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 (40) hide show
  1. package/README.md +50 -10
  2. package/dist/artifacts.js +73 -3
  3. package/dist/doctor/checks/executors.js +2 -2
  4. package/dist/flow-state.js +138 -1
  5. package/dist/index.js +175 -61
  6. package/dist/interactive/controller.js +56 -23
  7. package/dist/interactive/ink/index.js +22 -1
  8. package/dist/interactive/tree.js +2 -2
  9. package/dist/pipeline/auto-flow.js +9 -6
  10. package/dist/pipeline/context.js +6 -5
  11. package/dist/pipeline/declarative-flows.js +39 -20
  12. package/dist/pipeline/flow-catalog.js +36 -14
  13. package/dist/pipeline/flow-specs/auto-common.json +1 -0
  14. package/dist/pipeline/flow-specs/auto-golang.json +27 -1
  15. package/dist/pipeline/flow-specs/design-review/design-review-loop.json +13 -1
  16. package/dist/pipeline/flow-specs/plan.json +4 -2
  17. package/dist/pipeline/launch-profile-config.js +30 -18
  18. package/dist/pipeline/node-contract.js +1 -0
  19. package/dist/pipeline/node-registry.js +74 -5
  20. package/dist/pipeline/nodes/flow-run-node.js +188 -173
  21. package/dist/pipeline/nodes/llm-prompt-node.js +15 -33
  22. package/dist/pipeline/plugin-loader.js +389 -0
  23. package/dist/pipeline/plugin-types.js +1 -0
  24. package/dist/pipeline/registry.js +71 -4
  25. package/dist/pipeline/spec-compiler.js +1 -0
  26. package/dist/pipeline/spec-loader.js +14 -0
  27. package/dist/pipeline/spec-validator.js +6 -0
  28. package/dist/pipeline/value-resolver.js +2 -1
  29. package/dist/plugin-sdk.js +1 -0
  30. package/dist/runtime/artifact-registry.js +3 -0
  31. package/dist/runtime/execution-routing.js +25 -19
  32. package/dist/runtime/interactive-execution-routing.js +66 -57
  33. package/docs/example/.flows/examples/claude-example.json +50 -0
  34. package/docs/example/.plugins/claude-example-plugin/index.js +149 -0
  35. package/docs/example/.plugins/claude-example-plugin/plugin.json +8 -0
  36. package/docs/examples/.flows/claude-example.json +50 -0
  37. package/docs/examples/.plugins/claude-example-plugin/index.js +149 -0
  38. package/docs/examples/.plugins/claude-example-plugin/plugin.json +8 -0
  39. package/docs/plugin-sdk.md +731 -0
  40. package/package.json +6 -2
@@ -0,0 +1,731 @@
1
+ # AgentWeaver Plugin SDK
2
+
3
+ This guide is for external plugin authors who want to add custom executors, custom nodes, and custom declarative flows without modifying AgentWeaver core.
4
+
5
+ Use only the public SDK import:
6
+
7
+ ```ts
8
+ import type {
9
+ ExecutorDefinition,
10
+ JsonValue,
11
+ NodeContractMetadata,
12
+ PipelineNodeDefinition,
13
+ PluginEntryModuleExports,
14
+ PluginExecutorRegistration,
15
+ PluginManifest,
16
+ PluginNodeRegistration,
17
+ } from "agentweaver/plugin-sdk";
18
+ ```
19
+
20
+ Do not import from:
21
+
22
+ - `agentweaver`
23
+ - `agentweaver/dist/*`
24
+ - `agentweaver/src/*`
25
+ - repository-relative source paths
26
+
27
+ ## Architecture Overview
28
+
29
+ AgentWeaver has four pieces that matter to plugin authors:
30
+
31
+ - An `executor` integrates with an external tool or runtime action. It is a typed function with `defaultConfig` and `execute`.
32
+ - A `node` is the runtime unit referenced from declarative flow JSON. A node can use executors, read flow context, and return outputs.
33
+ - A `flow` is declarative JSON loaded from built-in specs, global `~/.agentweaver/.flows/**/*.json`, or project-local `.agentweaver/.flows/**/*.json`.
34
+ - A `plugin manifest` tells AgentWeaver where a global or project-local plugin is installed and which ESM entrypoint to load.
35
+
36
+ The runtime merges built-in registries with global and project-local plugin registrations. Flow validation then runs against that merged registry. That means a custom flow can reference plugin-provided node kinds directly, and plugin node metadata can declare dependencies on built-in or plugin-provided executor ids.
37
+
38
+ ## Installation Layout
39
+
40
+ Supported plugin locations are:
41
+
42
+ ```text
43
+ ~/.agentweaver/.plugins/<plugin-id>/plugin.json
44
+ .agentweaver/.plugins/<plugin-id>/plugin.json
45
+ ```
46
+
47
+ Rules enforced by the loader:
48
+
49
+ - AgentWeaver discovers plugin directories from `~/.agentweaver/.plugins/` and `.agentweaver/.plugins/`.
50
+ - Directories are loaded in lexicographic order.
51
+ - Each plugin directory must contain `plugin.json`.
52
+ - The directory name must match the manifest `id` exactly.
53
+ - Loading is fail-fast. An invalid plugin stops registry construction.
54
+ - Invalid plugins are not skipped partially.
55
+ - Duplicate built-in ids and duplicate plugin ids are rejected by registry creation.
56
+
57
+ Custom flows live under:
58
+
59
+ ```text
60
+ ~/.agentweaver/.flows/**/*.json
61
+ .agentweaver/.flows/**/*.json
62
+ ```
63
+
64
+ Those flows use the same validator and runtime as built-in flows.
65
+ If the same flow id or plugin id is discovered from more than one source, AgentWeaver fails fast instead of silently overriding one source with another.
66
+
67
+ ## Repository Examples
68
+
69
+ This repository keeps reference plugin examples under `docs/examples/`.
70
+
71
+ ## Claude Example Plugin
72
+
73
+ Current Claude example files:
74
+
75
+ - plugin manifest: `docs/examples/.plugins/claude-example-plugin/plugin.json`
76
+ - plugin entrypoint: `docs/examples/.plugins/claude-example-plugin/index.js`
77
+ - example flow: `docs/examples/.flows/claude-example.json`
78
+
79
+ `docs/examples/` is documentation material, not an auto-loaded runtime location. To run an example, copy it into `~/.agentweaver/` or `.agentweaver/`.
80
+
81
+ The Claude example is intentionally an executor-only plugin. The flow uses the built-in `llm-prompt` node with `executor: "claude"`, so the example demonstrates the same integration surface used by built-in LLM executors such as Codex and OpenCode.
82
+
83
+ Important runtime behavior:
84
+
85
+ - the executor shells out to `claude -p <prompt> --output-format json`
86
+ - for artifact-producing `llm-prompt` steps it also grants Claude access to the current workspace via `--add-dir <cwd>` and configured non-interactive edit permissions
87
+ - it accepts `CLAUDE_BIN`, `CLAUDE_MODEL`, and `CLAUDE_MAX_TURNS`
88
+ - optional runtime controls can be driven through `CLAUDE_PERMISSION_MODE`, `CLAUDE_ALLOWED_TOOLS`, and `CLAUDE_DISALLOWED_TOOLS`
89
+ - it normalizes assistant text from `result`, `message.content[*].text`, or `content[*].text`
90
+ - when a flow declares `requiredArtifacts`, `llm-prompt` only verifies and publishes those paths; the Claude prompt itself must create files such as `artifacts/examples/claude-example-proof.json`
91
+ - authentication is expected to be checked with `claude auth status`
92
+
93
+ ## Manifest Contract
94
+
95
+ `plugin.json` must be a JSON object with these required fields:
96
+
97
+ - `id`
98
+ - `sdk_version`
99
+ - `entrypoint`
100
+
101
+ Supported optional fields:
102
+
103
+ - `name`
104
+ - `version`
105
+ - `description`
106
+
107
+ Example:
108
+
109
+ ```json
110
+ {
111
+ "id": "sample-plugin",
112
+ "sdk_version": 1,
113
+ "entrypoint": "index.js",
114
+ "name": "Sample Plugin",
115
+ "version": "0.1.0",
116
+ "description": "Custom executor and node for a project-local flow."
117
+ }
118
+ ```
119
+
120
+ Validation rules:
121
+
122
+ - `id` must be a non-empty string.
123
+ - `sdk_version` must be a positive integer.
124
+ - `sdk_version` must match the current supported SDK major exactly. Today that value is `1`.
125
+ - `entrypoint` must be a non-empty string.
126
+
127
+ ## Entrypoint Rules
128
+
129
+ The manifest `entrypoint` is resolved relative to the plugin root.
130
+
131
+ Supported module formats:
132
+
133
+ - ESM `.js`
134
+ - ESM `.mjs`
135
+
136
+ Unsupported patterns:
137
+
138
+ - `.cjs`
139
+ - files without `.js` or `.mjs`
140
+ - entrypoints outside the plugin root
141
+ - default exports
142
+
143
+ The plugin entry module may export:
144
+
145
+ - `executors`
146
+ - `nodes`
147
+ - both
148
+
149
+ At least one recognized non-empty registration array must exist.
150
+
151
+ This is valid:
152
+
153
+ ```ts
154
+ export const executors = [/* ... */];
155
+ export const nodes = [/* ... */];
156
+ ```
157
+
158
+ This is invalid:
159
+
160
+ ```ts
161
+ export default {
162
+ executors: [],
163
+ };
164
+ ```
165
+
166
+ ## Executor Contract
167
+
168
+ Executors are registered as objects with `id` and `definition`.
169
+
170
+ ```ts
171
+ import type { ExecutorDefinition, JsonValue, PluginExecutorRegistration } from "agentweaver/plugin-sdk";
172
+
173
+ type EchoConfig = {
174
+ prefix: string;
175
+ };
176
+
177
+ type EchoInput = {
178
+ message: string;
179
+ };
180
+
181
+ type EchoResult = {
182
+ echoed: string;
183
+ };
184
+
185
+ const echoExecutorDefinition: ExecutorDefinition<EchoConfig, EchoInput, EchoResult> = {
186
+ kind: "sample-echo-executor",
187
+ version: 1,
188
+ defaultConfig: {
189
+ prefix: "plugin:",
190
+ },
191
+ async execute(context, input, config) {
192
+ context.ui.writeStdout(`[sample-echo-executor] ${input.message}\n`);
193
+ return {
194
+ echoed: `${config.prefix}${input.message}`,
195
+ };
196
+ },
197
+ };
198
+
199
+ export const executors: PluginExecutorRegistration[] = [
200
+ {
201
+ id: "sample-echo-executor",
202
+ definition: echoExecutorDefinition,
203
+ },
204
+ ];
205
+ ```
206
+
207
+ Rules enforced by the loader:
208
+
209
+ - `definition.kind === id`
210
+ - `definition.version` must be a positive integer
211
+ - `definition.defaultConfig` must be JSON-serializable
212
+ - `definition.execute` must be a function
213
+
214
+ ### Optional Routing Metadata
215
+
216
+ If your executor is intended to appear in the execution-routing modal and be used by `llm-prompt`, you may also export `routing`.
217
+
218
+ Example:
219
+
220
+ ```ts
221
+ export const executors: PluginExecutorRegistration[] = [
222
+ {
223
+ id: "claude",
224
+ definition: claudeExecutorDefinition,
225
+ routing: {
226
+ kind: "llm",
227
+ defaultModel: "sonnet",
228
+ models: ["sonnet", "opus", "haiku"],
229
+ },
230
+ },
231
+ ];
232
+ ```
233
+
234
+ Rules:
235
+
236
+ - `routing.kind` must currently be `llm`
237
+ - `routing.defaultModel` must be a non-empty string
238
+ - `routing.models` must be a non-empty string array
239
+ - `routing.defaultModel` must also appear inside `routing.models`
240
+
241
+ Executors without `routing` still work normally when referenced directly by plugin nodes, but they will not appear in the routing modal and cannot be selected through execution routing.
242
+
243
+ ### Executor Runtime Context
244
+
245
+ `ExecutorContext` contains:
246
+
247
+ - `cwd`: current project working directory
248
+ - `env`: resolved process environment
249
+ - `ui`: terminal output adapter
250
+ - `dryRun`: whether the current execution is dry-run
251
+ - `verbose`: verbose execution flag
252
+ - `mdLang`: markdown language preference when available
253
+ - `runtime.resolveCmd(name, envVarName)`: resolve a tool path
254
+ - `runtime.runCommand(argv, options)`: run a subprocess
255
+ - `runtime.artifactRegistry`: publish artifacts through the runtime registry
256
+
257
+ Use these facade APIs instead of importing internal runtime modules from AgentWeaver source.
258
+
259
+ ## Node Contract
260
+
261
+ Nodes are what flow JSON references through `step.node`.
262
+
263
+ Each node registration has three parts:
264
+
265
+ - `id`
266
+ - `definition`
267
+ - `metadata`
268
+
269
+ Example:
270
+
271
+ ```ts
272
+ import type {
273
+ NodeContractMetadata,
274
+ PipelineNodeDefinition,
275
+ PluginNodeRegistration,
276
+ } from "agentweaver/plugin-sdk";
277
+
278
+ type SampleNodeParams = {
279
+ message: string;
280
+ };
281
+
282
+ type SampleNodeResult = {
283
+ echoed: string;
284
+ };
285
+
286
+ const sampleNodeDefinition: PipelineNodeDefinition<SampleNodeParams, SampleNodeResult> = {
287
+ kind: "sample-node",
288
+ version: 1,
289
+ async run(context, params) {
290
+ const executor = context.executors.get("sample-echo-executor");
291
+ const result = await executor.execute(context, { message: params.message }, executor.defaultConfig);
292
+ context.setSummary?.(`Echoed: ${result.echoed}`);
293
+ return {
294
+ value: {
295
+ echoed: result.echoed,
296
+ },
297
+ };
298
+ },
299
+ };
300
+
301
+ const sampleNodeMetadata: NodeContractMetadata = {
302
+ kind: "sample-node",
303
+ version: 1,
304
+ prompt: "forbidden",
305
+ requiredParams: ["message"],
306
+ executors: ["sample-echo-executor"],
307
+ };
308
+
309
+ export const nodes: PluginNodeRegistration[] = [
310
+ {
311
+ id: "sample-node",
312
+ definition: sampleNodeDefinition,
313
+ metadata: sampleNodeMetadata,
314
+ },
315
+ ];
316
+ ```
317
+
318
+ Rules enforced by the loader:
319
+
320
+ - `definition.kind === id`
321
+ - `metadata.kind === id`
322
+ - `definition.version` must be a positive integer
323
+ - `metadata.version` must be a positive integer
324
+ - `definition.version === metadata.version`
325
+ - `definition.run` must be a function
326
+ - `metadata.prompt` must be one of `required`, `allowed`, or `forbidden`
327
+ - `metadata.requiredParams`, when present, must be a non-empty `string[]`
328
+ - `metadata.executors`, when present, must be a non-empty `string[]`
329
+ - `metadata.nestedFlowParam`, when present, must be a non-empty string
330
+
331
+ After registries are merged, every executor id listed in `metadata.executors` must exist. This can point to built-in executors or plugin-provided executors.
332
+
333
+ ### Node Runtime Context
334
+
335
+ `PipelineContext` contains everything from the executor-facing runtime plus pipeline-specific services:
336
+
337
+ - `issueKey`
338
+ - `jiraRef`
339
+ - `cwd`
340
+ - `env`
341
+ - `ui`
342
+ - `dryRun`
343
+ - `verbose`
344
+ - `mdLang`
345
+ - `runtime`
346
+ - `executors`
347
+ - `nodes`
348
+ - `registryContext`
349
+ - `setSummary(markdown)`
350
+ - `requestUserInput(...)` when the active node supports it
351
+ - `executionRouting`
352
+ - resume helpers such as `resumeStepValue` and `persistRunningStepValue`
353
+
354
+ Use the context object and the public SDK types as the stable integration surface. Do not couple plugin code to internal files under `src/` or `dist/`.
355
+
356
+ ## Executors vs. Nodes
357
+
358
+ Use an executor when you need a reusable integration boundary:
359
+
360
+ - call an external CLI
361
+ - wrap a service client
362
+ - normalize I/O or configuration across nodes
363
+
364
+ Use a node when you need a flow-visible runtime unit:
365
+
366
+ - consume flow params
367
+ - enforce required params and prompt behavior through metadata
368
+ - combine one or more executors
369
+ - publish outputs or set summaries for the surrounding flow
370
+
371
+ A declarative flow never references an executor directly. It references node kinds. Nodes are the bridge between flow JSON and executor-backed behavior.
372
+
373
+ ## Complete Plugin Entry Module
374
+
375
+ The following `index.js` is a minimal but complete plugin entrypoint that exports both a custom executor and a custom node:
376
+
377
+ ```js
378
+ /** @type {import("agentweaver/plugin-sdk").PluginExecutorRegistration[]} */
379
+ export const executors = [
380
+ {
381
+ id: "sample-echo-executor",
382
+ definition: {
383
+ kind: "sample-echo-executor",
384
+ version: 1,
385
+ defaultConfig: {
386
+ prefix: "plugin:",
387
+ },
388
+ async execute(context, input, config) {
389
+ context.ui.writeStdout(`[sample-echo-executor] ${String(input.message)}\n`);
390
+ return {
391
+ echoed: `${config.prefix}${String(input.message)}`,
392
+ };
393
+ },
394
+ },
395
+ },
396
+ ];
397
+
398
+ /** @type {import("agentweaver/plugin-sdk").PluginNodeRegistration[]} */
399
+ export const nodes = [
400
+ {
401
+ id: "sample-node",
402
+ definition: {
403
+ kind: "sample-node",
404
+ version: 1,
405
+ async run(context, params) {
406
+ const executor = context.executors.get("sample-echo-executor");
407
+ const result = await executor.execute(
408
+ context,
409
+ { message: String(params.message) },
410
+ executor.defaultConfig,
411
+ );
412
+ context.setSummary?.(`Sample node completed with ${result.echoed}`);
413
+ return {
414
+ value: result,
415
+ };
416
+ },
417
+ },
418
+ metadata: {
419
+ kind: "sample-node",
420
+ version: 1,
421
+ prompt: "forbidden",
422
+ requiredParams: ["message"],
423
+ executors: ["sample-echo-executor"],
424
+ },
425
+ },
426
+ ];
427
+ ```
428
+
429
+ ## Wiring a Custom Flow
430
+
431
+ A custom flow can be discovered from `~/.agentweaver/.flows/**/*.json` or `.agentweaver/.flows/**/*.json`.
432
+
433
+ A flow can reference your plugin-provided node id directly:
434
+
435
+ ```json
436
+ {
437
+ "kind": "sample-flow",
438
+ "version": 1,
439
+ "description": "Run the sample plugin node.",
440
+ "phases": [
441
+ {
442
+ "id": "run-sample",
443
+ "steps": [
444
+ {
445
+ "id": "echo",
446
+ "node": "sample-node",
447
+ "params": {
448
+ "message": {
449
+ "const": "hello from plugin"
450
+ }
451
+ }
452
+ }
453
+ ]
454
+ }
455
+ ]
456
+ }
457
+ ```
458
+
459
+ Save that file as either:
460
+
461
+ ```text
462
+ .agentweaver/.flows/sample-flow.json
463
+ ```
464
+
465
+ or:
466
+
467
+ ```text
468
+ ~/.agentweaver/.flows/sample-flow.json
469
+ ```
470
+
471
+ Once the plugin loads successfully, the flow validator treats `sample-node` like any built-in node kind.
472
+
473
+ ### Nested Flow Resolution
474
+
475
+ If a node supports nested flow references through a metadata field such as `nestedFlowParam`, AgentWeaver resolves the nested flow by file name.
476
+
477
+ Resolution rules:
478
+
479
+ - project-local, global, and built-in flow file names must not collide for the same nested flow reference
480
+ - multiple project-local files with the same base file name are ambiguous
481
+ - multiple global files with the same base file name are ambiguous
482
+ - multiple built-in files with the same base file name are ambiguous
483
+ - an unknown file name fails validation
484
+
485
+ Keep nested flow file names unique when you rely on file-name-based resolution.
486
+
487
+ ## End-to-End Walkthrough
488
+
489
+ This walkthrough is the acceptance path for the public docs. It creates a throwaway local plugin and runs a custom flow using only the documented contract.
490
+
491
+ ### 1. Create the plugin directory
492
+
493
+ Use either project-local or global installation. Project-local example:
494
+
495
+ ```bash
496
+ mkdir -p .agentweaver/.plugins/sample-plugin
497
+ ```
498
+
499
+ Global example:
500
+
501
+ ```bash
502
+ mkdir -p ~/.agentweaver/.plugins/sample-plugin
503
+ ```
504
+
505
+ ### 2. Write `plugin.json`
506
+
507
+ ```json
508
+ {
509
+ "id": "sample-plugin",
510
+ "sdk_version": 1,
511
+ "entrypoint": "index.js",
512
+ "name": "Sample Plugin",
513
+ "version": "0.1.0",
514
+ "description": "Throwaway local plugin used to validate the public SDK guide."
515
+ }
516
+ ```
517
+
518
+ Write it to one of:
519
+
520
+ ```text
521
+ .agentweaver/.plugins/sample-plugin/plugin.json
522
+ ~/.agentweaver/.plugins/sample-plugin/plugin.json
523
+ ```
524
+
525
+ ### 3. Write the plugin entrypoint
526
+
527
+ Write the complete `index.js` example from the previous section to one of:
528
+
529
+ ```text
530
+ .agentweaver/.plugins/sample-plugin/index.js
531
+ ~/.agentweaver/.plugins/sample-plugin/index.js
532
+ ```
533
+
534
+ ### 4. Create the custom flow
535
+
536
+ Project-local:
537
+
538
+ ```bash
539
+ mkdir -p .agentweaver/.flows
540
+ ```
541
+
542
+ Global:
543
+
544
+ ```bash
545
+ mkdir -p ~/.agentweaver/.flows
546
+ ```
547
+
548
+ Create `sample-flow.json` in the matching flow directory with the flow JSON from the previous section.
549
+
550
+ ### 5. Build AgentWeaver
551
+
552
+ From the AgentWeaver repository:
553
+
554
+ ```bash
555
+ npm install
556
+ npm run build
557
+ ```
558
+
559
+ ### 6. Run the flow
560
+
561
+ Custom flows are discovered in the interactive catalog:
562
+
563
+ ```bash
564
+ node dist/index.js
565
+ node dist/index.js --help
566
+ ```
567
+
568
+ The flow should appear under either the `global` or `custom` catalog root with the id `sample-flow`. Select it from interactive mode and run it there.
569
+
570
+ ### 7. Expected result
571
+
572
+ The registry should load the plugin, validate `sample-node`, and allow the custom flow to execute without reading AgentWeaver internals.
573
+
574
+ If execution fails, use the troubleshooting section below before inspecting any core source files.
575
+
576
+ ## Compatibility and Versioning
577
+
578
+ Compatibility is strict:
579
+
580
+ - `sdk_version` must match the currently supported SDK major exactly
581
+ - the current public SDK major is `1`
582
+ - the supported public export is `agentweaver/plugin-sdk`
583
+ - built-in node and executor ids are protected and cannot be overridden
584
+ - plugin-provided ids must also be unique across all loaded plugins
585
+
586
+ Recommended upgrade workflow after updating AgentWeaver:
587
+
588
+ 1. Check whether `AGENTWEAVER_PLUGIN_SDK_VERSION` changed.
589
+ 2. Update `sdk_version` in each plugin manifest if the SDK major changed.
590
+ 3. Rebuild AgentWeaver.
591
+ 4. Run at least one local custom flow that exercises your plugin nodes.
592
+ 5. Re-check packaging or deployment steps if you publish your plugin from a separate repository.
593
+
594
+ If the SDK major changes, review your plugin entrypoint, executor definitions, node metadata, routing metadata, and custom flow assumptions before trusting the plugin in production use.
595
+
596
+ ## Testing Workflow for Plugin Authors
597
+
598
+ A practical minimum workflow:
599
+
600
+ 1. Build AgentWeaver with `npm run build`.
601
+ 2. Keep your plugin under `~/.agentweaver/.plugins/<plugin-id>/` or `.agentweaver/.plugins/<plugin-id>/`.
602
+ 3. Keep one or more smoke-test flows under `~/.agentweaver/.flows/` or `.agentweaver/.flows/`.
603
+ 4. Run a custom flow that touches every plugin node and executor dependency.
604
+ 5. Re-run the flow after every AgentWeaver upgrade.
605
+
606
+ Useful checks:
607
+
608
+ - `npm run check`
609
+ - `npm run build`
610
+ - `node dist/index.js --help`
611
+ - interactive catalog inspection to confirm the custom flow is visible
612
+
613
+ ## Troubleshooting
614
+
615
+ ### Manifest parse error
616
+
617
+ Symptom: AgentWeaver reports that it failed to parse `plugin.json`.
618
+
619
+ Checks:
620
+
621
+ - ensure `plugin.json` is valid JSON
622
+ - ensure the top-level value is a JSON object
623
+
624
+ ### Plugin directory does not match manifest id
625
+
626
+ Symptom: the loader reports that the manifest id does not match the installation directory.
627
+
628
+ Fix:
629
+
630
+ - rename the directory or change `plugin.json.id` so both values match exactly
631
+
632
+ ### Unsupported `sdk_version`
633
+
634
+ Symptom: the loader reports that the plugin declares one SDK version but AgentWeaver supports another.
635
+
636
+ Fix:
637
+
638
+ - change `sdk_version` to the exact supported major
639
+ - review compatibility before trusting the plugin after the upgrade
640
+
641
+ ### Invalid entrypoint path
642
+
643
+ Symptom: the loader reports that the entrypoint resolves outside the plugin root.
644
+
645
+ Fix:
646
+
647
+ - point `entrypoint` to a file inside `.agentweaver/.plugins/<plugin-id>/`
648
+
649
+ ### Unsupported module format
650
+
651
+ Symptom: the loader rejects `.cjs` or another unsupported file extension.
652
+
653
+ Fix:
654
+
655
+ - use ESM `.js` or `.mjs`
656
+
657
+ ### Default export misuse
658
+
659
+ Symptom: the loader reports that default exports are not supported.
660
+
661
+ Fix:
662
+
663
+ - export named `executors` and/or `nodes` arrays only
664
+
665
+ ### Empty or missing registration arrays
666
+
667
+ Symptom: the loader reports that the plugin must export at least one non-empty recognized registration array.
668
+
669
+ Fix:
670
+
671
+ - export `executors`, `nodes`, or both
672
+ - make sure at least one of them contains a registration
673
+
674
+ ### Invalid executor registration
675
+
676
+ Checks:
677
+
678
+ - `definition.kind` matches `id`
679
+ - `definition.version` is a positive integer
680
+ - `definition.defaultConfig` is JSON-serializable
681
+ - `definition.execute` is a function
682
+
683
+ ### Invalid node registration
684
+
685
+ Checks:
686
+
687
+ - `definition.kind` matches `id`
688
+ - `metadata.kind` matches `id`
689
+ - `definition.version` matches `metadata.version`
690
+ - `metadata.prompt` is `required`, `allowed`, or `forbidden`
691
+ - `metadata.executors` references valid executor ids
692
+
693
+ ### Duplicate ids
694
+
695
+ Symptom: registry creation fails because a node or executor id already exists.
696
+
697
+ Fix:
698
+
699
+ - rename the plugin-provided id
700
+ - avoid built-in ids and ids used by other local plugins
701
+
702
+ ### Unresolved executor dependencies
703
+
704
+ Symptom: a node declares `metadata.executors` and registry creation reports an unknown executor.
705
+
706
+ Fix:
707
+
708
+ - export the executor from the same plugin or another loaded plugin
709
+ - confirm the executor id matches exactly
710
+
711
+ ### Missing or ambiguous nested flow reference
712
+
713
+ Symptom: flow validation fails with an unknown or ambiguous nested flow name.
714
+
715
+ Fix:
716
+
717
+ - ensure the referenced file exists
718
+ - avoid duplicate base file names across global, project-local, and built-in flows
719
+ - keep global and project-local nested flow file names unique
720
+
721
+ ## Supported Boundary Summary
722
+
723
+ Treat these as stable public assumptions for plugin authoring:
724
+
725
+ - import only from `agentweaver/plugin-sdk`
726
+ - install local plugins under `~/.agentweaver/.plugins/<plugin-id>/plugin.json` or `.agentweaver/.plugins/<plugin-id>/plugin.json`
727
+ - export named `executors` and/or `nodes` arrays from an ESM `.js` or `.mjs` entrypoint
728
+ - reference plugin node ids from `~/.agentweaver/.flows/**/*.json` or `.agentweaver/.flows/**/*.json`
729
+ - keep plugin ids, node ids, executor ids, and nested flow file names unambiguous
730
+
731
+ Everything else should be treated as internal implementation detail unless it is exposed through the public SDK subpath in a future release.