@jimhoyd/urlcode 0.4.1 → 0.4.6

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 (212) hide show
  1. package/.claude/skills/urlcode-authoring/SKILL.md +60 -7
  2. package/.claude/skills/urlcode-operations/SKILL.md +4 -0
  3. package/README.md +19 -15
  4. package/SECURITY.md +5 -3
  5. package/dist/BUILD-MANIFEST.json +31 -28
  6. package/dist/agent-context.js +82 -0
  7. package/dist/agents-guide.js +42 -42
  8. package/dist/authoring.js +12 -2
  9. package/dist/body-schema.js +159 -0
  10. package/dist/build-cloudflare.js +2 -0
  11. package/dist/capabilities.js +1 -1
  12. package/dist/cli.js +29 -12
  13. package/dist/config.js +74 -6
  14. package/dist/context.js +4 -6
  15. package/dist/errors.js +3 -1
  16. package/dist/examples.js +1 -1
  17. package/dist/extensions.js +138 -3
  18. package/dist/http-policy.js +19 -4
  19. package/dist/http-response.js +2 -2
  20. package/dist/init-with.js +71 -9
  21. package/dist/mcp.js +15 -2
  22. package/dist/pattern-guard.js +32 -0
  23. package/dist/policies/security.js +0 -0
  24. package/dist/policy.js +16 -0
  25. package/dist/project-tests.js +35 -11
  26. package/dist/readiness.js +188 -32
  27. package/dist/recipes.js +1 -1
  28. package/dist/router.js +17 -0
  29. package/dist/runtime.js +26 -3
  30. package/dist/scaffold.js +0 -0
  31. package/dist/server.js +26 -3
  32. package/dist/site.js +0 -0
  33. package/dist/tooling.js +3 -1
  34. package/dist/types/agent-context.d.ts +44 -0
  35. package/dist/types/authoring.d.ts +3 -1
  36. package/dist/types/body-schema.d.ts +58 -0
  37. package/dist/types/config.d.ts +10 -2
  38. package/dist/types/context.d.ts +1 -1
  39. package/dist/types/errors.d.ts +9 -1
  40. package/dist/types/examples.d.ts +1 -1
  41. package/dist/types/extensions.d.ts +105 -2
  42. package/dist/types/http-policy.d.ts +3 -0
  43. package/dist/types/init-with.d.ts +10 -1
  44. package/dist/types/pattern-guard.d.ts +10 -0
  45. package/dist/types/project-tests.d.ts +9 -0
  46. package/dist/types/readiness.d.ts +71 -0
  47. package/dist/types/recipes.d.ts +1 -1
  48. package/dist/types/runtime.d.ts +4 -0
  49. package/dist/types/server.d.ts +9 -1
  50. package/dist/types/tooling.d.ts +2 -0
  51. package/dist/types/types.d.ts +13 -0
  52. package/dist/types.js +10 -2
  53. package/dist/typescript-authoring.js +5 -3
  54. package/dist/verify-deployment.js +16 -10
  55. package/examples/body-validation/README.md +16 -0
  56. package/examples/body-validation/example.yaml +17 -0
  57. package/examples/body-validation/tests/requests.json +15 -0
  58. package/examples/body-validation/urlcode.yaml +34 -0
  59. package/examples/coverage-waiver/README.md +8 -0
  60. package/examples/coverage-waiver/example.yaml +16 -0
  61. package/examples/coverage-waiver/functions/notes.mjs +2 -0
  62. package/examples/coverage-waiver/tests/requests.json +3 -0
  63. package/examples/coverage-waiver/urlcode.yaml +10 -0
  64. package/examples/data-dir/README.md +39 -0
  65. package/examples/data-dir/data/welcome.txt +1 -0
  66. package/examples/data-dir/example.yaml +22 -0
  67. package/examples/data-dir/functions/note.mjs +18 -0
  68. package/examples/data-dir/tests/requests.json +6 -0
  69. package/examples/data-dir/urlcode.yaml +6 -0
  70. package/examples/lifecycle/README.md +15 -0
  71. package/examples/lifecycle/example.yaml +19 -0
  72. package/examples/lifecycle/functions/notes.mjs +29 -0
  73. package/examples/lifecycle/tests/requests.json +12 -0
  74. package/examples/lifecycle/urlcode.yaml +29 -0
  75. package/examples/not-found/README.md +10 -0
  76. package/examples/not-found/example.yaml +17 -0
  77. package/examples/not-found/public/404.html +3 -0
  78. package/examples/not-found/public/index.html +3 -0
  79. package/examples/not-found/tests/requests.json +7 -0
  80. package/examples/not-found/urlcode.yaml +7 -0
  81. package/examples/shared-blocks/README.md +11 -0
  82. package/examples/shared-blocks/example.yaml +17 -0
  83. package/examples/shared-blocks/tests/requests.json +7 -0
  84. package/examples/shared-blocks/urlcode.yaml +37 -0
  85. package/llms-full.txt +436 -149
  86. package/llms.txt +44 -6
  87. package/package.json +15 -22
  88. package/recipes/static-page/README.md +9 -0
  89. package/recipes/static-page/public/index.html +11 -0
  90. package/recipes/static-page/recipe.yaml +21 -0
  91. package/recipes/static-page/tests/requests.json +22 -0
  92. package/recipes/static-page/urlcode.yaml +7 -0
  93. package/recipes/static-plus-api/README.md +6 -0
  94. package/recipes/static-plus-api/urlcode.yaml +4 -0
  95. package/recipes/store-crud/README.md +53 -0
  96. package/recipes/store-crud/recipe.yaml +31 -0
  97. package/recipes/store-crud/tests/requests.json +18 -0
  98. package/recipes/store-crud/urlcode.yaml +18 -0
  99. package/schemas/urlcode.schema.json +125 -60
  100. package/skills/urlcode/SKILL.md +53 -26
  101. package/starters/default/AGENTS.md +43 -43
  102. package/starters/page/README.md +14 -0
  103. package/starters/page/public/index.html +12 -0
  104. package/starters/page/tests/requests.json +17 -0
  105. package/starters/page/urlcode.yaml +6 -0
  106. package/.claude-plugin/marketplace.json +0 -18
  107. package/CONTRIBUTING.md +0 -112
  108. package/ROADMAP.md +0 -66
  109. package/docs/AI-AUTHORING.md +0 -338
  110. package/docs/ASSETS.md +0 -107
  111. package/docs/AUTH-BACKUP.md +0 -32
  112. package/docs/AWS.md +0 -86
  113. package/docs/BEST-PRACTICES.md +0 -276
  114. package/docs/BULK.md +0 -79
  115. package/docs/CAPABILITIES.md +0 -192
  116. package/docs/CAPACITY.md +0 -305
  117. package/docs/CI-FOLLOWUP-2026-09-19.md +0 -97
  118. package/docs/CI-RELEASE-AUDIT-2026-09-19.md +0 -322
  119. package/docs/CI.md +0 -147
  120. package/docs/CLOUDFLARE.md +0 -109
  121. package/docs/CODEBASE-AUDIT-2026-09-20.md +0 -284
  122. package/docs/COMPLIANCE.md +0 -239
  123. package/docs/COMPOSING-A-SITE.md +0 -278
  124. package/docs/CONDITIONS.md +0 -74
  125. package/docs/DEPLOYMENT-CHECKS.md +0 -108
  126. package/docs/DEVELOPMENT-PIPELINE.md +0 -270
  127. package/docs/EGRESS.md +0 -125
  128. package/docs/EXTENSIONS.md +0 -438
  129. package/docs/FRAMEWORK.md +0 -217
  130. package/docs/FUNCTION-SECURITY.md +0 -254
  131. package/docs/HTTP.md +0 -129
  132. package/docs/INSTALL.md +0 -128
  133. package/docs/INTERCHANGE.md +0 -134
  134. package/docs/LOAD-TESTING.md +0 -91
  135. package/docs/LOCAL-DEVELOPMENT.md +0 -102
  136. package/docs/MIDDLEWARE-EXAMPLES.md +0 -75
  137. package/docs/MIDDLEWARE.md +0 -102
  138. package/docs/MONITORING.md +0 -115
  139. package/docs/OBSERVABILITY.md +0 -222
  140. package/docs/OPEN-DECISIONS.md +0 -224
  141. package/docs/OPERATIONAL-PROOF.md +0 -41
  142. package/docs/OPERATIONS.md +0 -201
  143. package/docs/ORGANIZATION.md +0 -135
  144. package/docs/PERFORMANCE.md +0 -72
  145. package/docs/PLUGINS.md +0 -271
  146. package/docs/POLICIES.md +0 -211
  147. package/docs/PRERENDER.md +0 -245
  148. package/docs/PROJECT-DIRECTION.md +0 -118
  149. package/docs/PROVIDER-VERIFICATION.md +0 -84
  150. package/docs/READINESS.md +0 -150
  151. package/docs/README.md +0 -87
  152. package/docs/RECIPES.md +0 -99
  153. package/docs/RELEASE-0.4.0-alpha.3.md +0 -50
  154. package/docs/RELEASE-0.4.1.md +0 -73
  155. package/docs/RELEASE-READINESS.md +0 -117
  156. package/docs/RELEASE-SECURITY.md +0 -96
  157. package/docs/RESILIENCE.md +0 -161
  158. package/docs/ROUTING.md +0 -92
  159. package/docs/SANDBOX-REVIEW.md +0 -72
  160. package/docs/SCAFFOLDING.md +0 -70
  161. package/docs/SECURITY-AUDIT.md +0 -164
  162. package/docs/SITE.md +0 -150
  163. package/docs/SPECIFICATION.md +0 -359
  164. package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +0 -288
  165. package/docs/SPIKE-BUSINESS-SUITE.md +0 -1029
  166. package/docs/SPIKE-CORE-LAYERING.md +0 -368
  167. package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +0 -211
  168. package/docs/STANDARDS.md +0 -311
  169. package/docs/STARTERS.md +0 -83
  170. package/docs/STATIC.md +0 -105
  171. package/docs/TOOLING.md +0 -298
  172. package/docs/TUNNELS.md +0 -72
  173. package/docs/TYPESCRIPT-AUTHORING.md +0 -87
  174. package/docs/TYPESCRIPT.md +0 -123
  175. package/docs/VERCEL.md +0 -114
  176. package/docs/VERSION-ALIGNMENT.md +0 -80
  177. package/docs/YAML-GUIDE.md +0 -57
  178. package/docs/YAML-REFERENCE.md +0 -449
  179. package/docs/archive/2026-09-19/EXTENSION-IMPLEMENTATION.md +0 -68
  180. package/docs/archive/2026-09-19/MANAGEMENT-SECURITY.md +0 -102
  181. package/docs/archive/2026-09-19/NEXT-PHASE-PLAN.md +0 -108
  182. package/docs/archive/2026-09-19/NEXT-STEPS.md +0 -646
  183. package/docs/archive/2026-09-19/OPEN-DECISIONS.md +0 -277
  184. package/docs/archive/2026-09-19/RELEASE-SECURITY.md +0 -186
  185. package/docs/archive/2026-09-19/ROADMAP.md +0 -387
  186. package/docs/archive/2026-09-19/SPIKE-EXTENSION-MODEL.md +0 -430
  187. package/docs/archive/2026-09-19/SPIKE-EXTENSIONS.md +0 -492
  188. package/docs/archive/2026-09-19/SPIKE-LAMBDA-COMPILE.md +0 -365
  189. package/docs/archive/2026-09-19/SPIKE-MONOREPO.md +0 -778
  190. package/docs/archive/2026-09-19/USABILITY-REVIEW.md +0 -139
  191. package/docs/archive/README.md +0 -28
  192. package/docs/policies/agents.md +0 -182
  193. package/docs/policies/cache.md +0 -152
  194. package/docs/policies/compression.md +0 -169
  195. package/docs/policies/contract.md +0 -52
  196. package/docs/policies/hardened.md +0 -56
  197. package/docs/policies/interoperability.md +0 -169
  198. package/docs/policies/operations.md +0 -45
  199. package/docs/policies/security.md +0 -161
  200. package/docs/policies/throttle.md +0 -103
  201. package/docs/yaml/assets.md +0 -36
  202. package/docs/yaml/conditions.md +0 -20
  203. package/docs/yaml/functions.md +0 -168
  204. package/docs/yaml/middleware.md +0 -31
  205. package/docs/yaml/organization.md +0 -74
  206. package/docs/yaml/policies.md +0 -37
  207. package/docs/yaml/redirects.md +0 -64
  208. package/docs/yaml/responses.md +0 -57
  209. package/docs/yaml/site.md +0 -24
  210. package/packaging/claude-plugin/.claude-plugin/plugin.json +0 -19
  211. package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +0 -120
  212. package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +0 -108
