@jimhoyd/urlcode 0.4.2 → 0.4.7

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 (214) hide show
  1. package/.claude/skills/urlcode-authoring/SKILL.md +57 -14
  2. package/.claude/skills/urlcode-operations/SKILL.md +4 -0
  3. package/README.md +42 -18
  4. package/SECURITY.md +5 -3
  5. package/dist/BUILD-MANIFEST.json +30 -27
  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 +28 -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 +60 -2
  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/project-tests.js +35 -11
  25. package/dist/readiness.js +184 -32
  26. package/dist/recipes.js +1 -1
  27. package/dist/router.js +17 -0
  28. package/dist/runtime.js +26 -3
  29. package/dist/scaffold.js +0 -0
  30. package/dist/server.js +26 -3
  31. package/dist/site.js +0 -0
  32. package/dist/tooling.js +2 -1
  33. package/dist/types/agent-context.d.ts +44 -0
  34. package/dist/types/authoring.d.ts +3 -1
  35. package/dist/types/body-schema.d.ts +58 -0
  36. package/dist/types/config.d.ts +10 -2
  37. package/dist/types/context.d.ts +1 -1
  38. package/dist/types/errors.d.ts +9 -1
  39. package/dist/types/examples.d.ts +1 -1
  40. package/dist/types/extensions.d.ts +47 -2
  41. package/dist/types/http-policy.d.ts +3 -0
  42. package/dist/types/init-with.d.ts +10 -1
  43. package/dist/types/pattern-guard.d.ts +10 -0
  44. package/dist/types/project-tests.d.ts +9 -0
  45. package/dist/types/readiness.d.ts +68 -0
  46. package/dist/types/recipes.d.ts +1 -1
  47. package/dist/types/runtime.d.ts +4 -0
  48. package/dist/types/server.d.ts +9 -1
  49. package/dist/types/tooling.d.ts +1 -0
  50. package/dist/types/types.d.ts +13 -0
  51. package/dist/types.js +10 -2
  52. package/dist/typescript-authoring.js +5 -3
  53. package/dist/verify-deployment.js +16 -10
  54. package/examples/body-validation/README.md +16 -0
  55. package/examples/body-validation/example.yaml +17 -0
  56. package/examples/body-validation/tests/requests.json +15 -0
  57. package/examples/body-validation/urlcode.yaml +34 -0
  58. package/examples/coverage-waiver/README.md +8 -0
  59. package/examples/coverage-waiver/example.yaml +16 -0
  60. package/examples/coverage-waiver/functions/notes.mjs +2 -0
  61. package/examples/coverage-waiver/tests/requests.json +3 -0
  62. package/examples/coverage-waiver/urlcode.yaml +10 -0
  63. package/examples/data-dir/README.md +39 -0
  64. package/examples/data-dir/data/welcome.txt +1 -0
  65. package/examples/data-dir/example.yaml +22 -0
  66. package/examples/data-dir/functions/note.mjs +18 -0
  67. package/examples/data-dir/tests/requests.json +6 -0
  68. package/examples/data-dir/urlcode.yaml +6 -0
  69. package/examples/lifecycle/README.md +15 -0
  70. package/examples/lifecycle/example.yaml +19 -0
  71. package/examples/lifecycle/functions/notes.mjs +29 -0
  72. package/examples/lifecycle/tests/requests.json +12 -0
  73. package/examples/lifecycle/urlcode.yaml +29 -0
  74. package/examples/not-found/README.md +10 -0
  75. package/examples/not-found/example.yaml +17 -0
  76. package/examples/not-found/public/404.html +3 -0
  77. package/examples/not-found/public/index.html +3 -0
  78. package/examples/not-found/tests/requests.json +7 -0
  79. package/examples/not-found/urlcode.yaml +7 -0
  80. package/examples/shared-blocks/README.md +11 -0
  81. package/examples/shared-blocks/example.yaml +17 -0
  82. package/examples/shared-blocks/tests/requests.json +7 -0
  83. package/examples/shared-blocks/urlcode.yaml +37 -0
  84. package/llms-full.txt +364 -49
  85. package/llms.txt +44 -6
  86. package/package.json +15 -26
  87. package/recipes/static-page/README.md +9 -0
  88. package/recipes/static-page/public/index.html +11 -0
  89. package/recipes/static-page/recipe.yaml +21 -0
  90. package/recipes/static-page/tests/requests.json +22 -0
  91. package/recipes/static-page/urlcode.yaml +7 -0
  92. package/recipes/static-plus-api/README.md +6 -0
  93. package/recipes/static-plus-api/urlcode.yaml +4 -0
  94. package/recipes/store-crud/README.md +53 -0
  95. package/recipes/store-crud/recipe.yaml +31 -0
  96. package/recipes/store-crud/tests/requests.json +18 -0
  97. package/recipes/store-crud/urlcode.yaml +18 -0
  98. package/schemas/urlcode.schema.json +125 -60
  99. package/skills/urlcode/SKILL.md +47 -27
  100. package/starters/default/AGENTS.md +43 -43
  101. package/starters/page/README.md +14 -0
  102. package/starters/page/public/index.html +12 -0
  103. package/starters/page/tests/requests.json +17 -0
  104. package/starters/page/urlcode.yaml +6 -0
  105. package/.claude-plugin/marketplace.json +0 -18
  106. package/CONTRIBUTING.md +0 -148
  107. package/ROADMAP.md +0 -70
  108. package/docs/AI-AUTHORING.md +0 -339
  109. package/docs/ASSETS.md +0 -107
  110. package/docs/AUTH-BACKUP.md +0 -32
  111. package/docs/AWS.md +0 -86
  112. package/docs/BEST-PRACTICES.md +0 -276
  113. package/docs/BULK.md +0 -79
  114. package/docs/CAPABILITIES.md +0 -192
  115. package/docs/CAPACITY.md +0 -305
  116. package/docs/CI-FOLLOWUP-2026-09-19.md +0 -97
  117. package/docs/CI-RELEASE-AUDIT-2026-09-19.md +0 -322
  118. package/docs/CI.md +0 -147
  119. package/docs/CLOUDFLARE.md +0 -109
  120. package/docs/CODEBASE-AUDIT-2026-09-20.md +0 -284
  121. package/docs/COMPLIANCE.md +0 -239
  122. package/docs/COMPOSING-A-SITE.md +0 -287
  123. package/docs/CONDITIONS.md +0 -74
  124. package/docs/CONTAINER-PROMOTION.md +0 -74
  125. package/docs/DEPLOYMENT-CHECKS.md +0 -108
  126. package/docs/DEVELOPMENT-PIPELINE.md +0 -304
  127. package/docs/EGRESS.md +0 -125
  128. package/docs/EXTENSIONS.md +0 -403
  129. package/docs/FRAMEWORK.md +0 -217
  130. package/docs/FUNCTION-SECURITY.md +0 -251
  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 -149
  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 -153
  151. package/docs/README.md +0 -93
  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-0.4.2.md +0 -30
  156. package/docs/RELEASE-READINESS.md +0 -146
  157. package/docs/RELEASE-SECURITY.md +0 -100
  158. package/docs/RESILIENCE.md +0 -161
  159. package/docs/ROUTING.md +0 -92
  160. package/docs/SANDBOX-REVIEW.md +0 -72
  161. package/docs/SCAFFOLDING.md +0 -70
  162. package/docs/SECURITY-AUDIT.md +0 -164
  163. package/docs/SITE.md +0 -150
  164. package/docs/SPECIFICATION.md +0 -359
  165. package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +0 -288
  166. package/docs/SPIKE-BUSINESS-SUITE.md +0 -1029
  167. package/docs/SPIKE-CORE-LAYERING.md +0 -368
  168. package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +0 -207
  169. package/docs/STANDARDS.md +0 -311
  170. package/docs/STARTERS.md +0 -83
  171. package/docs/STATIC.md +0 -105
  172. package/docs/TOOLING.md +0 -298
  173. package/docs/TUNNELS.md +0 -72
  174. package/docs/TYPESCRIPT-AUTHORING.md +0 -87
  175. package/docs/TYPESCRIPT.md +0 -123
  176. package/docs/VERCEL.md +0 -114
  177. package/docs/VERSION-ALIGNMENT.md +0 -88
  178. package/docs/YAML-GUIDE.md +0 -57
  179. package/docs/YAML-REFERENCE.md +0 -449
  180. package/docs/archive/2026-09-19/EXTENSION-IMPLEMENTATION.md +0 -68
  181. package/docs/archive/2026-09-19/MANAGEMENT-SECURITY.md +0 -102
  182. package/docs/archive/2026-09-19/NEXT-PHASE-PLAN.md +0 -108
  183. package/docs/archive/2026-09-19/NEXT-STEPS.md +0 -646
  184. package/docs/archive/2026-09-19/OPEN-DECISIONS.md +0 -277
  185. package/docs/archive/2026-09-19/RELEASE-SECURITY.md +0 -186
  186. package/docs/archive/2026-09-19/ROADMAP.md +0 -387
  187. package/docs/archive/2026-09-19/SPIKE-EXTENSION-MODEL.md +0 -430
  188. package/docs/archive/2026-09-19/SPIKE-EXTENSIONS.md +0 -492
  189. package/docs/archive/2026-09-19/SPIKE-LAMBDA-COMPILE.md +0 -365
  190. package/docs/archive/2026-09-19/SPIKE-MONOREPO.md +0 -778
  191. package/docs/archive/2026-09-19/USABILITY-REVIEW.md +0 -139
  192. package/docs/archive/2026-09-20/OPEN-DECISIONS-COMPLETED.md +0 -116
  193. package/docs/archive/README.md +0 -29
  194. package/docs/policies/agents.md +0 -182
  195. package/docs/policies/cache.md +0 -152
  196. package/docs/policies/compression.md +0 -169
  197. package/docs/policies/contract.md +0 -52
  198. package/docs/policies/hardened.md +0 -56
  199. package/docs/policies/interoperability.md +0 -169
  200. package/docs/policies/operations.md +0 -45
  201. package/docs/policies/security.md +0 -161
  202. package/docs/policies/throttle.md +0 -103
  203. package/docs/yaml/assets.md +0 -36
  204. package/docs/yaml/conditions.md +0 -20
  205. package/docs/yaml/functions.md +0 -168
  206. package/docs/yaml/middleware.md +0 -31
  207. package/docs/yaml/organization.md +0 -74
  208. package/docs/yaml/policies.md +0 -37
  209. package/docs/yaml/redirects.md +0 -64
  210. package/docs/yaml/responses.md +0 -57
  211. package/docs/yaml/site.md +0 -24
  212. package/packaging/claude-plugin/.claude-plugin/plugin.json +0 -19
  213. package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +0 -130
  214. package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +0 -108
