@vimhead.dev/norn-cli 0.1.0-tip.0

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 (171) hide show
  1. package/README.md +13 -0
  2. package/assets/README.md +157 -0
  3. package/assets/docs/README.md +23 -0
  4. package/assets/docs/agents.md +64 -0
  5. package/assets/docs/cli.md +183 -0
  6. package/assets/docs/composition.md +76 -0
  7. package/assets/docs/persistence.md +56 -0
  8. package/assets/docs/projects.md +75 -0
  9. package/assets/docs/recovery.md +56 -0
  10. package/assets/docs/resources.md +61 -0
  11. package/assets/docs/workflows.md +57 -0
  12. package/assets/examples/agent-then-analysis/README.md +103 -0
  13. package/assets/examples/agent-then-analysis/input.json +5 -0
  14. package/assets/examples/agent-then-analysis/norn.project.json +4 -0
  15. package/assets/examples/agent-then-analysis/plugin.ts +89 -0
  16. package/assets/examples/coordinating-multiple-agents/README.md +56 -0
  17. package/assets/examples/coordinating-multiple-agents/input.json +10 -0
  18. package/assets/examples/coordinating-multiple-agents/norn.project.json +4 -0
  19. package/assets/examples/coordinating-multiple-agents/plugin.ts +102 -0
  20. package/assets/examples/coordinating-multiple-agents/queue-adapter.ts +52 -0
  21. package/assets/examples/coordinating-multiple-agents/work-queue.ts +153 -0
  22. package/assets/examples/minimal-workflow/README.md +71 -0
  23. package/assets/examples/minimal-workflow/norn.project.json +4 -0
  24. package/assets/examples/minimal-workflow/plugin.ts +29 -0
  25. package/assets/examples/shared-state/README.md +19 -0
  26. package/assets/examples/shared-state/input.json +1 -0
  27. package/assets/examples/shared-state/norn.project.json +4 -0
  28. package/assets/examples/shared-state/plugin.ts +47 -0
  29. package/assets/examples/worktree-development-loop/README.md +66 -0
  30. package/assets/examples/worktree-development-loop/index.ts +1 -0
  31. package/assets/examples/worktree-development-loop/manifest.ts +26 -0
  32. package/assets/examples/worktree-development-loop/norn.project.json +9 -0
  33. package/assets/examples/worktree-development-loop/plugin.ts +27 -0
  34. package/assets/examples/worktree-development-loop/shared/commands.ts +6 -0
  35. package/assets/examples/worktree-development-loop/state.ts +23 -0
  36. package/assets/examples/worktree-development-loop/workflows/development-loop/declaration.ts +8 -0
  37. package/assets/examples/worktree-development-loop/workflows/development-loop/execute.ts +18 -0
  38. package/assets/examples/worktree-development-loop/workflows/development-loop/index.ts +4 -0
  39. package/assets/examples/worktree-development-loop/workflows/development-loop/repository.ts +22 -0
  40. package/assets/examples/worktree-development-loop/workflows/development-loop/schema.ts +14 -0
  41. package/assets/examples/worktree-development-loop/workflows/implementation/declaration.ts +8 -0
  42. package/assets/examples/worktree-development-loop/workflows/implementation/execute.ts +54 -0
  43. package/assets/examples/worktree-development-loop/workflows/implementation/index.ts +3 -0
  44. package/assets/examples/worktree-development-loop/workflows/implementation/schema.ts +12 -0
  45. package/assets/examples/worktree-development-loop/workflows/planning/declaration.ts +8 -0
  46. package/assets/examples/worktree-development-loop/workflows/planning/execute.ts +28 -0
  47. package/assets/examples/worktree-development-loop/workflows/planning/index.ts +3 -0
  48. package/assets/examples/worktree-development-loop/workflows/planning/schema.ts +12 -0
  49. package/assets/examples/worktree-development-loop/workflows/review/declaration.ts +8 -0
  50. package/assets/examples/worktree-development-loop/workflows/review/execute.ts +53 -0
  51. package/assets/examples/worktree-development-loop/workflows/review/index.ts +10 -0
  52. package/assets/examples/worktree-development-loop/workflows/review/schema.ts +23 -0
  53. package/assets/examples/worktree-development-loop/workflows/review-router/declaration.ts +12 -0
  54. package/assets/examples/worktree-development-loop/workflows/review-router/execute.ts +51 -0
  55. package/assets/examples/worktree-development-loop/workflows/review-router/index.ts +3 -0
  56. package/assets/examples/worktree-development-loop/workflows/review-router/schema.ts +12 -0
  57. package/assets/package.json +1 -0
  58. package/assets/packages/cli/src/build-info.ts +36 -0
  59. package/assets/packages/cli/src/bun/cli.ts +16 -0
  60. package/assets/packages/cli/src/cli.ts +1135 -0
  61. package/assets/packages/cli/src/client.ts +167 -0
  62. package/assets/packages/cli/src/documentation-intro.ts +30 -0
  63. package/assets/packages/cli/src/documentation.ts +149 -0
  64. package/assets/packages/cli/src/generated-build-info.ts +12 -0
  65. package/assets/packages/cli/src/internal/agent-directory.ts +5 -0
  66. package/assets/packages/cli/src/internal/agent-response-tool.ts +96 -0
  67. package/assets/packages/cli/src/internal/agents.ts +365 -0
  68. package/assets/packages/cli/src/internal/artifacts.ts +26 -0
  69. package/assets/packages/cli/src/internal/commands.ts +180 -0
  70. package/assets/packages/cli/src/internal/documentation-bundle.ts +49 -0
  71. package/assets/packages/cli/src/internal/engine.ts +501 -0
  72. package/assets/packages/cli/src/internal/errors.ts +39 -0
  73. package/assets/packages/cli/src/internal/file-names.ts +3 -0
  74. package/assets/packages/cli/src/internal/launch-request.ts +94 -0
  75. package/assets/packages/cli/src/internal/logs.ts +41 -0
  76. package/assets/packages/cli/src/internal/metrics.ts +356 -0
  77. package/assets/packages/cli/src/internal/pi-assets.ts +95 -0
  78. package/assets/packages/cli/src/internal/resource-bindings.ts +35 -0
  79. package/assets/packages/cli/src/internal/run-lease.ts +158 -0
  80. package/assets/packages/cli/src/internal/run-log.ts +59 -0
  81. package/assets/packages/cli/src/internal/run-names.ts +36 -0
  82. package/assets/packages/cli/src/internal/run-resources.ts +23 -0
  83. package/assets/packages/cli/src/internal/run-state.ts +380 -0
  84. package/assets/packages/cli/src/internal/run-store.ts +323 -0
  85. package/assets/packages/cli/src/internal/run.ts +133 -0
  86. package/assets/packages/cli/src/internal/state-store.ts +75 -0
  87. package/assets/packages/cli/src/internal/usage.ts +70 -0
  88. package/assets/packages/cli/src/internal/workflow-registry.ts +176 -0
  89. package/assets/packages/cli/src/plugin-loader.ts +412 -0
  90. package/assets/packages/cli/src/resources.ts +67 -0
  91. package/assets/packages/core/src/agent-protocol.ts +1 -0
  92. package/assets/packages/core/src/atomic-files.ts +24 -0
  93. package/assets/packages/core/src/errors.ts +3 -0
  94. package/assets/packages/sdk/src/agent-resource-adapter.ts +11 -0
  95. package/assets/packages/sdk/src/api.ts +821 -0
  96. package/assets/packages/sdk/src/files.ts +136 -0
  97. package/assets/packages/sdk/src/index.ts +6 -0
  98. package/assets/packages/sdk/src/resources.ts +20 -0
  99. package/assets/packages/sdk/src/schema.ts +48 -0
  100. package/assets/packages/sdk/src/seer/config.ts +62 -0
  101. package/assets/packages/sdk/src/seer/index.ts +7 -0
  102. package/assets/packages/sdk/src/state-adapter.ts +75 -0
  103. package/assets/setup/providers.md +128 -0
  104. package/assets/setup/releases.md +76 -0
  105. package/assets/tests/workflow-ref.test.ts +113 -0
  106. package/bin/norn.mjs +10 -0
  107. package/dist/build-info.d.ts +30 -0
  108. package/dist/build-info.js +6 -0
  109. package/dist/cli.d.ts +2 -0
  110. package/dist/cli.js +1032 -0
  111. package/dist/client.d.ts +48 -0
  112. package/dist/client.js +118 -0
  113. package/dist/documentation-intro.d.ts +5 -0
  114. package/dist/documentation-intro.js +29 -0
  115. package/dist/documentation.d.ts +33 -0
  116. package/dist/documentation.js +132 -0
  117. package/dist/generated-build-info.d.ts +10 -0
  118. package/dist/generated-build-info.js +14 -0
  119. package/dist/internal/agent-directory.d.ts +4 -0
  120. package/dist/internal/agent-directory.js +8 -0
  121. package/dist/internal/agent-response-tool.d.ts +21 -0
  122. package/dist/internal/agent-response-tool.js +79 -0
  123. package/dist/internal/agents.d.ts +29 -0
  124. package/dist/internal/agents.js +336 -0
  125. package/dist/internal/artifacts.d.ts +10 -0
  126. package/dist/internal/artifacts.js +29 -0
  127. package/dist/internal/commands.d.ts +18 -0
  128. package/dist/internal/commands.js +147 -0
  129. package/dist/internal/documentation-bundle.d.ts +16 -0
  130. package/dist/internal/documentation-bundle.js +42 -0
  131. package/dist/internal/engine.d.ts +44 -0
  132. package/dist/internal/engine.js +399 -0
  133. package/dist/internal/errors.d.ts +14 -0
  134. package/dist/internal/errors.js +38 -0
  135. package/dist/internal/file-names.d.ts +1 -0
  136. package/dist/internal/file-names.js +7 -0
  137. package/dist/internal/launch-request.d.ts +33 -0
  138. package/dist/internal/launch-request.js +110 -0
  139. package/dist/internal/logs.d.ts +16 -0
  140. package/dist/internal/logs.js +38 -0
  141. package/dist/internal/metrics.d.ts +19 -0
  142. package/dist/internal/metrics.js +282 -0
  143. package/dist/internal/pi-assets.d.ts +13 -0
  144. package/dist/internal/pi-assets.js +94 -0
  145. package/dist/internal/resource-bindings.d.ts +13 -0
  146. package/dist/internal/resource-bindings.js +34 -0
  147. package/dist/internal/run-lease.d.ts +32 -0
  148. package/dist/internal/run-lease.js +166 -0
  149. package/dist/internal/run-log.d.ts +30 -0
  150. package/dist/internal/run-log.js +71 -0
  151. package/dist/internal/run-names.d.ts +1 -0
  152. package/dist/internal/run-names.js +144 -0
  153. package/dist/internal/run-resources.d.ts +6 -0
  154. package/dist/internal/run-resources.js +26 -0
  155. package/dist/internal/run-state.d.ts +95 -0
  156. package/dist/internal/run-state.js +323 -0
  157. package/dist/internal/run-store.d.ts +35 -0
  158. package/dist/internal/run-store.js +314 -0
  159. package/dist/internal/run.d.ts +51 -0
  160. package/dist/internal/run.js +101 -0
  161. package/dist/internal/state-store.d.ts +22 -0
  162. package/dist/internal/state-store.js +97 -0
  163. package/dist/internal/usage.d.ts +5 -0
  164. package/dist/internal/usage.js +70 -0
  165. package/dist/internal/workflow-registry.d.ts +35 -0
  166. package/dist/internal/workflow-registry.js +129 -0
  167. package/dist/plugin-loader.d.ts +55 -0
  168. package/dist/plugin-loader.js +353 -0
  169. package/dist/resources.d.ts +11 -0
  170. package/dist/resources.js +98 -0
  171. package/package.json +52 -0