@@ -18,7 +18,9 @@ is to author only what the pinned revision implements and then prove it.
18
18
  Check the installed version's primitives, YAML configuration, policies, supported
19
19
  extensions and recipes/templates before writing a custom function or middleware.
20
20
  Keep necessary custom code focused and report the capability gap; never invent
21
- fields or bypass target limits or operator grants. See `docs/PROJECT-DIRECTION.md` in the installed runtime.
21
+ fields or bypass target limits or operator grants. In a source checkout, see
22
+ `docs/PROJECT-DIRECTION.md`; in an npm installation, search the matching heading
23
+ in `llms-full.txt`.
22
24
 
23
25
  ## Read the contract before writing YAML
24
26
 
@@ -26,12 +28,25 @@ Documentation, schema and runtime must come from the **same revision**. Read fro
26
28
  the project's installed runtime (`node_modules/@jimhoyd/urlcode/`) or the
27
29
  checkout you are working in — never from memory of another version.
28
30
 
29
- Start with `urlcode context --project <dir> --budget 4000`, then retrieve the
30
- capability, schema fragment, recipe or example relevant to the change. Use the
31
- read-only MCP equivalents when available. `llms.txt` is the index; read the
32
- matching task guide from `docs/` when a query needs more explanation.
33
- `docs/SPECIFICATION.md` and `schemas/urlcode.schema.json` resolve contract
34
- questions. Archived plans are historical, not valid YAML guidance.
31
+ Make one bounded query first: MCP `get_context` when the `urlcode` server is
32
+ registered, otherwise `urlcode context --project <dir>` (add `--budget 4000`
33
+ when the project is large). It is a compact summary, constraints and exact
34
+ commands, not a schema dump. Then retrieve only what the change needs:
35
+ `urlcode capabilities NAME` (`get_capability`, for its limits), `get_schema`,
36
+ `recipes search TEXT` (`search_recipes`), `explain` and, when the operator
37
+ supplies a host file, `get_extensions`. Bare `urlcode capabilities`, `recipes
38
+ list`, the compact `llms.txt` index and `llms-full.txt` remain deliberate
39
+ fallback/reference: in a source checkout read the matching task guide from
40
+ `docs/`; in an npm installation search the heading in `llms-full.txt`.
41
+ When the project has an operator host file, inspect `urlcode extensions
42
+ --project <dir> --host-file <absolute-file> --json` (MCP: `get_extensions`)
43
+ before writing extension configuration or project hooks. The report is the
44
+ machine-readable source for config/policy schemas, hook contracts, supported
45
+ project-owned authoring surfaces and fast checks.
46
+ The `SPECIFICATION` section of `llms-full.txt` and
47
+ `schemas/urlcode.schema.json` resolve contract questions in an installed
48
+ package. A source checkout also has `docs/SPECIFICATION.md`. Archived plans are
49
+ historical, not valid YAML guidance.
35
50
 