@@ -116,7 +116,7 @@
116
116
  },
117
117
  "site": {
118
118
  "type": "object",
119
- "description": "Site conventions. Each declared key generates one native route (robots.txt, sitemap.xml, favicon.ico, .well-known/security.txt, llms.txt); a declared route at the same path wins. Entry urlcode.yaml only.",
119
+ "description": "Site conventions. Each declared key generates one native route (robots.txt, sitemap.xml, favicon.ico, .well-known/security.txt, llms.txt, 404.html); a declared route at the same path wins. Entry urlcode.yaml only.",
120
120
  "properties": {
121
121
  "robots": {
122
122
  "type": "object",
@@ -279,6 +279,13 @@
279
279
  "minLength": 1,
280
280
  "maxLength": 1024,
281
281
  "description": "Project-relative text file served at /llms.txt."
282
+ },
283
+ "notFound": {
284
+ "type": "string",
285
+ "minLength": 1,
286
+ "maxLength": 1024,
287
+ "pattern": "\\.[hH][tT][mM][lL]?$",
288
+ "description": "Project-relative .html file served with status 404 and text/html for a GET or HEAD that matches no route. Generated as a page route at /404.html, which is also the object name static hosting uses."
282
289
  }
283
290
  },
284
291
  "additionalProperties": false
@@ -307,6 +314,26 @@
307
314
  "additionalProperties": false
308
315
  },