package/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # Norn CLI
2
+
3
+ Harness-agnostic workflow runtime with Pi-powered agent sessions.
4
+
5
+ ```bash
6
+ npm install -g @vimhead.dev/norn-cli@tip
7
+ norn docs intro
8
+ ```
9
+
10
+ The package includes its matching SDK, documentation, and runnable examples.
11
+ Use `norn pi` to configure Norn's provider credentials and default model.
12
+
13
+ [Installation, authentication, and optional adapters](./assets/README.md).
@@ -0,0 +1,157 @@
1
+ # Norn
2
+
3
+ Norn is a harness-agnostic workflow framework and runtime built primarily for
4
+ agents. Use the Norn SDK to write reusable agent-driven and code-driven TypeScript
5
+ workflows, then discover, run, inspect, and recover them through the CLI.
6
+
7
+ Norn is intended as a portable replacement for harness-specific subagents and
8
+ workflow extensions. Use it from Claude Code, Pi, Codex, or any other harness
9
+ that can invoke its CLI.
10
+
11
+ Norn agents are powered by the bundled, open-source and extensible
12
+ [Pi coding agent](https://pi.dev). Your outer harness does not need to be Pi,
13
+ and code-only workflows do not require a model.
14
+
15
+ - [Documentation index](docs/README.md) — focused references by capability
16
+ - [Create → run → change a workflow](examples/minimal-workflow/README.md) — code-driven, no model required
17
+ - [Norn agent → saved artifact → analysis](examples/agent-then-analysis/README.md) — agent-driven, with a recoverable transition
18
+ - [Norn SDK types](packages/sdk/src/api.ts)
19
+
20
+ ## Installation
21
+
22
+ Install the runtime, authenticate for workflows that use Norn agents, and
23
+ optionally connect your harness with an adapter. Direct CLI use needs no adapter.
24
+
25
+ ### 1. Install the runtime
26
+
27
+ Install the rolling npm `tip` release (Node `>=22.19.0`):
28
+
29
+ ```bash
30
+ npm install -g @vimhead.dev/norn-cli@tip
31
+ norn version
32
+ ```
33
+
34
+ Releases are prereleases, not stable `latest` releases. For a standalone binary
35
+ without Node, use the matching GitHub `tip` release:
36
+
37
+ ```bash
38
+ curl -fsSL https://github.com/vimhead/norn/releases/download/tip/install.sh | sh
39
+ ```
40
+
41
+ Set `NORN_INSTALL_DIR` to select a different binary installation directory.
42
+
43
+ [Runtime selection](docs/cli.md#select-the-runtime) covers source checkout invocation
44
+ and keeping examples/docs matched to the executable. Upgrade discovery:
45
+
46
+ ```bash
47
+ norn upgrade --dry-run
48
+ ```
49
+
50
+ ### 2. Authenticate Norn agents
51
+
52
+ Open the bundled Pi interface; no separate Pi installation is required:
53
+
54
+ ```bash
55
+ norn pi
56
+ ```
57
+
58
+ Inside the interactive session:
59
+
60
+ 1. Run `/login`, choose a provider, and complete its authentication flow.
61
+ 2. Run `/model`, highlight a model, and press **Ctrl+S** to save the startup default.
62
+ 3. Run `/quit`.
63
+
64
+ Model-free workflows need no provider authentication. For other credential
65
+ methods, custom providers, and Norn's configuration directory, see
66
+ [providers and authentication](setup/providers.md).
67
+
68
+ ### 3. Optionally connect your harness
69
+
70
+ The shipped Pi and Cursor adapters deliver Norn documentation context to your
71
+ harness. Installing Norn alone does not register an adapter. Claude Code, Codex,
72
+ and other harnesses can [invoke the CLI directly](docs/cli.md#javascript-client-and-other-harnesses).
73
+
74
+ #### Pi
75
+
76
+ With Pi already installed and `norn` available on `PATH`, install the adapter
77
+ and start a new session:
78
+
79
+ ```bash
80
+ pi install npm:@vimhead.dev/pi-norn@tip
81
+ pi
82
+ ```
83
+
84
+ To select a CLI executable outside `PATH`:
85
+
86
+ ```bash
87
+ pi --norn-executable /absolute/path/to/norn
88
+ ```
89
+
90
+ #### Cursor
91
+
92
+ 1. Open **Customize** in Cursor and choose **From GitHub Repository**.
93
+ 2. Enter `https://github.com/vimhead/norn` to import the marketplace.
94
+ 3. Install the **norn** plugin, choosing user or project scope.
95
+ 4. Start a new agent conversation.
96
+
97
+ By default the adapter runs `norn` from `PATH`. To select a CLI executable
98
+ outside `PATH`, start Cursor with an executable path:
99
+
100
+ ```bash
101
+ NORN_EXECUTABLE=/absolute/path/to/norn cursor .
102
+ ```
103
+
104
+ Need an adapter for another harness? [Open an issue](https://github.com/vimhead/norn/issues/new)
105
+ with the harness name.
106
+
107
+ ## Setting up a Norn project
108
+
109
+ [Projects and loading](docs/projects.md) covers initialization, registration,
110
+ reusable configuration, dependencies, source reload, and discovery diagnostics.
111
+
112
+ ## Build workflows with the Norn SDK
113
+
114
+ Install SDK types and helpers for TypeScript/editor support:
115
+
116
+ ```bash
117
+ npm install -D @vimhead.dev/norn@tip
118
+ ```
119
+
120
+ Use the SDK version reported by `norn version` for an exact runtime match. Runtime
121
+ execution also supplies [virtual SDK imports](docs/projects.md#import-and-reload),
122
+ so standalone examples need no local SDK installation.
123
+
124
+ [Workflow authoring](docs/workflows.md) covers declarations, implementations,
125
+ commands, and run outcomes. Focused companion references:
126
+
127
+ - [Norn agents](docs/agents.md)
128
+ - [State, artifacts, and workspaces](docs/persistence.md)
129
+ - [Composition and reuse](docs/composition.md)
130
+ - [Recovery and gates](docs/recovery.md)
131
+
132
+ The larger [worktree development loop](examples/worktree-development-loop/README.md)
133
+ is an optional composition example, not a required workflow architecture.
134
+
135
+ ## Run workflows with Norn
136
+
137
+ [CLI and client](docs/cli.md) covers live contract discovery, JSON invocation,
138
+ launch/wait semantics, results, and use from other harnesses.
139
+
140
+ ## Development
141
+
142
+ ```bash
143
+ pnpm install --frozen-lockfile
144
+ pnpm check
145
+ pnpm test
146
+ pnpm pack:dry
147
+ ```
148
+
149
+ Use the pnpm version pinned in `package.json`. The private root coordinates three
150
+ published workspaces: `packages/sdk`, `packages/cli`, and `packages/pi-norn`.
151
+ `packages/core` is private source shared through consumer builds, not a fourth
152
+ published dependency. No separate core build is needed.
153
+
154
+ Checks cover package builds, TypeScript (including examples, adapters, scripts,
155
+ and tests), runtime regressions, isolated npm installations, and standalone binaries.
156
+ `pack:dry` creates local tarballs without publishing. See
157
+ [release setup](setup/releases.md) for bootstrap and trusted publishing.
@@ -0,0 +1,23 @@
1
+ # Norn documentation
2
+
3
+ Norn capabilities are ordinary TypeScript plugins: an agent can write one during a task, register it in that project, exercise it, change it, and retain it for another caller. No generated project hierarchy or separate compilation step is required.
4
+
5
+ ## Read by task
6
+
7
+ | Task | Documentation | Runnable example |
8
+ |---|---|---|
9
+ | Build, register, or diagnose workflows with the Norn SDK | [Projects and loading](projects.md), [Workflow authoring](workflows.md) | [Create → run → change](../examples/minimal-workflow/README.md) |
10
+ | Discover contracts or invoke Norn from another harness | [CLI and client](cli.md) | [Create → run → change](../examples/minimal-workflow/README.md) |
11
+ | Delegate work with explicit inputs and structured results | [Norn agents](agents.md) | [Norn agent → saved artifact → analysis](../examples/agent-then-analysis/README.md) |
12
+ | Initialize shared resources, attach state tools, or coordinate file mutations | [Resources and locking](resources.md) | [Explicit shared state](../examples/shared-state/README.md) |
13
+ | Implement a custom resource and adapter to coordinate concurrent agents | [Resource contracts](resources.md) | [Example-local work queue](../examples/coordinating-multiple-agents/README.md) |
14
+ | Retain evidence or choose a filesystem boundary | [State, artifacts, and workspaces](persistence.md) | [Norn agent → saved artifact → analysis](../examples/agent-then-analysis/README.md) |
15
+ | Reuse a workflow with a caller-selected continuation | [Composition](composition.md) | [Worktree development loop](../examples/worktree-development-loop/README.md) — larger, optional |
16
+ | Repair a failed run without repeating earlier work | [Recovery and gates](recovery.md) | [Analysis-only repair](../examples/agent-then-analysis/README.md#repair-only-the-analysis-step) |
17
+
18
+ [Public types](../packages/sdk/src/api.ts) define the Norn SDK's authoring interface. CLI discovery exposes the currently loaded project, not a documentation-time workflow catalogue. See [installation](../README.md#installation) for runtime setup.
19
+
20
+ | Decision | GOOD | BAD |
21
+ |---|---|---|
22
+ | IF a task needs persisted workflow control, independently prompted Norn agents, or a callable capability, THEN use the relevant pages and author only the missing capability. ELSE solve it directly. | A retryable delivery step consuming saved assessments. | Wrapping a literal text replacement in a workflow solely because Norn is installed. |
23
+ | IF the executable differs from the installation containing these docs, THEN locate matching docs or invoke this installation explicitly using [CLI setup](cli.md#select-the-runtime). ELSE use its local examples and types. | A source checkout paired with its own `packages/cli/bin/norn.mjs`. | Reading a new checkout while invoking an older `PATH` binary. |
@@ -0,0 +1,64 @@
1
+ # Norn agents
2
+
3
+ A Norn agent is a workflow-managed session powered by the bundled, open-source and extensible [Pi coding agent](https://pi.dev). Pi supplies the agent implementation regardless of which [outer harness invokes Norn](cli.md#javascript-client-and-other-harnesses). Extensions, skills, and custom providers can customize these sessions; their loading and boundaries are described below.
4
+
5
+ The [Norn agent → saved artifact → analysis example](../examples/agent-then-analysis/README.md) is a complete two-session application. Agent outputs flow through a saved contract, not shared conversation history.
6
+
7
+ ## One prompt or a retained session
8
+
9
+ `run.agents.prompt({ label, prompt, response, ...sessionOptions })` creates a Pi session, prompts it, validates its response, and disposes it in `finally`. It returns the parsed response itself, not `{ response, raw }`.
10
+
11
+ For follow-up turns in the same conversation:
12
+
13
+ ```ts
14
+ const agentSession = await run.agents.createSession({
15
+ label: "implementation",
16
+ cwd: run.cwd,
17
+ tools: ["read", "bash", "edit", "write"],
18
+ });
19
+ try {
20
+ const implementation = await agentSession.prompt({
21
+ prompt: task,
22
+ response: implementationSchema,
23
+ maxAttempts: 2,
24
+ });
25
+ const verification = await agentSession.prompt({
26
+ prompt: JSON.stringify({ task: "Verify the saved changes", implementation }),
27
+ response: verificationSchema,
28
+ maxAttempts: 2,
29
+ });
30
+ const verificationArtifact = await run.artifacts.write("verification.json", JSON.stringify(verification));
31
+ return run.complete({ artifacts: { verification: verificationArtifact } });
32
+ } finally {
33
+ await agentSession.dispose();
34
+ }
35
+ ```
36
+
37
+ `task` and both Zod schemas are capability-specific inputs in this fragment. [Provider setup](../setup/providers.md) is a prerequisite for Norn agents; detached execution cannot conduct an interactive login.
38
+
39
+ ## Response contract and evidence
40
+
41
+ Norn adds `pi_workflows_agent_response` to the requested tools and supplies the schema and response instructions. If a turn omits that tool call, Norn requests finalization with only that tool active. Invalid or missing structured responses can be retried in the same session (`maxAttempts`, default 3). This is response-contract recovery, not a domain retry policy or a retry of every provider exception.
42
+
43
+ Successful results and raw attempts are written under `current/logs/agents/`; Pi session files live under `current/sessions/`. A schema-valid response establishes shape, not factual support, successful external effects, or task completion.
44
+
45
+ | Decision | GOOD | BAD |
46
+ |---|---|---|
47
+ | IF later work needs independent judgment, THEN create a fresh session and pass only its input/evidence contract. ELSE retain a session for conversation-dependent follow-up. | Analysis receives saved source and draft, not the author's conversation. | Call an author again and describe its self-review as independent. |
48
+ | IF a Norn agent claims a verifiable result, THEN verify the evidence before accepting it. ELSE preserve the uncertainty in the result. | Check quotations against source bytes and command outcomes against logs. | Treat a schema-valid `passed: true` as proof that tests ran. |
49
+ | IF a result must survive a workflow transition, THEN save its content/ref using [persistence](persistence.md). ELSE keep it local to the active step. | Save a draft artifact, then pass its ref to analysis. | Expect the next workflow to recover a local variable or an undisposed session object. |
50
+
51
+ ## Prompts, tools, and resource loading
52
+
53
+ The default tool allowlist is `read`, `bash`, `edit`, `write`, plus the response tool. An explicit `tools: []` requests no built-in task tools, but still includes the response tool and any explicitly attached [resource-adapter tools](resources.md#explicit-agent-attachment). `resourceAdapters` is accepted by both session creation and one-shot prompting; omitting it attaches no workflow state.
54
+
55
+ Each session constructs Pi runtime services at its `cwd`, using the engine's explicit `agentDir`, then `NORN_AGENT_DIR`, then `~/.norn/agent`. An inherited `PI_CODING_AGENT_DIR` does not select the Norn agent's global configuration. Installed provider extensions register before default-model selection. Model selection uses the session's explicit `model`, then the engine's model, then Pi's model configuration. `thinkingLevel` similarly falls through from session to engine to Pi configuration. Discoverable settings, skills, context files, and extensions can therefore affect it. It does **not** inherit the outer conversation or its in-memory tool registrations. Loaded extensions may change active tools; the requested tool list alone is not an adversarial restriction.
56
+
57
+ `systemPrompt` replaces the base prompt; `appendSystemPrompt` adds to resource-loader append content. Pi's default self-documentation block is absent with a custom base prompt. Context files and applicable skill advertisements can still be appended by Pi. Norn currently does not automatically inject a Norn authoring bootstrap.
58
+
59
+ | Decision | GOOD | BAD |
60
+ |---|---|---|
61
+ | IF a custom-prompt Norn agent must author capabilities, THEN deliberately supply the matching documentation locations and authoring scope. ELSE keep authoring material out of a source-only assessor's supplied prompt. | Author gets installed Norn references; assessor gets source and result. | Inject the entire parent task and authoring manual into every agent. |
62
+ | IF strict evidence/tool isolation is required, THEN control the Pi resource environment and inspect the effective session, using an OS boundary for filesystem restrictions. ELSE describe this as conversation separation only. | Verify loaded context and active tools in a controlled agent environment. | Call `tools: []` plus a fresh session a filesystem sandbox. |
63
+
64
+ Sources: [session API](../packages/sdk/src/api.ts), [agent runner](../packages/cli/src/internal/agents.ts), [response tool](../packages/cli/src/internal/agent-response-tool.ts). Filesystem semantics: [workspaces](persistence.md#filesystem-boundaries).
@@ -0,0 +1,183 @@
1
+ # CLI and client
2
+
3
+ ## Select the runtime
4
+
5
+ [Install Norn](../README.md#installation), then inspect the executable you will actually invoke:
6
+
7
+ ```bash
8
+ command -v norn
9
+ norn version
10
+ norn help
11
+ ```
12
+
13
+ For a source checkout, run `pnpm install --frozen-lockfile` and `pnpm build` first. A shell function keeps all examples bound to that checkout rather than another `PATH` installation:
14
+
15
+ ```bash
16
+ NORN_ROOT=/absolute/path/to/norn
17
+ norn() { node "$NORN_ROOT/packages/cli/bin/norn.mjs" "$@"; }
18
+ norn version
19
+ ```
20
+
21
+ Use Node satisfying the package's engine requirement (currently `>=22.19.0`). `NORN_ROOT` here is an example shell variable, not a runtime configuration option. Use `norn docs inspect` to locate this installation's documentation and examples;
22
+ [local documentation assets](#local-documentation-assets) covers binary extraction.
23
+ Source builds may not carry release revision metadata. Rebuild after changing source or documentation.
24
+
25
+ Registry installations update through the package manager in their existing scope:
26
+ `npm install -g @vimhead.dev/norn-cli@tip` for a global npm installation, or the
27
+ corresponding local install command. `norn upgrade` does not guess that scope.
28
+ Standalone binaries retain their checksum-verified `norn upgrade` command.
29
+
30
+ Copied examples already contain a project file, so they skip initialization. npm
31
+ omits `.gitignore` from the package; add `.norn/runs/` to the copy's `.gitignore`
32
+ before committing example work. Source-checkout examples include that exclusion.
33
+
34
+ ## Local documentation assets
35
+
36
+ ```bash
37
+ norn docs inspect
38
+ ```
39
+
40
+ This explicit command works outside a Norn project and does not use the network.
41
+ Its `documentation` result contains `storage`, `version`, `commit`, `assetDigest`,
42
+ and absolute `paths` (`root`, `readme`, `index`, `docs`, `examples`).
43
+
44
+ npm/source installations resolve their built `assets/` tree directly from the CLI
45
+ package, not the current directory or another executable on PATH. A version mismatch
46
+ fails rather than advertising another build's documentation. Compiled binaries embed the docs,
47
+ examples, and source references, preserving relative links. The first
48
+ inspection publishes a complete extracted tree into a build/content-specific
49
+ cache; later calls verify and reuse it without rewriting files. Different asset
50
+ contents or build commits use separate entries. `version` and help do not extract
51
+ anything. No prompt augmentation or agent-context delivery is performed.
52
+
53
+ Cache roots:
54
+
55
+ - macOS: `~/Library/Caches/norn/docs/`
56
+ - Linux: `$XDG_CACHE_HOME/norn/docs/`, or `~/.cache/norn/docs/`
57
+ - Windows: `%LOCALAPPDATA%/norn/docs/`, or `~/AppData/Local/norn/docs/`
58
+ - Explicit override: `NORN_DOCS_CACHE_DIR`
59
+
60
+ Extraction uses staging directories and atomic publication. Existing cache entries
61
+ are checked for exact file bytes, missing/extra files, and symlinks. Corrupt entries
62
+ are not silently overwritten; the error names the entry to remove before retrying.
63
+ This is accidental-corruption detection, not a sandbox against another process
64
+ with access to the same user's cache. Old build entries are not automatically
65
+ removed. The extracted tree is a documentation snapshot, not a separate runtime
66
+ installation.
67
+
68
+ | Decision | GOOD | BAD |
69
+ |---|---|---|
70
+ | IF an example will be edited or run, THEN copy it into the task workspace first. ELSE read the cached asset in place. | Copy `paths.examples/minimal-workflow` before starting a run. | Modify the verified cache or put `.norn/` state inside it. |
71
+ | IF inspection reports a modified/incomplete cache, THEN preserve any wanted edits elsewhere, remove only the named cache entry, and retry. ELSE reuse the returned paths. | Remove the reported `v1-...` directory after preserving work. | Delete every build's cache or accept modified docs as matching the binary. |
72
+
73
+ The same resolver is available from [`@vimhead.dev/norn-cli/documentation`](../packages/cli/src/documentation.ts),
74
+ with explicit source, build metadata, and cache-root inputs.
75
+
76
+ ## Documentation introduction
77
+
78
+ ```bash
79
+ norn docs intro
80
+ ```
81
+
82
+ Returns `{ "intro": "..." }`: a compact authoring introduction with runtime
83
+ version/commit, invocation, and pointers to the documentation index and examples.
84
+ Topic routing remains in the index; the command does not copy manuals or enumerate
85
+ workflows. It uses the same asset resolver/cache as `docs inspect`
86
+ and works without a valid project.
87
+
88
+ The invocation is a JSON argument array, not a shell command string. Its first
89
+ entry is the executable; remaining entries precede CLI arguments. Source/npm
90
+ invocations include the Node executable and this installation's `bin/norn.mjs`;
91
+ compiled invocations contain the binary path. Spaces and quotes remain part of
92
+ each argument, without relying on another `norn` installation on PATH.
93
+
94
+ `renderNornDocumentationIntro({ documentation, invocation })`, also exported from
95
+ [`@vimhead.dev/norn-cli/documentation`](../packages/cli/src/documentation.ts), renders the same text from explicit
96
+ inputs without filesystem or process access. Generating the introduction does not
97
+ inject it into prompts or alter Norn agent sessions.
98
+
99
+ ## Discover live contracts
100
+
101
+ ```bash
102
+ norn project inspect
103
+ norn workflows list
104
+ norn workflows list --all
105
+ norn workflows inspect <workflow-id>
106
+ norn commands list
107
+ norn commands inspect runs.start
108
+ norn help runs start
109
+ ```
110
+
111
+ Default workflow listing shows entrypoints; `--all` includes internal steps. Workflow inspection returns instructions, params JSON Schema, isolation, gate metadata and plugin source locations. [Loading diagnostics](projects.md#diagnose-registration) are part of the discovery envelope.
112
+
113
+ Help is text; ordinary results are JSON. `runs logs` emits JSONL events.
114
+ `norn pi [arguments...]` is a passthrough to bundled Pi, preserving Pi's native
115
+ output and exit status rather than wrapping them in Norn JSON. Use `norn pi --help`
116
+ for Pi's options and [provider setup](../setup/providers.md) for operator instructions.
117
+ Commands and schemas from the invoked executable are authoritative when a checkout and installation differ.
118
+
119
+ ## Start, wait, inspect
120
+
121
+ From inside the target project:
122
+
123
+ ```bash
124
+ printf '%s\n' '{"params":{"name":"Ada"}}' | norn runs start greeting.write
125
+ norn runs wait <run>
126
+ norn runs inspect <run>
127
+ norn runs metrics <run>
128
+ ```
129
+
130
+ Start returns `{ "run": ... }` with `id`, `name`, and `path`, after launching a detached executor. This is acceptance of the launch, not success of the task. `runs wait` returns when the run is no longer running or inspection reports it unhealthy. Its successful process exit does not mean the workflow completed; callers check `run.status`, `run.health`, and outcome/failure information.
131
+
132
+ A completed capability's outputs are in `run.outcome.metadata`. Artifact refs resolve beneath `<run.path>/current/artifacts/`. The [minimal example](../examples/minimal-workflow/README.md) gives concrete output expectations.
133
+
134
+ Start stdin accepts `params` and optional `config`, with config overrides keyed by plugin ID. Params are JSON, not CLI flags or TOON. For display, a JSON viewer can format a finite result; keep machine artifacts and JSONL events in their native format.
135
+
136
+ | Decision | GOOD | BAD |
137
+ |---|---|---|
138
+ | IF start returns a run ID, THEN retain it and inspect the terminal outcome. ELSE handle the launch error. | Wait, then verify `status === "completed"` and expected artifact content. | Report task success from `runs start` alone. |
139
+ | IF a new capability is written or registered, THEN query the current catalogue and schema. ELSE use the inspected contract. | `workflows inspect greeting.write` after editing. | Rely on a cached session-start list that cannot contain the new workflow. |
140
+
141
+ For live monitoring and explicit lifecycle control:
142
+
143
+ ```bash
144
+ norn runs list
145
+ norn runs logs <run>
146
+ norn runs logs <run> --follow
147
+ norn runs stop <run>
148
+ norn runs kill <run>
149
+ norn runs delete <run>
150
+ ```
151
+
152
+ `stop` signals SIGTERM; `kill` signals SIGKILL. Delete removes an inactive run and its evidence. Neither stopping nor deleting undoes external effects. Resume and rollback are documented in [recovery](recovery.md).
153
+
154
+ ## JavaScript client and other harnesses
155
+
156
+ Claude Code, Pi, Codex, and other CLI-capable harnesses can invoke Norn without an
157
+ adapter. Workflows provide portable task delegation and workflow logic, not
158
+ compatibility with a host's plugin format or UI extension APIs. The caller does
159
+ not need Pi installed: [Norn agents](agents.md) use Norn's bundled Pi runtime.
160
+
161
+ The JavaScript client invokes the runtime; the [Norn SDK](workflows.md) defines
162
+ workflows. For example, start and inspect a run through `@vimhead.dev/norn-cli/client`:
163
+
164
+ ```ts
165
+ import { createNornClient } from "@vimhead.dev/norn-cli/client";
166
+
167
+ const client = createNornClient({ spawnCwd: "/absolute/path/to/project" });
168
+ const started = await client.runs.start({
169
+ workflowId: "greeting.write",
170
+ params: { name: "Ada" },
171
+ });
172
+ const finished = await client.runs.wait(started.id);
173
+ if (finished.status !== "completed" || finished.health !== "healthy") {
174
+ throw new Error(`Run ${finished.id}: ${finished.status} (${finished.health})`);
175
+ }
176
+ console.log(finished.outcome?.metadata);
177
+ ```
178
+
179
+ The client defaults to its own package's `bin/norn.mjs`. Its optional `executablePath` is a script launched through `process.execPath`, not an arbitrary standalone binary or shell command. Other languages can invoke the CLI directly with cwd, JSON stdin, and parsed stdout.
180
+
181
+ `workflows.list()` and `inspect()` use fresh CLI discovery. `workflows.entries()` and `client.state` use a cached in-process project load; that state is registration memory, not a chosen run's persisted state. A new client is needed to refresh that in-process catalogue after source edits.
182
+
183
+ Sources: [CLI declarations and handlers](../packages/cli/src/cli.ts), [client API](../packages/cli/src/client.ts).
@@ -0,0 +1,76 @@
1
+ # Composition and reuse
2
+
3
+ ## Transfer, not a returning call
4
+
5
+ ```ts
6
+ return run.next(manifest.workflows.analyze, { draftArtifact });
7
+ ```
8
+
9
+ `run.next` constructs a control result. Returning it lets the scheduler persist the transition and execute the target in the **same run**, with that target's isolation mode. It does not suspend the caller and later return a value. Awaiting `run.next` cannot turn it into a subroutine.
10
+
11
+ The caller and target share run state and artifacts, not local variables or agent conversations. All targets must be registered in the loaded project. Params are validated at the target; a returned `complete` completes the entire run.
12
+
13
+ ## Caller-selected continuation
14
+
15
+ A reusable capability can accept a continuation whose schema describes the values it contributes. The caller owns the remaining params:
16
+
17
+ ```ts
18
+ import { artifactRefSchema, workflowRefSchema } from "@vimhead.dev/norn";
19
+ import { z } from "zod";
20
+
21
+ const paramsSchema = z.object({
22
+ task: z.string(),
23
+ next: workflowRefSchema({
24
+ params: z.object({
25
+ resultArtifact: artifactRefSchema,
26
+ summary: z.string(),
27
+ }),
28
+ }).nullable(),
29
+ });
30
+ ```
31
+
32
+ After producing `resultArtifact` and `summary`, the reusable implementation returns:
33
+
34
+ ```ts
35
+ return params.next
36
+ ? run.next(params.next.workflow, {
37
+ ...params.next.forwardParams,
38
+ resultArtifact,
39
+ summary,
40
+ })
41
+ : run.complete({ summary, artifacts: { result: resultArtifact } });
42
+ ```
43
+
44
+ A caller supplies a registered target and its own context:
45
+
46
+ ```json
47
+ {
48
+ "params": {
49
+ "task": "Assess this import",
50
+ "next": {
51
+ "workflow": "importer.deliver",
52
+ "forwardParams": { "batchId": "batch-17" }
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ `importer.deliver` must accept `batchId`, `resultArtifact`, and `summary`. Code can supply a workflow declaration instead of the ID string. A bare ID or `{ id }` reference normalizes to empty `forwardParams`.
59
+
60
+ `workflows inspect` exposes `x-norn-workflow-ref.contributedParamsSchema` at the reference's JSON Schema node. This is the producer's contribution contract, not extra fields required in the caller's reference payload. It does not automatically merge params, verify the target exists, or prove the target accepts the combination.
61
+
62
+ | Decision | GOOD | BAD |
63
+ |---|---|---|
64
+ | IF a caller selects the next step, THEN forward its opaque params and add the declared contribution explicitly. ELSE transition to a known declaration with explicit params. | Spread `forwardParams`, then add the producer-owned result fields. | Hardcode a task-specific next workflow into a supposedly reusable producer. |
65
+ | IF resuming the caller requires additional work, THEN represent that work as the supplied continuation. ELSE let the producer complete. | `assess → caller.deliver`. | Expect execution to return to the line following `run.next`. |
66
+ | IF a target schema changes, THEN inspect and exercise the combined params contract. ELSE preserve its existing input contract. | Verify the target accepts both batch context and result ref. | Treat the contributed schema annotation as automatic end-to-end compatibility checking. |
67
+
68
+ The [worktree development loop](../examples/worktree-development-loop/README.md) is a larger continuation-based example, not a required planner/reviewer architecture.
69
+
70
+ ## Another project or harness
71
+
72
+ Reuse source by explicitly registering it, directly or through [included config](projects.md). There is no required package layout. Plugin IDs must remain unique within a project; run state and artifacts belong to the invoking project/run, not the plugin source directory.
73
+
74
+ An external shell, Python program, or agent harness can call the [CLI](cli.md) from the target project directory. The JavaScript client offers the same lifecycle without inventing another orchestration layer. Separate CLI starts create separate runs; connecting their artifact content is a caller responsibility, unlike same-run continuation refs.
75
+
76
+ Sources: [reference schemas and controls](../packages/sdk/src/api.ts), [scheduler](../packages/cli/src/internal/engine.ts), [reference contract tests](../tests/workflow-ref.test.ts).
@@ -0,0 +1,56 @@
1
+ # State, artifacts, and workspaces
2
+
3
+ ## Choose what survives
4
+
5
+ | Value | Lifetime and access |
6
+ |---|---|
7
+ | Local variables / plugin factory memory | Current executor only; not a resume contract. Factory context state is in-memory registration state. |
8
+ | `run.state` | Per-run, schema-validated JSON shared across steps. `get` requires a value; `getOptional` permits absence; `set` persists it. |
9
+ | `run.artifacts` | Text files addressed by `{ path }` relative to this run's artifacts directory. Write content, pass the ref, read and validate at the consumer. |
10
+ | Outcome metadata | Caller-facing summary, artifact/log refs and small data, exposed by run inspection. |
11
+ | Workflow params | Explicit input to the current/next step, persisted for recovery. |
12
+
13
+ Workflow state is the automatically initialized built-in [run resource](resources.md). State declarations live in the manifest. The [agent example](../examples/agent-then-analysis/plugin.ts) saves the draft ref in run state and also passes it explicitly to analysis. The state value is a retained run record; the params are the consumer's input contract.
14
+
15
+ Artifact refs are paths, not content hashes, and a write to the same path replaces its content. State writes are serialized and atomic; an artifact write plus a state update is not a single transaction. An artifact read returns text, so a JSON consumer still needs parsing and schema validation.
16
+
17
+ | Decision | GOOD | BAD |
18
+ |---|---|---|
19
+ | IF earlier work must survive retry of a later step, THEN persist it before a transition and recover from that boundary. ELSE expect the active step to be repeated. | Save assessments, transition to delivery, retry delivery. | Keep assessments in a closure and restart the entire coordinator. |
20
+ | IF evidence must remain distinguishable across attempts, THEN use distinct artifact paths or retain the relevant checkpoint. ELSE document intentional replacement. | `attempt-2/analysis.json`. | Overwrite `analysis.json` while promising both revisions remain in the current files. |
21
+ | IF a ref crosses into another run or project, THEN transfer its content and establish a destination-owned ref. ELSE use the ref within its original run. | Read and copy the source run's artifact before invoking a separate consumer run. | Pass `{ "path": "draft.json" }` to an unrelated run and expect global resolution. |
22
+
23
+ ## Filesystem boundaries
24
+
25
+ Each run is stored under `<project>/.norn/runs/<id>/`:
26
+
27
+ ```text
28
+ current/
29
+ workspace/ working files
30
+ artifacts/ capability evidence and results
31
+ resources/ resource definitions and data
32
+ state.json workflow state values
33
+ run-state.json scheduler state
34
+ manifest.json recorded events
35
+ logs/ command and agent output
36
+ sessions/ Pi conversations
37
+ checkpoints.json
38
+ locks/ transient resource/file coordination; not snapshotted
39
+ store/ snapshot manifests and content-addressed objects
40
+ ```
41
+
42
+ | Workflow isolation | Default `run.cwd` / `run.path(...)` | Additional access |
43
+ |---|---|---|
44
+ | `runWorkspace` (default) | `current/workspace/` | An initially empty directory, not a checkout or copy of the project. |
45
+ | `project` | Project root | Typed `run.projectRoot` and `run.projectPath(...)`. |
46
+
47
+ `run.workspace` remains the per-run workspace in both modes. Command/agent cwd selection and path helpers reject lexical escapes from the selected root. These checks do not sandbox Node code, shell commands, tool file arguments, symlinks, network access, or loaded extensions.
48
+
49
+ | Decision | GOOD | BAD |
50
+ |---|---|---|
51
+ | IF work needs existing project files, THEN declare project isolation or explicitly prepare a copy/worktree inside the run workspace. ELSE use the empty per-run workspace. | A project-mode verifier checks the actual project; an editing workflow prepares its own worktree. | Run `npm test` in an empty workspace and assume the repository is present. |
52
+ | IF rollback must undo a change, THEN keep it in snapshotted run files or separately manage the external effect. ELSE do not promise rollback of that change. | Reconcile a project-root edit or remote delivery explicitly. | Assume snapshots restore project plugin source, remote APIs, or symlink targets. |
53
+
54
+ Snapshots cover `current/`, preserve symlinks as links rather than copying targets, and do not include project-root source. [Recovery](recovery.md) defines when snapshots are taken and how to select a retry boundary.
55
+
56
+ Sources: [state store](../packages/cli/src/internal/state-store.ts), [artifacts](../packages/cli/src/internal/artifacts.ts), [run paths](../packages/cli/src/internal/run.ts), [snapshot store](../packages/cli/src/internal/run-store.ts).
@@ -0,0 +1,75 @@
1
+ # Projects and loading
2
+
3
+ ## Create and register
4
+
5
+ ```bash
6
+ norn project init
7
+ ```
8
+
9
+ Initialization creates `norn.project.json`, `.norn/runs/`, and a run-state exclusion in `.gitignore`. Project discovery walks upward from the invocation directory to the nearest `norn.project.json`.
10
+
11
+ A plugin can be a single file anywhere explicitly registered by the project:
12
+
13
+ ```json
14
+ {
15
+ "version": 1,
16
+ "plugins": ["./workflows/plugin.ts"],
17
+ "config": {
18
+ "example": { "repositoryRoot": "." }
19
+ }
20
+ }
21
+ ```
22
+
23
+ `config` is keyed by plugin ID and validated against that plugin's manifest schema. Omit the entry for a plugin with no config schema. [The minimal example](../examples/minimal-workflow/README.md) needs only its project file and plugin.
24
+
25
+ Reusable config files, conventionally `norn.json`, can declare `plugins`, `includes`, and `config`. The project includes them explicitly:
26
+
27
+ ```json
28
+ {
29
+ "version": 1,
30
+ "plugins": ["./local-plugin.ts"],
31
+ "includes": ["./packages/*/norn.json"]
32
+ }
33
+ ```
34
+
35
+ Plugin and include paths resolve relative to the file declaring them. `*` matches one directory segment. There is no automatic plugin tree scan, nor automatic inclusion of a sibling `norn.json`. Project config overrides included values; conflicting reusable values and duplicate plugin IDs are rejected. `version` and `seerMode` belong only in the project file.
36
+
37
+ Projects using Seer can additionally declare writable project-relative roots:
38
+
39
+ ```json
40
+ "seerMode": { "writableRoots": ["./workflow-sources"] }
41
+ ```
42
+
43
+ This is a project-file field, not an OS sandbox. The current helper contract is in
44
+ [Seer exports](../packages/sdk/src/seer/index.ts) and [config resolution](../packages/sdk/src/seer/config.ts).
45
+
46
+ ## Import and reload
47
+
48
+ Each registered module default-exports `definePlugin(manifest, implementation)`. Norn loads TypeScript through jiti without a local build, supplying runtime imports for `@vimhead.dev/norn`, its `/files`, `/schema`, and `/seer` subpaths, `zod`, and `typebox`. Other dependencies need normal package resolution from the plugin's location.
49
+
50
+ Runtime virtual imports do not configure TypeScript or an editor. A matching `@vimhead.dev/norn` installation provides the SDK types; the source checkout's examples are checked by its `tsconfig.json`. A successful runtime import alone is not a type check.
51
+
52
+ New CLI discovery/start/resume invocations load current source; an already executing workflow retains its loaded implementation. Module evaluation and implementation factories run even during discovery. Factory context state is in-memory registration state, **not** durable run state; see [persistence](persistence.md).
53
+
54
+ | Decision | GOOD | BAD |
55
+ |---|---|---|
56
+ | IF source changes, THEN inspect it through a new invocation before starting or resuming. ELSE use the inspected declaration. | Edit `plugin.ts`, run `workflows inspect`, then resume. | Assume a running Norn agent or executor hot-reloads the edit. |
57
+ | IF importing a plugin can mutate files or start work, THEN move those effects into workflow execution. ELSE keep import-time declarations and factory construction. | `execute` launches the command. | `workflows list` unexpectedly starts a delivery from top-level module code. |
58
+
59
+ ## Diagnose registration
60
+
61
+ ```bash
62
+ norn project inspect
63
+ norn workflows list --all
64
+ norn workflows inspect example.plan
65
+ ```
66
+
67
+ Discovery returns `isComplete` and `diagnostics`. Each diagnostic includes source paths, stage, message, and schema issues when available. A broken plugin is excluded as a whole; duplicate plugin IDs exclude all conflicting sources. `import` covers module evaluation as well as syntax/import errors.
68
+
69
+ Discovery can exit successfully with an incomplete catalogue. Start, resume, and executable client entries require the entire project to load; otherwise they report `NORN_PROJECT_INVALID`. Malformed project/include configuration remains fatal rather than producing a partial catalogue.
70
+
71
+ | Decision | GOOD | BAD |
72
+ |---|---|---|
73
+ | IF `isComplete` is false, THEN repair or explicitly remove the reported invalid registration and inspect again. ELSE select from the loaded contracts. | Fix the named config field or missing default export. | Treat a listed valid sibling as permission to launch an invalid project. |
74
+
75
+ Sources: [loader](../packages/cli/src/plugin-loader.ts), [registry](../packages/cli/src/internal/workflow-registry.ts). Next: [write a workflow](workflows.md), [reuse across projects](composition.md).