36
51
  ## Workflow
37
52
 
@@ -49,6 +64,24 @@ questions. Archived plans are historical, not valid YAML guidance.
49
64
  - Create every referenced module, page and asset **before** validating. All
50
65
  source paths resolve from the project root. Trusted modules can import Node built-ins and npm packages;
51
66
  only `sandbox: true` modules are restricted to the relative snapshotted graph.
67
+ - Treat core, installed extensions and product UI as one application with
68
+ different owners. Follow an extension's published `authoring` surfaces in
69
+ this order: configuration; theme and copy; component or template override;
70
+ project CSS; declared trusted hook. Keep auth/admin security and workflow
71
+ behavior in their packages and keep only the product-specific difference in
72
+ the project. Build a new extension only for a reusable capability the
73
+ installed contracts cannot express. Extension hooks run trusted in-process
74
+ and reject `sandbox: true` in contract v1.
75
+ - When a React frontend has `components.json`, follow the installed official
76
+ shadcn/ui skill for component discovery, composition, accessibility and
77
+ semantic Tailwind styling. Start with `shadcn info --json`, then use its
78
+ `shadcn docs`/`search` flow or configured MCP registry before generating a
79
+ component. Do not put React components in URLCode's server template renderer
80
+ merely because it uses shadcn-compatible tokens.
81
+ - Run the extension's published `fastChecks` while iterating, then the full
82
+ project checks before handoff. Theme and copy changes should not rebuild the
83
+ framework packages. Full workspace/package checks may take several minutes;
84
+ give them enough time to finish instead of repeatedly rebuilding.
52
85
  - Write exact response fixtures for success and failure, covering every active
53
86
  method, middleware behavior, HEAD, and any range or cache semantics.
54
87
  - Follow `docs/BEST-PRACTICES.md` for layout and readability as the project grows.
@@ -108,6 +141,26 @@ runtime checkout, substitute `node src/cli.ts` for `urlcode`; in a project made
108
141
  from `urlcode-template`, the equivalent npm scripts work. External bindings
109
142
  require an already reviewed policy — add `--policy` where needed.
110
143
 
144
+ ## Feedback after a real attempt
145
+
146
+ After a task, give feedback only when a real attempt exposed one of these:
147
+
148
+ - a **capability gap**: a requirement the current contract cannot express;
149
+ - a **repeated-workaround**: custom code recreating framework plumbing likely
150
+ to recur across applications;
151
+ - a **documentation/discovery gap**: the supported path was hard to find or
152
+ distinguish from an unsupported one; or
153
+ - a **suspected defect**: observed behavior contradicts the installed contract
154
+ or its fixture.
155
+
156
+ Produce a compact draft, not an issue: category, installed runtime/target,
157
+ sanitized route or YAML fragment, the exact validation/test observation, the
158
+ smallest expected behavior, and a proposed fixture. Do not include secrets,
159
+ customer URLs, raw source, or one-off product logic. Search existing URLCode
160
+ issues first and name a likely duplicate when found. You may propose a new
161
+ issue or comment, but never create or update a GitHub issue without the user's
162
+ explicit approval.
163
+
111
164
  ## Boundaries
112
165
 
113
166
  - Keep secrets out of source, examples and Git. Request named bindings, but
@@ -18,6 +18,10 @@ another version.
18
18
 
19
19
  ## Read before advising
20
20
 
21
+ In a source checkout, use the `docs/` paths below. In an npm installation,
22
+ search the same document headings in `llms-full.txt`; the archive deliberately
23
+ does not duplicate the repository's authored documentation tree.
24
+
21
25
  1. `docs/OPERATIONS.md` — process and container deployment, shutdown, exposure.
22
26
  2. `docs/DEPLOYMENT-CHECKS.md` — `verify-deployment`: what it checks against a
23
27
  live target and what it deliberately does not.
package/README.md CHANGED
@@ -53,19 +53,22 @@ application by adding YAML; the operator wires trusted packages in one host
53
53
  file outside the project. The full map, the composition contract and the rules
54
54
  an AI agent must follow are in [the framework](docs/FRAMEWORK.md).
55
55
 
56
- | Package | Adds | Status |
56
+ | Package | Adds | Stable npm channel |
57
57
  |---|---|---|