309
316
  "description": "Versioned logical extension configurations. Requires explicit external operator registrations pinned to the project revision; never loads project code."
317
+ },
318
+ "shared": {
319
+ "type": "object",
320
+ "description": "Reusable named request and response.headers blocks a route selects with use. Resolved at load time; the route hash, audit and routes output show the resolved route. Entry urlcode.yaml only. Response headers the runtime owns are refused.",
321
+ "maxProperties": 32,
322
+ "propertyNames": {
323
+ "pattern": "^[a-z][a-z0-9-]{0,63}$"
324
+ },
325
+ "additionalProperties": {
326
+ "type": "object",
327
+ "properties": {
328
+ "request": {
329
+ "$ref": "#/$defs/requestBlock"
330
+ },
331
+ "response": {
332
+ "$ref": "#/$defs/responseBlock"
333
+ }
334
+ },
335
+ "additionalProperties": false
336
+ }
310
337
  }
311
338
  },
312
339
  "required": [
@@ -351,6 +378,20 @@
351
378
  "maxLength": 500,
352
379
  "description": "Optional justification for this route's sandbox decision, whether sandbox is true or false: why it needs isolation, or why it is safe to trust. Never inferred or enforced; surfaced verbatim by explain/context/manifest."
353
380
  },
381
+ "coveredElsewhere": {
382
+ "type": "object",
383
+ "minProperties": 1,
384
+ "propertyNames": {
385
+ "enum": ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]
386
+ },
387
+ "additionalProperties": {
388
+ "type": "string",
389
+ "minLength": 1,
390
+ "maxLength": 500,
391
+ "description": "Why this method is tested elsewhere."
392
+ },
393
+ "description": "Audit-only waiver: methods of this route whose normal-response fixture is provided by other tests (for example stateful create/update/delete). Each method needs a non-empty reason and must be one of the route's methods. audit lists waived pairs with their reasons under waivedRouteMethods and still requires the route to have another normally covered method; it never hides a function route that only serves errors. Project file only: there is no CLI flag."
394
+ },
354
395
  "expires": {
355
396
  "type": "string"
356
397
  },
@@ -432,6 +473,16 @@
432
473
  "maximum": {
433
474
  "type": "number"
434
475
  },
476
+ "pattern": {
477
+ "type": "string",
478
+ "minLength": 1,
479
+ "maxLength": 128
480
+ },
481
+ "format": {
482
+ "enum": [
483
+ "uuid"
484
+ ]
485
+ },
435
486
  "items": {
436
487
  "type": "object",
437
488
  "properties": {
@@ -773,67 +824,10 @@
773
824
  "additionalProperties": false
774
825
  },
775
826
  "request": {
776
- "type": "object",
777
- "properties": {
778
- "body": {
779
- "type": "object",
780
- "properties": {
781
- "required": {
782
- "type": "boolean"
783
- },
784
- "maxBytes": {
785
- "type": "integer",
786
- "minimum": 0,
787
- "maximum": 1048576
788
- },
789
- "contentTypes": {
790
- "type": "array",
791
- "minItems": 1,
792
- "maxItems": 16,
793
- "uniqueItems": true,
794
- "items": {
795
- "type": "string",
796
- "pattern": "^[a-z0-9!#$&^_.+-]+/[a-z0-9!#$&^_.+-]+$"
797
- }
798
- },
799
- "format": {
800
- "enum": [
801
- "text",
802
- "json"
803
- ]
804
- }
805
- },
806
- "additionalProperties": false
807
- }
808
- },
809
- "additionalProperties": false
827
+ "$ref": "#/$defs/requestBlock"
810
828
  },
811
829
  "response": {
812
- "type": "object",
813
- "properties": {
814
- "headers": {
815
- "type": "object",
816
- "maxProperties": 64,
817
- "additionalProperties": {
818
- "oneOf": [
819
- {
820
- "type": "string",
821
- "maxLength": 4096
822
- },
823
- {
824
- "type": "array",
825
- "minItems": 1,
826
- "maxItems": 16,
827
- "items": {
828
- "type": "string",
829
- "maxLength": 4096
830
- }
831
- }
832
- ]
833
- }
834
- }
835
- },
836
- "additionalProperties": false
830
+ "$ref": "#/$defs/responseBlock"
837
831
  },
838
832
  "respond": {
839
833
  "type": "object",
@@ -942,6 +936,11 @@
942
936
  "cache": {
943
937
  "description": "Short form for policies.cache: the same object, expanded to policies.cache before anything else reads the project. Refused alongside policies.cache; use one form.",
944
938
  "$ref": "#/$defs/policyCache"
939
+ },
940
+ "use": {
941
+ "type": "string",
942
+ "pattern": "^[a-z][a-z0-9-]{0,63}$",
943
+ "description": "Name of a top-level shared block whose request and response.headers this route inherits. A key the route declares itself replaces the shared block as a whole; there is no deep merge."
945
944
  }
946
945
  },
947
946
  "required": [],
@@ -1774,6 +1773,72 @@
1774
1773
  "url"
1775
1774
  ],
1776
1775
  "additionalProperties": false
1776
+ },
1777
+ "requestBlock": {
1778
+ "type": "object",
1779
+ "properties": {
1780
+ "body": {
1781
+ "type": "object",
1782
+ "properties": {
1783
+ "required": {
1784
+ "type": "boolean"
1785
+ },
1786
+ "maxBytes": {
1787
+ "type": "integer",
1788
+ "minimum": 0,
1789
+ "maximum": 1048576
1790
+ },
1791
+ "contentTypes": {
1792
+ "type": "array",
1793
+ "minItems": 1,
1794
+ "maxItems": 16,
1795
+ "uniqueItems": true,
1796
+ "items": {
1797
+ "type": "string",
1798
+ "pattern": "^[a-z0-9!#$&^_.+-]+/[a-z0-9!#$&^_.+-]+$"
1799
+ }
1800
+ },
1801
+ "format": {
1802
+ "enum": [
1803
+ "text",
1804
+ "json"
1805
+ ]
1806
+ },
1807
+ "schema": {
1808
+ "type": "object"
1809
+ }
1810
+ },
1811
+ "additionalProperties": false
1812
+ }
1813
+ },
1814
+ "additionalProperties": false
1815
+ },
1816
+ "responseBlock": {
1817
+ "type": "object",
1818
+ "properties": {
1819
+ "headers": {
1820
+ "type": "object",
1821
+ "maxProperties": 64,
1822
+ "additionalProperties": {
1823
+ "oneOf": [
1824
+ {
1825
+ "type": "string",
1826
+ "maxLength": 4096
1827
+ },
1828
+ {
1829
+ "type": "array",
1830
+ "minItems": 1,
1831
+ "maxItems": 16,
1832
+ "items": {
1833
+ "type": "string",
1834
+ "maxLength": 4096
1835
+ }
1836
+ }
1837
+ ]
1838
+ }
1839
+ }
1840
+ },
1841
+ "additionalProperties": false
1777
1842
  }