58
- | [urlcode](https://github.com/jimhoyd-com/urlcode) (this repository) | Runtime, CLI, policies, provider adapters, extension contract | `0.4.1` stable release target, Apache-2.0 |
59
- | [urlcode-ui](packages/ui) (in this repository) | Shared presentation: escaped templates, shadcn/ui partials, themes, translations | `0.4.1` stable release target; review pending |
60
- | [urlcode-auth](packages/auth) (in this repository) | Accounts: password, passkeys, OIDC, email codes, TOTP, sessions, roles, account page | `0.4.1` stable release target; review pending |
61
- | [urlcode-admin](packages/admin) (in this repository) | Administration: users, sessions, roles, audit, approvals, cases, impersonation | `0.4.1` stable release target; review pending |
62
-
63
- This release aligns all four packages at `0.4.1`, with publication to npm's
64
- `latest` channel in the order core ui auth → admin. The table describes
65
- the release target; confirm publication with `npm run release:status` before
66
- installing it. Matching numbers do not establish a permanent fixed-version
67
- policy. Peer ranges, channel rules and generated application pins are documented
68
- in [package and channel alignment](docs/VERSION-ALIGNMENT.md).
58
+ | [urlcode](https://github.com/jimhoyd-com/urlcode) (this repository) | Runtime, CLI, policies, provider adapters, extension contract | [![npm stable version](https://img.shields.io/npm/v/%40jimhoyd%2Furlcode?label=stable)](https://www.npmjs.com/package/@jimhoyd/urlcode) |
59
+ | [urlcode-ui](packages/ui) (in this repository) | Shared presentation: escaped templates, shadcn/ui partials, themes, translations | [![npm stable version](https://img.shields.io/npm/v/%40jimhoyd%2Furlcode-ui?label=stable)](https://www.npmjs.com/package/@jimhoyd/urlcode-ui) |
60
+ | [urlcode-auth](packages/auth) (in this repository) | Accounts: password, passkeys, OIDC, email codes, TOTP, sessions, roles, account page | [![npm stable version](https://img.shields.io/npm/v/%40jimhoyd%2Furlcode-auth?label=stable)](https://www.npmjs.com/package/@jimhoyd/urlcode-auth) |
61
+ | [urlcode-admin](packages/admin) (in this repository) | Administration: users, sessions, roles, audit, approvals, cases, impersonation | [![npm stable version](https://img.shields.io/npm/v/%40jimhoyd%2Furlcode-admin?label=stable)](https://www.npmjs.com/package/@jimhoyd/urlcode-admin) |
62
+
63
+ The badges report each package's live npm `latest` channel, which is the stable
64
+ version of that package. Stability is independent: matching version numbers are
65
+ not required. Releases created by the current [GitHub release
66
+ publisher](https://github.com/jimhoyd-com/urlcode/releases) show the exact
67
+ four-package combination tested together, its declared peer
68
+ requirements and a copyable exact-version install command; the signed
69
+ `train.json` asset is the machine-readable receipt. Peer ranges, channel rules
70
+ and generated application pins are documented in [package and channel
71
+ alignment](docs/VERSION-ALIGNMENT.md).
69
72
 
70
73
  `urlcode-dynamic-link` and `urlcode-short` were published once as
71
74
  `0.1.0-alpha.1` and have since been retired: both were unpublished from npm and
@@ -106,7 +109,8 @@ it. Cross-repository acceptance is tracked in
106
109
 
107
110
  ## Status
108
111
 
109
- The `0.4.1` release line brings core, UI, auth and admin to matching stable
112
+ <!-- urlcode-current-version:start -->
113
+ The `0.4.6` release line brings core, UI, auth and admin to matching stable
110
114
  versions. A stable version selects the npm `latest` channel; it does not close
111
115
  the review and deployment evidence gaps below. `0.4.0-alpha.1`
112
116
  added the extension contract, capabilities and provider conformance, strict
@@ -118,6 +122,7 @@ opt-in, and removed the native `link:`/`dynamicLinks:` YAML shape. That is a
118
122
  behaviour change for existing projects with no YAML edit; read
119
123
  [the roadmap entry](ROADMAP.md) before upgrading. Use the schema and docs from
120
124
  the runtime revision you run.
125
+ <!-- urlcode-current-version:end -->
121
126
  The [roadmap](ROADMAP.md) separates implemented from planned, and
122
127
  [release readiness](docs/RELEASE-READINESS.md) records what is proven and
123
128
  what is not: provider deployments, soak and independent security review
@@ -178,8 +183,7 @@ SQLite build requirement, unverified from this repository.
178
183
  ## Try it
179
184
 
180
185
  ```sh
181
- # After the 0.4.1 release has been published:
182
- npm install --global @jimhoyd/urlcode@0.4.1
186
+ npm install --global @jimhoyd/urlcode@latest
183
187
  urlcode init my-urls && cd my-urls
184
188
  urlcode dev
185
189
  ```
package/SECURITY.md CHANGED
@@ -57,6 +57,8 @@ confirmed issues use private coordination and a public advisory when appropriate
57
57
  Bind loopback by default; protect public deployments with HTTPS, rate limits,
58
58
  network controls and restricted operational endpoints. See [operations](docs/OPERATIONS.md).
59
59
 
60
- See the [internal security reviews](docs/SECURITY-AUDIT.md) most recently
61
- 2026-09-17 for fixed findings and remaining gates. Use a current reviewed commit: the shared 0.3.0
62
- version label alone does not identify which hardening patches are present.
60
+ Use a current reviewed commit: the shared 0.3.0 version label alone does not
61
+ identify which hardening patches are present. Internal source-review details are
62
+ maintainer material, not an independent assessment; the public security model,
63
+ reporting path and outstanding assessment gate are the authoritative claims on
64
+ this page and in [the sandbox review](docs/SANDBOX-REVIEW.md).
@@ -2,19 +2,21 @@
2
2
  "node": "v26.9.0",
3
3
  "files": {
4
4
  "dist/adapters.js": "a7153ec52f2ed7e0cdd8ed7d433504815f402ec53b2b1c3d38d0cf0e2fcf6509",
5
+ "dist/agent-context.js": "1e4e9c7b85d155c06d99d8b70f625bd7ab31330a0207aef6ed1803243b759611",
5
6
  "dist/agent-lists.js": "35ab484198897501d011cb6cc00b5a6787192e19df29c97646e8c118fcc19eef",
6
- "dist/agents-guide.js": "0b19909aee3f8a1039c34c43ff58116ec1bc3f1875e3dbc34b3b01655273201c",
7
+ "dist/agents-guide.js": "14684bf514cabbe7c9bb1ad6b6b2c479f8aaf3feb299b64655fd9fba218268d6",
7
8
  "dist/assets.js": "0833b093d2fe457ce68281110dc07d47914992753607741c13b339d92c76cf5c",
8
9
  "dist/authoring-files.js": "ad32814f9ae9c549c6247396f982aa700d13a293cc0a589609eccc68f8965550",
9
- "dist/authoring.js": "5fe1e871ff216ef1f7d2f490f74397b81b1de4edfe31cdb6115907296aa1c652",
10
+ "dist/authoring.js": "bb3d4e7c6c982c4a1985a7663f960d05a08459d935e2609d404f4001b7ea767f",
10
11
  "dist/aws.js": "7d8e3a97b4f6dbefbd68da058f05192469d1efcaed5458b284863ebe462e060e",
11
- "dist/build-cloudflare.js": "af4f49ad45287d7c4105bb84b1592b5b8e76c930f7159505338298f7c5fd5651",
12
+ "dist/body-schema.js": "0227ef8cf2b380e3ef65a358533aa0e0f4a119c94e63747b8eb03fe65a6b9193",
13
+ "dist/build-cloudflare.js": "e552dbf3c08036f02b0e5eb4bfd1309229bbba41d021ac15051e3f6fb165d8b4",
12
14
  "dist/build-static.js": "fe01ef4fcc66d83d8be7a787538b55974e84fd3d7c89e26f0a2f1a152762d565",
13
15
  "dist/bulk.js": "aac88d422bd9a7a341a421fb4e29ff5580b28d39250b7f1f5315ba20ae92da8a",
14
- "dist/capabilities.js": "28dba05b3851b8b12b3c1b809af87b732f84d601c737afe9225abe429886e691",
16
+ "dist/capabilities.js": "bb98f5bbf54cc4e82fa197f999a621ad815273176f02692c35566886e2bb8777",
15
17
  "dist/capability-query.js": "9f68bc94901451d7b9ecdd3aee8c3376dca7f0b890e31d8205306cf8120dea86",
16
18
  "dist/catalog.js": "c378ef9bfd63b940790f6975f7db54557c2459722b65a7c170b97df24184bc52",
17
- "dist/cli.js": "45b8adaae66a46e7b05067f1ced488b9dd7ccff8d15ba71e858459d76f5ddbb8",
19
+ "dist/cli.js": "c155fc50b1750dd0eda78ec3860f8855f6726e563d6d28632a6e54891e09b768",
18
20
  "dist/client-address.js": "9d0d01466aab23124330605c5a0e0f981f87c897858acfad909f546a63df165b",
19
21
  "dist/cloudflare.js": "17b43b0a6b6a0ef8a893415c989e4ae3976d97cc966adbf897b785f9adc472e3",
20
22
  "dist/compliance-rules/baseline.js": "6296dea6bcb9f9bb80ed6ed5ab2f456e7f74e6de2be5d2d98ca8c983fb4df3ab",
@@ -24,63 +26,64 @@
24
26
  "dist/compliance.js": "29a18da3cefea94802ac7d817d1ab4e3674abd5c3ac4ef893cb8b01c6a23fb61",
25
27
  "dist/conditions.js": "ff25e97da550a3bdd80af55522045669438aa31a77d2bc83ad602bcefdee0475",
26
28
  "dist/config-worker.js": "bc2170d60c35f8d5de227cbfc4c5067dc61d7cbc5b98aed88e68a11797072da5",
27
- "dist/config.js": "8a0fde242b4658c522031a15d89daed25f8b77761f5c4204f295d5e311ac8ff7",
28
- "dist/context.js": "549a53e4738b9c20a1ec55614027f758026fb5860bf4ac962ce22d7029e48df0",
29
+ "dist/config.js": "33c8d1f80aa7f1ce25eab12644f6cbef961a897b72b1585d4bfa6424985f0d16",
30
+ "dist/context.js": "f0de473b1e13649b0778fe2d5e7a65d4d6ac82614b47a1f86b453b73a85cb166",
29
31
  "dist/ecosystem-cli.js": "1e71bacd53d6fa8c7857cfcce3c3012ce054771a434b78d1f39e892e32642edd",
30
32
  "dist/egress.js": "2ae29fe2cb4590fd2f715abe6817db47fed2f50dd31f37946ecf42eafbb0dd9e",
31
- "dist/errors.js": "a908e66496afebbdd632a8c159a6e14d23f8f38798a0b4342ca122f2511c6cde",
32
- "dist/examples.js": "89ae2b764a688fe52acfb9b94d3d262d7742401ebd0ef10c9ebfc76edfa5631c",
33
+ "dist/errors.js": "fef26eb834dd61b8b5f587eb7ab265d216122d182545f0a1c5b19c20840dffb0",
34
+ "dist/examples.js": "8523799797d2530fe48ec5e96c34970bdba03c49afb31fdaab6a9c162a17dfa9",
33
35
  "dist/explain-cli.js": "f0f8f3b5046430d03c6abb629b38651c9c734b03456040735ce9d7e582b2bcd5",
34
36
  "dist/explain.js": "7fb632036cc68280701dd512c74d27d6e0f97b4848e9024b284d7c5393b35eb5",
35
- "dist/extensions.js": "0506ec6289fa0582399d8c6d27727ffeb629bd442264248c921c63cc5b46ff01",
37
+ "dist/extensions.js": "966441cca677b0d88683d29d89d36c61cf487ae2b70d94eaa0c71c50730a4212",
36
38
  "dist/function-sources.js": "16fad4abc81c7ee07b6cbcef2d23a9fc50e97a17cb4dde1db53469bbb555c96f",
37
39
  "dist/function-worker.js": "35771790ada4e1b36d447d4967a5e6cf0b543f32944e4c904f5fbf8998e824a5",
38
40
  "dist/functions.js": "0f09d1bd27eb655ceb5900a4a5e2b760d2028b02cb637a6a89a4eb5940828008",
39
41
  "dist/guest-api.js": "49aec9ed72733ad119e63bcfcee18158dcc8ceb951e1823b8947f6407ff24afc",
40
42
  "dist/header-validation.js": "465181dbb08ff05f52defdd29fda025c0c64589bf319fa87fa6d3ab4b68216d5",
41
- "dist/http-policy.js": "4cb187642269078ddf3460a3f1813dc57878a616a6f8132ef8f8d3b4b91ebb56",
42
- "dist/http-response.js": "62f5da2e08bfe7ecff07464a49aaf910aa55770308a59118be9372390c2df9a1",
43
+ "dist/http-policy.js": "393a6383bdf9e05597c98721b3a4c4207a9bbe359883babcbfa06b696c70f56c",
44
+ "dist/http-response.js": "565826d1ece4bd30dfc1150c75800acec1fef584f732e964409aa92958fc8550",
43
45
  "dist/index.js": "8d7532ae0a31f9439ebb62e7b01a2748aee00f350262ff55d1226121d206c1ed",
44
- "dist/init-with.js": "bf43b3aa4b421e9a31c5227e6afdf4956aba70d836ffddde96176a772d79e09b",
46
+ "dist/init-with.js": "0d2dccb83f0ad53181c6f5c95a4c663ce06ee9a1fa9074facac9a1aee7599a96",
45
47
  "dist/interchange-cli.js": "35bd70ba8077af5c3e39404ff0e5d28707632090a59a90645141252449fd3f04",
46
48
  "dist/interchange.js": "26789420af33344d9a08c00fe6b2708aa71994224df527b3075295be2151611e",
47
49
  "dist/logging.js": "8ec57fea26983aa071b05fe15d680d6550b03488101163ed9666da674118cf31",
48
50
  "dist/manifest.js": "83eed0d59621039ef364cf6e7b54c5bd47e0d8cf0a5abe7b07344bfc1db56ed8",
49
51
  "dist/match.js": "53ebcc2cda529a8d07fb83f8cb69a1446036ffc1641af3c4bd45a55851bded28",
50
52
  "dist/mcp-authoring.js": "1183a56c5decb99ecb67a5da7bd91d1b494bc17a2965051aa63c4a7e291462b5",
51
- "dist/mcp.js": "484c03cdf81f94116ec973feb70754298f8b1d5b3b42561969f8cce26b3c97c2",
53
+ "dist/mcp.js": "28e6b98a394ae330d4310abc89e0e5a5210d2b892c9ecb3ac97345e765e584f8",
52
54
  "dist/observability.js": "f4b1ab496f051fe3ef2ed36b2b2e469c63a8940700e2df852e6ff2d9cccdd5ae",
53
55
  "dist/operator-host.js": "e3dac9d43a83beb775202b4ab9eeeba7ac63cebfc5dcc669be38d825be587bd0",
56
+ "dist/pattern-guard.js": "6f157ced99666a89ca5af1418f5a14568d850985042dea309bf9ec0c19dbaca5",
54
57
  "dist/plugins.js": "a61aa933cd9e1b41020b86fae78aa3a7f45f5313124aa11b50cb57898722385e",
55
58
  "dist/policies/agents.js": "c1dbc1e90339f472eeeb2372f7f4637f59a5d210797ea680ac8120a02aa20c10",
56
59
  "dist/policies/cache.js": "d08184e50b0ecb7331b29e4145aaefacb23b64ddaf3555d579743762f90c1629",
57
60
  "dist/policies/compression.js": "800f3ae3b1a4c1fe58c3d9908364ea9d78f655ff50c7f7589f584378e7f194b0",
58
- "dist/policies/security.js": "2b3bfdf82140156fea4b162adc28ee43ccd85c402fb200680dbb8d8706417420",
61
+ "dist/policies/security.js": "c68d39f5fa2d7d16f5bfb3dcff2ac71428cc41814970eecf8b931debd40c0f3e",
59
62
  "dist/policies/throttle.js": "bbb0cb1c24cf70d0a1ac32fc0618efb6c44e5b5d42564842f9c585ff7e501603",
60
63
  "dist/policies.js": "3750a7032ec7326aa544f4808683ad9eb91d4f2c5afe79904420cd8a355710a9",
61
- "dist/policy.js": "33c527008fafe4af18243ba668d069517c20659150f9f1d1a5a1d076e8724f89",
64
+ "dist/policy.js": "2da95b3f1f77249b1e9f399a06b88909b68594fdbc958176075e91ff23104a7c",
62
65
  "dist/prerender.js": "6210999e848ab86c87f265943960ef63716896da7a40e248221a6a30425c56b8",
63
66
  "dist/project-dependencies.js": "b43a8f3125f62d38f0e71237b7813a785ef0613a83fcdec3fa8314f33758a534",
64
- "dist/project-tests.js": "445eaa139d2f1a2534369cfdeef081ef518de03218a467e7c5c2059caf840270",
67
+ "dist/project-tests.js": "63562978411ee94a69dcf45d4d47e84fba009d8654ac421c2a02a418cd80b4db",
65
68
  "dist/provider-verification.js": "ffcf9f05e8cb5f71ea46a97e279e8a613fdfdf9435ab02bd57af11e2680a9107",
66
69
  "dist/proxy.js": "34107e59ac0dbbea090efa3cf5badf3226c5302ba25e8f8ff9b2b5596ed80e50",
67
- "dist/readiness.js": "90b54bc0cf60dd155d05789a1aad767bd67483d5fa6064ae8b1143f8cf9e06b2",
68
- "dist/recipes.js": "11853f23e63c3c65c5bed03a278cde0349d28c9fa23266c9907a2df318bb5fc3",
70
+ "dist/readiness.js": "2b67bc86c0c73528f3f798b6a0ee1bd5aec5ac6f4a0998c45443c903a622af4f",
71
+ "dist/recipes.js": "7af62ea9f612c82ea21e97e9d14451f05e0b509d6e420fb99fec96b22e3533f1",
69
72
  "dist/route-diff.js": "8d71d50d332ffaaed588656bd32aa36763260d1ad87bb62d7ea1c8fb23383969",
70
- "dist/router.js": "cf831025d5ed6778d1d6a0e541177799794e76766c82084ded81d3e87317ca1e",
71
- "dist/runtime.js": "2346d4630d178ee52caa7a94d4289f9b16f4b8ee467070b39fdd05742ed4513f",
73
+ "dist/router.js": "b2b26409321c5d119ac54793efe6bb6a2f9bbf2f36db251c68337c25b9d836b9",
74
+ "dist/runtime.js": "e36153ab250b566ea778584a447ce603cf283274d9f8ac54a22aa9969c2284e8",
72
75
  "dist/sandbox.js": "c88c5aa5dd95b4f55f1ba62da7969ad66dbd97c30f72e5b5f2817a2098ac1c65",
73
- "dist/scaffold.js": "3ef243aceca7ddf2780aa2c8c04ae17edd07682d3a418fd5d65ba00f5c762f14",
76
+ "dist/scaffold.js": "0f936cabd20b609c7ebfebd7895710ce6c30882c3088a2356ac75bb4e0d10c55",
74
77
  "dist/schema-query.js": "bfd1844acd8d54ac361115191fcfbaf828a67e223b9ec6e9c22f158761af149b",
75
- "dist/server.js": "d878bc8f0d6a05f8fd25997cace3150e2ff4d44ee9c8f4b5530e29601e164be1",
78
+ "dist/server.js": "165b66fc4ed3b8e7c46ae4402ef66a5bc988c0910fb3e11556b040781e09d03c",
76
79
  "dist/signals.js": "b55e54efc8fb6703e08f2a1e808ec8e011bda67738db8ceadf1b248f695795be",
77
- "dist/site.js": "c40a06a6f9e2d6d3bea94727783c115fed4309bb0190787f58434eed64cbde84",
78
- "dist/tooling.js": "7409db98422325cd4181d073d645ea57debca0e54cb151123474b85f4d4ed7dc",
80
+ "dist/site.js": "38176ac4d1970ebf73e3f96094f39900724ce96b29d6de892b8baae01e183aa5",
81
+ "dist/tooling.js": "3d2848aba0a374ef980328c6924d4b314c53094efc2cc94638f1a58b726f8161",
79
82
  "dist/trusted-functions.js": "f3800c75f45ce90faf85ba6664398ad9031c5a9ac51d5ce42bdcff08a497d48e",
80
- "dist/types.js": "2fe7664dbb5695ec72114197abde72de4031df9c3b211740eacefa68e9b21844",
81
- "dist/typescript-authoring.js": "2e98498a15bdbb76f36fbee84afb7c42ca95bbf80a2e6dd4040147f3b1642a29",
83
+ "dist/types.js": "827f1afde90d19715e79500515ecaa80f5b65ce552f0ef24d2fc561ef77e6e40",
84
+ "dist/typescript-authoring.js": "df3d9c82e6b545cae5caae04c443ed4d2feae96def5e5cde250c0a90d83ae98c",
82
85
  "dist/vercel.js": "a0da20c095d0c7fa8f579ed4dd5951e7a34191f8a72a57c5e782c9eab39f6f08",
83
- "dist/verify-deployment.js": "0c2e68f3cf258a364728c801411df5284343bc01b75a64fe275ff84e397e998b",
86
+ "dist/verify-deployment.js": "2d3b6301b70684abfccea669f7901afda7fae9d9d66902809ecdef65f22aea16",
84
87
  "dist/scripts/operational-drills.js": "c26c406d28013cc554b25a5b6bf8baf4e71d5e67e50d866fae546f538a192317"
85
88
  }
86
89
  }
@@ -0,0 +1,82 @@
1
+ import {readFile} from 'node:fs/promises';
2
+ import {fileURLToPath} from 'node:url';
3
+ import {parseYaml,validateDocument} from './config.js';
4
+ import {listExamples} from './examples.js';
5
+
6
+ /**
7
+ * Fixed, package-owned agent material. This is intentionally a manifest rather
8
+ * than an arbitrary file reader: MCP clients cannot use it to enumerate or
9
+ * exfiltrate a local project.
10
+ */
11
+ const packageRoot=fileURLToPath(new URL('../',import.meta.url));
12
+ const docs=[
13
+ {id:'llms',title:'URLCode agent index',file:'llms.txt',summary:'Compact map of the framework, its declarative primitives and the minimum reference to load next.'},
14
+ {id:'authoring',title:'AI authoring',file:'docs/AI-AUTHORING.md',summary:'Declarative-first authoring workflow, retrieval order and framework constraints.'},
15
+ {id:'yaml-reference',title:'YAML reference',file:'docs/YAML-REFERENCE.md',summary:'Generated inventory of accepted URLCode YAML fields.'},
16
+ {id:'tooling',title:'Tooling and local MCP',file:'docs/TOOLING.md',summary:'Bounded local project inspection, validation and MCP tool behavior.'},
17
+ {id:'security',title:'Function security',file:'docs/FUNCTION-SECURITY.md',summary:'Trusted versus sandboxed function behavior, bindings and operator grants.'},
18
+ ] ;
19
+ const skills=[
20
+ {name:'urlcode',description:'Author URLCode projects declaratively, retrieve only the required contract, and validate the result.',file:'skills/urlcode/SKILL.md'},
21
+ ] ;
22
+ const maxExcerpt=1800;
23
+
24
+ function terms(query ) {return [...new Set(query.toLowerCase().split(/[^a-z0-9]+/).filter(term=>term.length>1))].slice(0,16);}
25
+ function excerpt(text , query ) {
26
+ const words=terms(query),lower=text.toLowerCase();
27
+ const positions=words.map(word=>lower.indexOf(word)).filter(position=>position>=0);
28
+ const start=Math.max(0,(positions.length?Math.min(...positions):0)-300);
29
+ return text.slice(start,start+maxExcerpt);
30
+ }
31
+ async function content(file ) {return readFile(packageRoot+file,'utf8');}
32
+
33
+ export function listSkills() {return skills.map(({name,description})=>({name,description}));}
34
+ export async function getSkill(name ) {
35
+ const skill=skills.find(candidate=>candidate.name===name);
36
+ if(!skill)throw new Error('Unknown bundled skill');
37
+ return {name:skill.name,description:skill.description,content:await content(skill.file)};
38
+ }
39
+
40
+ /** Deterministic lexical search over a deliberately small, agent-facing corpus. */
41
+ export async function searchDocs(query ) {
42
+ const words=terms(query);
43
+ if(!words.length)throw new Error('Search text must contain a word');
44
+ const hits=(await Promise.all(docs.map(async doc=>{
45
+ const text=await content(doc.file),haystack=`${doc.title} ${doc.summary} ${text}`.toLowerCase();
46
+ const matched=words.filter(word=>haystack.includes(word));
47
+ return {doc,text,matched,score:matched.length};
48
+ }))).filter(hit=>hit.score>0).sort((a,b)=>b.score-a.score||a.doc.id.localeCompare(b.doc.id)).slice(0,3);
49
+ return {query,results:hits.map(({doc,text,matched})=>({id:doc.id,title:doc.title,summary:doc.summary,matched,excerpt:excerpt(text,query)}))};
50
+ }
51
+
52
+ /** Returns the two smallest high-value files of a fixed packaged example. */
53
+ export async function getExample(name ) {
54
+ const example=(await listExamples()).find(candidate=>candidate.name===name);
55
+ if(!example)throw new Error('Unknown bundled example');
56
+ const files=example.files.filter(file=>file==='urlcode.yaml'||file==='README.md');
57
+ const content =Object.create(null);
58
+ for(const file of files)content[file]=await readFile(`${packageRoot}examples/${name}/${file}`,'utf8');
59
+ return {metadata:example,content};
60
+ }
61
+
62
+ /** Validates only supplied YAML syntax and the versioned document schema. It never resolves includes or reads source files. */
63
+ export function validateYaml(text ) {
64
+ try {
65
+ const document=validateDocument(parseYaml(text));
66
+ return {valid:true,scope:'syntax-and-schema-only',version:document.version,routeCount:Object.keys(document.routes).length};
67
+ }catch(error){
68
+ return {valid:false,scope:'syntax-and-schema-only',error:error instanceof Error?error.message:'Invalid URLCode YAML'};
69
+ }
70
+ }
71
+
72
+ /** Short deterministic remediation for common validator output; no model call or project read occurs. */
73
+ export function explainError(error ) {
74
+ const lower=error.toLowerCase();
75
+ let guidance='Use validate_yaml for YAML syntax/schema feedback, then use local validate for project files, includes and route semantics.';
76
+ if(lower.includes('duplicate yaml')||lower.includes('duplicate key'))guidance='Give every mapping key one value. URLCode rejects duplicate YAML keys rather than choosing one silently.';
77
+ else if(lower.includes('aliases')||lower.includes('anchors')||lower.includes('explicit tags'))guidance='Rewrite YAML anchors, aliases and tags as ordinary repeated YAML values; URLCode accepts a JSON-compatible YAML subset.';
78
+ else if(lower.includes('invalid configuration at'))guidance='The named location does not match the versioned URLCode schema. Ask get_schema for that field or get_capability for the handler before editing it.';
79
+ else if(lower.includes('project file')||lower.includes('referenced'))guidance='This needs local project validation: confirm the referenced path is project-relative, exists, and is allowed by the selected route type.';
80
+ else if(lower.includes('sandbox'))guidance='Sandboxed routes cannot use Node or network APIs. Prefer a declarative handler or proxy; otherwise remove sandboxing only after a deliberate trust review.';
81
+ return {guidance,nextTools:['get_schema','get_capability','validate']};
82
+ }
@@ -33,53 +33,55 @@ export function renderAgentsGuide({ routes } ) {
33
33
  return `# Working on this project
34
34
 
35
35
  This project uses URLCode: URL behavior is declared in \`urlcode.yaml\`, and the
36
- installed \`@jimhoyd/urlcode\` runtime serves it. There is no framework code to
37
- write for routing, validation, middleware wiring, policies, static serving or
38
- authentication; the runtime provides them. Read this file before changing anything.
36
+ installed runtime supplies routing, validation, middleware wiring, policies,
37
+ static serving and authentication. Read this file before changing anything.
39
38
 
40
39
  ## Before writing code
41
40
 
42
41
  1. Inspect \`urlcode.yaml\` first, then every file its \`includes\` list names,
43
- the referenced functions, middleware and \`tests/requests.json\`. Preserve the
44
- existing organization and every route you were not asked to change.
45
- 2. Run \`urlcode capabilities\` to see what this runtime version implements and
46
- which targets support it; \`urlcode capabilities --target NAME\` before
47
- promising any provider deployment.
48
- 3. Run \`urlcode recipes list\` and \`urlcode recipes show NAME\` before writing a
49
- route from scratch. If a recipe covers the need, add it with
50
- \`urlcode recipes add NAME --out DIR\` and adapt the copy.
42
+ referenced code and \`tests/requests.json\`. Preserve unrelated routes.
43
+ 2. Make one bounded query first: MCP \`get_context\` when the \`urlcode\` server is
44
+ registered, else \`urlcode context --project DIR\` (add \`--budget N\` to cap
45
+ it). It returns a compact summary, constraints and exact commands.
46
+ 3. Then retrieve only what the task needs: \`capabilities NAME\`/\`get_capability\`
47
+ (limits; \`--target NAME\` before promising a provider), \`get_schema\`,
48
+ \`recipes search TEXT\`/\`search_recipes\` then \`recipes add NAME --out DIR\`,
49
+ \`explain\` and, with an operator host file, \`get_extensions\`. Bare
50
+ \`capabilities\` and \`recipes list\` are complete catalogs: fallback, not step one.
51
51
  4. Use URLCode's highest-level declarative features whenever possible. Generate custom code only when the framework cannot express the requirement. Check supported extensions and recipes first; explain any capability gap.
52
52
 
53
- ## Ask the runtime through MCP first
53
+ ## MCP
54
54
 
55
- When present, \`${mcpConfigFile}\` registers the read-only \`urlcode mcp\` server. When it is
56
- available, prefer its tools over reading documents: \`get_context\`,
57
- \`get_capability\`, \`get_schema\`, \`search_recipes\`, \`explain\`, \`get_manifest\`.
58
- The CLI equivalents are the fallback: \`urlcode context\`, \`urlcode capabilities NAME\`,
59
- \`urlcode schema PATH\`, \`urlcode recipes search TEXT\`, \`urlcode explain PATH\`,
60
- \`urlcode manifest\`. \`--allow-authoring\` is an operator opt-in; never add it yourself.
55
+ When present, \`${mcpConfigFile}\` registers the read-only \`urlcode mcp\` server; prefer its
56
+ tools (also \`get_manifest\`) to reading documents. Inspect \`get_extensions\` before
57
+ replacing extension behavior. \`--allow-authoring\` is an operator opt-in; never add it.
61
58
 
62
59
  ## What the runtime provides (this version)
63
60
 
64
61
  - Handlers, exactly one per route: ${handlers.map(name => `\`${name}\``).join(', ')}.
65
62
  - Ordered \`middleware\` around any handler, declared in YAML, trusted by default.
66
- - Validated inputs: \`parameters\`, \`request.body\` and \`methods\` on the route;
67
- functions receive validated \`args\`, never raw user input.
63
+ - Validated route \`parameters\`, \`request.body\`, \`methods\` and function \`args\`.
68
64
  - Policies, host-enforced and off by default: ${policies.map(name => `\`${name}\``).join(', ')}.
69
65
  - Site conventions under \`site\`, each generating one native route: ${site.join(', ')}.
70
66
  - Bindings: named \`env\` and \`secrets\` references resolved by the operator, never values in YAML.
71
67
 
72
- Never recreate any of these in a function; a missing one is a report, not an
73
- invitation to reimplement it.
68
+ Never recreate these in a function; report a missing capability.
69
+
70
+ ## Build one application
71
+
72
+ Treat routes, extensions and UI as one application with different owners. Use
73
+ published surfaces in order: configuration/theme/copy, smallest template, CSS,
74
+ then a declared hook. Keep auth/admin security and workflows package-owned; add
75
+ an extension only for a reusable missing capability. Use the official shadcn/ui
76
+ skill only in a React frontend with \`components.json\`; start with \`shadcn info
77
+ --json\`. Do not put React components in the server renderer.
74
78
 
75
79
  ## Functions and middleware are trusted by default; sandbox is opt-in
76
80
 
77
- A route's \`function\`/\`middleware\` runs trusted, in-process, with full
78
- Node/filesystem/\`fetch\` access, given only declared \`args\`/\`env\`/\`secrets\`. Add
79
- \`sandbox: true\` when that code warrants isolation (unreviewed code, a sensitive
80
- secret, complex logic) not merely for untrusted input, which both modes share.
81
- A \`sandbox: true\` route gets a text/JSON subset only: use \`proxy\`/a binding, and
82
- say why in \`sandboxReason\`.
81
+ A \`function\`/\`middleware\` is trusted, in-process Node with only declared
82
+ \`args\`/\`env\`/\`secrets\`. Add \`sandbox: true\` for code needing isolation, not
83
+ merely untrusted input. The sandbox is text/JSON-only; use \`proxy\`/a binding and
84
+ record the reason in \`sandboxReason\`.
83
85
 
84
86
  ## Checks that count as evidence
85
87
 
@@ -89,25 +91,23 @@ urlcode test
89
91
  urlcode audit --expect-routes ${routes}
90
92
  \`\`\`
91
93
 
92
- Run all three after every change, updating the route count deliberately and
93
- adding \`tests/requests.json\` fixtures for every new route (positive/negative,
94
- every active method, HEAD). No global install: use \`node /path/to/urlcode/src/cli.ts\`.
94
+ Run all three after every change, updating the route count deliberately and adding \`tests/requests.json\` fixtures for every new route (positive/negative, every active method, HEAD). No global install: use \`node /path/to/urlcode/src/cli.ts\`.
95
+
96
+ ## Feedback
97
+
98
+ After a real attempt, draft evidence-backed feedback: category, sanitized YAML, observed validation/test result, expected behavior and fixture. Ignore one-off product logic; search existing URLCode issues first; never publish or comment without the user's explicit approval.
95
99
 
96
100
  ## Rules
97
101
 
98
- - Report unsupported requirements instead of inventing fields. The schema is
99
- exact; a field the validator rejects does not exist. Say what is missing.
100
- - Never create or approve operator grants. Request a named binding in YAML and
101
- stop; the operator grants it outside this project, pinned to the revision.
102
- - Secrets stay out of the project: no keys, tokens or credentials in YAML,
103
- functions, fixtures, \`.env\` files that are not ignored, or commit messages.
102
+ - Report unsupported requirements; a field the exact schema rejects does not exist.
103
+ - Never create operator grants. Request a named binding; the operator grants it
104
+ outside the project, pinned to the revision.
105
+ - Keep keys, tokens and credentials out of project files and commit messages.
104
106
  - Protect a route with \`auth: true\`/\`auth: { role: admin }\` where an \`auth\`
105
107
  extension is declared; \`cache\` likewise expands to \`policies.cache\`.
106
- - Validation, tests and the audit are the evidence. Local checks are not a
107
- deployment, a soak test or a security review; do not claim otherwise.
108
+ - Local checks are not deployment, soak or independent security evidence.
108
109
 
109
- The installed package ships an agent skill with the same loop at
110
- \`${skillPath}\` inside \`@jimhoyd/urlcode\` (for example
111
- \`node_modules/@jimhoyd/urlcode/${skillPath}\`).
110
+ The installed package ships the same loop at \`${skillPath}\` inside
111
+ \`@jimhoyd/urlcode\` (for example \`node_modules/@jimhoyd/urlcode/${skillPath}\`).
112
112
  `;
113
113
  }
package/dist/authoring.js CHANGED
@@ -18,18 +18,28 @@ import { renderPackageManifest } from './project-dependencies.js';
18
18
 
19
19
 
20
20
 
21
+
22
+
21
23
 
22
- export async function initProject(destination , { manifest } = {}) {
24
+ export async function initProject(destination , { manifest, template = 'default' } = {}) {
23
25
  const target = resolve(destination);
24
26
  await mkdir(dirname(target), { recursive: true });
25
27
  // Reserve destination before copying; never merge into existing user files.
26
28
  await mkdir(target);
27
29
  try {
28
- const source = fileURLToPath(new URL('../starters/default/', import.meta.url));
30
+ const source = fileURLToPath(new URL(`../starters/${template === 'page' ? 'page' : 'default'}/`, import.meta.url));
29
31
  for (const file of await readdir(source)) {
30
32
  if (file === '.gitignore' || file === 'AGENTS.md' || file === mcpConfigFile) continue;
31
33
  await cp(join(source,file), join(target,file === 'gitignore.template' ? '.gitignore' : file), { recursive: true, force: false, errorOnExist: true });
32
34
  }
35
+ if (template === 'page') {
36
+ await loadDocument(target);
37
+ if (manifest) {
38
+ const pkg = await open(join(target,'package.json'), 'wx', 0o644);
39
+ try { await pkg.writeFile(renderPackageManifest(target, manifest)); } finally { await pkg.close(); }
40
+ }
41
+ return target;
42
+ }
33
43
  // AGENTS.md is generated from the installed runtime's capability catalog so
34
44
  // it names only what this version implements; the starter carries a
35
45
  // committed copy for clones, kept identical by test.