1778
1843
  }
1779
1844
  }
@@ -5,19 +5,13 @@ description: Work on a URLCode project, recognized by a urlcode.yaml file with v
5
5
 
6
6
  # URLCode authoring loop
7
7
 
8
- A URLCode project declares URL behavior in YAML; the installed runtime serves
9
- it. Your job is to change the declaration and the minimal application code it names,
10
- then prove the change with the runtime's own checks. Never reimplement what the
11
- runtime provides, and never invent fields.
8
+ A URLCode project declares URL behavior in YAML; the installed runtime serves it. Change the declaration and minimal application code it names, then prove it with the runtime's own checks. Never reimplement what the runtime provides or invent fields.
12
9
 
13
10
  ## Declarative-first default
14
11
 
15
12
  > Use URLCode's highest-level declarative features whenever possible. Generate custom code only when the framework cannot express the requirement.
16
13
 
17
- Check the installed version's primitives, YAML configuration, policies, supported
18
- extensions and recipes/templates before writing a custom function or middleware.
19
- Keep necessary custom code focused and report the capability gap; never invent
20
- fields or bypass target limits or operator grants. See `docs/PROJECT-DIRECTION.md` in the installed runtime.
14
+ Check installed primitives, YAML configuration, policies, extensions and recipes/templates before writing custom code. Keep it focused and report the gap; never invent fields or bypass target limits or operator grants. Source checkouts have `docs/PROJECT-DIRECTION.md`; npm installations have it in `llms-full.txt`.
21
15
 
22
16
  ## 1. Recognize the project
23
17
 
@@ -33,21 +27,18 @@ fields or bypass target limits or operator grants. See `docs/PROJECT-DIRECTION.m
33
27
 
34
28
  ## 2. Retrieve the minimum, do not read everything
35
29
 
36
- If the project carries `.mcp.json` (written by `urlcode init`) and your client
37
- has registered the `urlcode` server, prefer its tools over reading documents:
38
- `get_context` (project summary, constraints, exact commands), `get_capability`
39
- and `get_schema` (one capability or YAML fragment), `search_recipes`,
40
- `explain` (a route's effective behavior) and `get_manifest`. The server is
41
- read-only; `--allow-authoring` is an operator opt-in you never add yourself.
30
+ **First step: one bounded query.** MCP `get_context` when the `urlcode` server is registered, otherwise `urlcode context --project DIR` (add `--budget N` to cap it). It returns a compact summary, constraints and exact commands, never a schema dump. Then retrieve only what the task needs: `capabilities NAME`/`get_capability` (its limits), `get_schema`, `recipes search`/`search_recipes`, `explain`, and `get_extensions` when an operator host file exists. The bare `urlcode capabilities` and `recipes list` catalogs, `llms.txt` and `llms-full.txt` are deliberate fallback/reference, not the opening move.
31
+
32
+ If the project carries `.mcp.json` (written by `urlcode init`) and your client has the `urlcode` server, prefer its tools: `get_context` (project summary, constraints, exact commands), `get_capability` and `get_schema` (one capability or YAML fragment), `search_recipes`, `search_examples`, `explain` (a route's effective behavior) and `get_manifest`. For framework discovery, use `list_skills` before `get_skill`, `search_docs` for a short package-owned excerpt, and `get_example` for one runnable example. Use `validate_yaml` for pasted YAML syntax/schema feedback only; use `validate` for the actual project. The server is read-only; `--allow-authoring` is an operator opt-in you never add yourself.
42
33
  When the MCP server was started with an operator host file, `get_extensions`
43
- returns installed extension configuration/policy schemas and declared project
44
- hook contracts. Otherwise use `urlcode extensions --project DIR --host-file
34
+ returns installed extension configuration/policy schemas, declared project
35
+ hook contracts, supported authoring surfaces and fast checks. Otherwise use `urlcode extensions --project DIR --host-file
45
36
  ABSOLUTE_HOST --json` when the operator has supplied that host file.
46
37
  Without the server, run the CLI equivalents and read only the output:
47
38
 
48
39
  ```sh
49
40
  urlcode context --project DIR # get_context: summary, constraints, commands
50
- urlcode capabilities # what this version implements, per target
41
+ urlcode capabilities # complete catalog (fallback, not step one)
51
42
  urlcode capabilities --target NAME # before promising a provider deployment
52
43
  urlcode capabilities NAME # get_capability: one capability's contract
53
44
  urlcode schema PATH # get_schema: one YAML fragment
@@ -61,9 +52,8 @@ urlcode routes --project DIR # the routes the project already has
61
52
 
62
53
  When a field or handler is unclear, ask the runtime, not memory:
63
54
  `urlcode validate --local` names the rejected field and the route. The
64
- installed package also ships `docs/YAML-REFERENCE.md` (generated field
65
- inventory) and `schemas/urlcode.schema.json`; search them for the one key you
66
- need rather than reading them whole.
55
+ installed package also ships `schemas/urlcode.schema.json` and the generated
56
+ field inventory in `llms-full.txt`; search only for the key you need.
67
57
 
68
58
  ## 3. Choose the highest-level supported abstraction
69
59
 
@@ -75,13 +65,12 @@ need rather than reading them whole.
75
65
  contract v1 runs trusted in-process and rejects `sandbox: true`. If a
76
66
  recipe from `recipes list` is close, `urlcode recipes add NAME --out DIR`
77
67
  and adapt the copy into the project's layout.
78
- 3. Only then write a function or middleware: one exported handler, inputs from validated `args`,
79
- output as a `Response`. `function`/`middleware` routes run trusted and
80
- unsandboxed by default: full Node, npm, filesystem and `fetch` access, like
81
- any other project code. Add `sandbox: true` only when that route's own code
82
- warrants isolation (unreviewed or third-party code, a secret whose blast
83
- radius matters, complex logic never merely because it handles request
84
- data, which is untrusted in both modes) — a `sandbox: true` route then has no
68
+ 3. Only then write a function or middleware: one exported handler, validated `args`,
69
+ and a `Response`. They run trusted and unsandboxed by default with Node, npm,
70
+ filesystem and `fetch` access. Use `sandbox: true` only when that route's own
71
+ code warrants isolation (unreviewed or third-party code, a secret whose blast
72
+ radius matters, complex logic not merely request data, which is untrusted in
73
+ both modes)a sandboxed route then has no
85
74
  `fetch`, Node, npm, filesystem, WebSocket, streaming or crypto APIs (bounded timers are supported);
86
75
  a need for those in a sandboxed route is a `proxy` route, a binding, or a
87
76
  report.
@@ -96,6 +85,28 @@ need rather than reading them whole.
96
85
  Keep every route you were not asked to change. Match the file organization the
97
86
  project already uses.
98
87
 
88
+ ## Build one application
89
+
90
+ Treat core routes, installed extensions and product UI as one application with
91
+ different owners. Core owns routing and policy mechanics; auth/admin own their
92
+ security and workflow behavior; the project owns its product pages, brand and
93
+ the smallest set of overrides that make it distinct.
94
+
95
+ For an installed extension, follow its `authoring` surfaces from
96
+ `get_extensions` in this order: configuration; theme and copy; component or
97
+ template override; project CSS; declared trusted hook. Build a new extension
98
+ only for a reusable capability the installed contracts do not provide. A visual
99
+ change is not a reason to fork core or copy an auth/admin flow.
100
+
101
+ For a React frontend with `components.json`, load the official shadcn/ui skill,
102
+ run `shadcn info --json`, then use its docs/search or MCP registry before
103
+ generating components. The URLCode skill still owns routing, extension and trust;
104
+ do not put React components in its shadcn-compatible server template renderer.
105
+
106
+ Use published `fastChecks` while iterating, then the full project checks before
107
+ handoff. Theme/copy should not rebuild framework packages; full workspace checks
108
+ may take several minutes, so let them finish instead of repeatedly rebuilding.
109
+
99
110
  ## 4. Prove it
100
111
 
101
112
  ```sh
@@ -124,3 +135,12 @@ the declaration rather than working around it.
124
135
  Do not invent fields, degrade silently or claim a workaround is equivalent.
125
136
  - Report the three commands' results as the evidence. They are not a
126
137
  deployment, a soak test or a security review.
138
+
139
+ ## 6. Leave evidence-backed feedback
140
+
141
+ After a real attempt, draft feedback only for a capability gap, repeated workaround,
142
+ documentation/discovery gap or suspected defect. Include the runtime/target, a
143
+ sanitized route/YAML fragment, exact validation or test observation, smallest expected
144
+ behavior and a proposed fixture. Exclude secrets, customer URLs, raw source and
145
+ one-off product logic; search existing issues for likely duplicates. A draft never
146
+ authorizes publishing: do not create or comment on a GitHub issue without explicit approval.
@@ -1,53 +1,55 @@
1
1
  # Working on this project
2
2
 
3
3
  This project uses URLCode: URL behavior is declared in `urlcode.yaml`, and the
4
- installed `@jimhoyd/urlcode` runtime serves it. There is no framework code to
5
- write for routing, validation, middleware wiring, policies, static serving or
6
- authentication; the runtime provides them. Read this file before changing anything.
4
+ installed runtime supplies routing, validation, middleware wiring, policies,
5
+ static serving and authentication. Read this file before changing anything.
7
6
 
8
7
  ## Before writing code
9
8
 
10
9
  1. Inspect `urlcode.yaml` first, then every file its `includes` list names,
11
- the referenced functions, middleware and `tests/requests.json`. Preserve the
12
- existing organization and every route you were not asked to change.
13
- 2. Run `urlcode capabilities` to see what this runtime version implements and
14
- which targets support it; `urlcode capabilities --target NAME` before
15
- promising any provider deployment.
16
- 3. Run `urlcode recipes list` and `urlcode recipes show NAME` before writing a
17
- route from scratch. If a recipe covers the need, add it with
18
- `urlcode recipes add NAME --out DIR` and adapt the copy.
10
+ referenced code and `tests/requests.json`. Preserve unrelated routes.
11
+ 2. Make one bounded query first: MCP `get_context` when the `urlcode` server is
12
+ registered, else `urlcode context --project DIR` (add `--budget N` to cap
13
+ it). It returns a compact summary, constraints and exact commands.
14
+ 3. Then retrieve only what the task needs: `capabilities NAME`/`get_capability`
15
+ (limits; `--target NAME` before promising a provider), `get_schema`,
16
+ `recipes search TEXT`/`search_recipes` then `recipes add NAME --out DIR`,
17
+ `explain` and, with an operator host file, `get_extensions`. Bare
18
+ `capabilities` and `recipes list` are complete catalogs: fallback, not step one.
19
19
  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.
20
20
 
21
- ## Ask the runtime through MCP first
21
+ ## MCP
22
22
 
23
- When present, `.mcp.json` registers the read-only `urlcode mcp` server. When it is
24
- available, prefer its tools over reading documents: `get_context`,
25
- `get_capability`, `get_schema`, `search_recipes`, `explain`, `get_manifest`.
26
- The CLI equivalents are the fallback: `urlcode context`, `urlcode capabilities NAME`,
27
- `urlcode schema PATH`, `urlcode recipes search TEXT`, `urlcode explain PATH`,
28
- `urlcode manifest`. `--allow-authoring` is an operator opt-in; never add it yourself.
23
+ When present, `.mcp.json` registers the read-only `urlcode mcp` server; prefer its
24
+ tools (also `get_manifest`) to reading documents. Inspect `get_extensions` before
25
+ replacing extension behavior. `--allow-authoring` is an operator opt-in; never add it.
29
26
 
30
27
  ## What the runtime provides (this version)
31
28
 
32
29
  - Handlers, exactly one per route: `redirect`, `respond`, `page`, `static`, `download`, `function`, `proxy`, `conditional`.
33
30
  - Ordered `middleware` around any handler, declared in YAML, trusted by default.
34
- - Validated inputs: `parameters`, `request.body` and `methods` on the route;
35
- functions receive validated `args`, never raw user input.
31
+ - Validated route `parameters`, `request.body`, `methods` and function `args`.
36
32
  - Policies, host-enforced and off by default: `agents`, `throttle`, `cache`, `security`, `compression`.
37
- - Site conventions under `site`, each generating one native route: `robots` (/robots.txt), `sitemap` (/sitemap.xml), `favicon` (/favicon.ico), `securityTxt` (/.well-known/security.txt), `llms` (/llms.txt).
33
+ - Site conventions under `site`, each generating one native route: `robots` (/robots.txt), `sitemap` (/sitemap.xml), `favicon` (/favicon.ico), `securityTxt` (/.well-known/security.txt), `llms` (/llms.txt), `notFound` (/404.html).
38
34
  - Bindings: named `env` and `secrets` references resolved by the operator, never values in YAML.
39
35
 
40
- Never recreate any of these in a function; a missing one is a report, not an
41
- invitation to reimplement it.
36
+ Never recreate these in a function; report a missing capability.
37
+
38
+ ## Build one application
39
+
40
+ Treat routes, extensions and UI as one application with different owners. Use
41
+ published surfaces in order: configuration/theme/copy, smallest template, CSS,
42
+ then a declared hook. Keep auth/admin security and workflows package-owned; add
43
+ an extension only for a reusable missing capability. Use the official shadcn/ui
44
+ skill only in a React frontend with `components.json`; start with `shadcn info
45
+ --json`. Do not put React components in the server renderer.
42
46
 
43
47
  ## Functions and middleware are trusted by default; sandbox is opt-in
44
48
 
45
- A route's `function`/`middleware` runs trusted, in-process, with full
46
- Node/filesystem/`fetch` access, given only declared `args`/`env`/`secrets`. Add
47
- `sandbox: true` when that code warrants isolation (unreviewed code, a sensitive
48
- secret, complex logic) not merely for untrusted input, which both modes share.
49
- A `sandbox: true` route gets a text/JSON subset only: use `proxy`/a binding, and
50
- say why in `sandboxReason`.
49
+ A `function`/`middleware` is trusted, in-process Node with only declared
50
+ `args`/`env`/`secrets`. Add `sandbox: true` for code needing isolation, not
51
+ merely untrusted input. The sandbox is text/JSON-only; use `proxy`/a binding and
52
+ record the reason in `sandboxReason`.
51
53
 
52
54
  ## Checks that count as evidence
53
55
 
@@ -57,23 +59,21 @@ urlcode test
57
59
  urlcode audit --expect-routes 2
58
60
  ```
59
61
 
60
- Run all three after every change, updating the route count deliberately and
61
- adding `tests/requests.json` fixtures for every new route (positive/negative,
62
- every active method, HEAD). No global install: use `node /path/to/urlcode/src/cli.ts`.
62
+ 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`.
63
+
64
+ ## Feedback
65
+
66
+ 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.
63
67
 
64
68
  ## Rules
65
69
 
66
- - Report unsupported requirements instead of inventing fields. The schema is
67
- exact; a field the validator rejects does not exist. Say what is missing.
68
- - Never create or approve operator grants. Request a named binding in YAML and
69
- stop; the operator grants it outside this project, pinned to the revision.
70
- - Secrets stay out of the project: no keys, tokens or credentials in YAML,
71
- functions, fixtures, `.env` files that are not ignored, or commit messages.
70
+ - Report unsupported requirements; a field the exact schema rejects does not exist.
71
+ - Never create operator grants. Request a named binding; the operator grants it
72
+ outside the project, pinned to the revision.
73
+ - Keep keys, tokens and credentials out of project files and commit messages.
72
74
  - Protect a route with `auth: true`/`auth: { role: admin }` where an `auth`
73
75
  extension is declared; `cache` likewise expands to `policies.cache`.
74
- - Validation, tests and the audit are the evidence. Local checks are not a
75
- deployment, a soak test or a security review; do not claim otherwise.
76
+ - Local checks are not deployment, soak or independent security evidence.
76
77
 
77
- The installed package ships an agent skill with the same loop at
78
- `skills/urlcode/SKILL.md` inside `@jimhoyd/urlcode` (for example
79
- `node_modules/@jimhoyd/urlcode/skills/urlcode/SKILL.md`).
78
+ The installed package ships the same loop at `skills/urlcode/SKILL.md` inside
79
+ `@jimhoyd/urlcode` (for example `node_modules/@jimhoyd/urlcode/skills/urlcode/SKILL.md`).
@@ -0,0 +1,14 @@
1
+ # Your URLCode page
2
+
3
+ The smallest project: one route that serves `public/index.html`.
4
+ Created with `urlcode init <dir> --template page`.
5
+
6
+ ```sh
7
+ urlcode validate --local
8
+ urlcode test
9
+ urlcode dev # http://127.0.0.1:3000/
10
+ ```
11
+
12
+ Edit `public/index.html`. Add more pages, a `static` directory, downloads,
13
+ redirects or functions as routes in `urlcode.yaml` (see docs/ASSETS.md in the
14
+ URLCode repository). Keep `tests/requests.json` in step with the routes.
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Hello, URLCode</title>
7
+ </head>
8
+ <body>
9
+ <h1>Hello, URLCode</h1>
10
+ <p>This page is served by a page route in urlcode.yaml.</p>
11
+ </body>
12
+ </html>
@@ -0,0 +1,17 @@
1
+ [
2
+ {
3
+ "path": "/",
4
+ "status": 200,
5
+ "expectBody": "<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Hello, URLCode</title>\n</head>\n<body>\n<h1>Hello, URLCode</h1>\n<p>This page is served by a page route in urlcode.yaml.</p>\n</body>\n</html>\n"
6
+ },
7
+ {
8
+ "path": "/",
9
+ "method": "HEAD",
10
+ "status": 200,
11
+ "expectBody": ""
12
+ },
13
+ {
14
+ "path": "/missing",
15
+ "status": 404
16
+ }
17
+ ]
@@ -0,0 +1,6 @@
1
+ version: "1"
2
+ routes:
3
+ /:
4
+ description: The home page, served from a file. Add routes beside it as the project grows.
5
+ page:
6
+ file: public/index.html
@@ -1,18 +0,0 @@
1
- {
2
- "name": "urlcode",
3
- "owner": {
4
- "name": "jimhoyd-com",
5
- "url": "https://github.com/jimhoyd-com"
6
- },
7
- "metadata": {
8
- "description": "Claude plugins published from the URLCode repository.",
9
- "version": "0.4.2"
10
- },
11
- "plugins": [
12
- {
13
- "name": "urlcode",
14
- "source": "./packaging/claude-plugin",
15
- "description": "Authoring and operating URLCode projects: the implemented YAML contract, capability limits, deployment and verification commands for the pinned runtime revision."
16
- }
17
- ]
18
- }