@jimhoyd/urlcode 0.4.0-alpha.1 → 0.4.0-alpha.3

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 (232) hide show
  1. package/.claude/skills/urlcode-authoring/SKILL.md +36 -22
  2. package/.claude/skills/urlcode-operations/SKILL.md +16 -22
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CONTRIBUTING.md +20 -16
  5. package/README.md +83 -80
  6. package/ROADMAP.md +61 -331
  7. package/SECURITY.md +23 -8
  8. package/dist/BUILD-MANIFEST.json +42 -47
  9. package/dist/agents-guide.js +18 -18
  10. package/dist/build-static.js +136 -0
  11. package/dist/capabilities.js +85 -31
  12. package/dist/capability-query.js +0 -1
  13. package/dist/cli.js +24 -32
  14. package/dist/compliance-rules/baseline.js +2 -10
  15. package/dist/compliance-rules/privacy.js +5 -16
  16. package/dist/compliance-rules/shared.js +0 -2
  17. package/dist/compliance.js +6 -8
  18. package/dist/config.js +15 -8
  19. package/dist/context.js +9 -10
  20. package/dist/examples.js +2 -2
  21. package/dist/explain-cli.js +7 -5
  22. package/dist/explain.js +10 -5
  23. package/dist/extensions.js +61 -2
  24. package/dist/function-sources.js +34 -2
  25. package/dist/function-worker.js +3 -1
  26. package/dist/functions.js +84 -13
  27. package/dist/guest-api.js +29 -3
  28. package/dist/index.js +3 -6
  29. package/dist/manifest.js +11 -7
  30. package/dist/mcp-authoring.js +2 -2
  31. package/dist/mcp.js +1 -1
  32. package/dist/observability.js +1 -21
  33. package/dist/policies/cache.js +8 -3
  34. package/dist/policies.js +3 -1
  35. package/dist/policy.js +28 -9
  36. package/dist/prerender.js +4 -0
  37. package/dist/project-tests.js +3 -3
  38. package/dist/readiness.js +35 -9
  39. package/dist/route-diff.js +12 -5
  40. package/dist/router.js +5 -7
  41. package/dist/runtime.js +77 -58
  42. package/dist/sandbox.js +48 -0
  43. package/dist/scaffold.js +0 -0
  44. package/dist/scripts/operational-drills.js +12 -54
  45. package/dist/server.js +3 -29
  46. package/dist/tooling.js +1 -1
  47. package/dist/trusted-functions.js +210 -0
  48. package/dist/types/build-static.d.ts +43 -0
  49. package/dist/types/capabilities.d.ts +14 -5
  50. package/dist/types/compliance-rules/shared.d.ts +0 -2
  51. package/dist/types/compliance.d.ts +0 -3
  52. package/dist/types/config.d.ts +2 -1
  53. package/dist/types/context.d.ts +2 -1
  54. package/dist/types/examples.d.ts +1 -1
  55. package/dist/types/explain.d.ts +6 -0
  56. package/dist/types/extensions.d.ts +55 -0
  57. package/dist/types/function-sources.d.ts +4 -0
  58. package/dist/types/functions.d.ts +48 -5
  59. package/dist/types/guest-api.d.ts +1 -0
  60. package/dist/types/index.d.ts +3 -6
  61. package/dist/types/manifest.d.ts +5 -3
  62. package/dist/types/observability.d.ts +1 -14
  63. package/dist/types/project-tests.d.ts +1 -2
  64. package/dist/types/readiness.d.ts +12 -3
  65. package/dist/types/router.d.ts +2 -1
  66. package/dist/types/runtime.d.ts +0 -27
  67. package/dist/types/sandbox.d.ts +12 -0
  68. package/dist/types/scaffold.d.ts +0 -2
  69. package/dist/types/server.d.ts +1 -4
  70. package/dist/types/tooling.d.ts +3 -3
  71. package/dist/types/trusted-functions.d.ts +29 -0
  72. package/dist/types/types.d.ts +22 -8
  73. package/dist/types/verify-deployment.d.ts +2 -2
  74. package/dist/types.js +25 -5
  75. package/dist/typescript-authoring.js +67 -18
  76. package/dist/verify-deployment.js +3 -3
  77. package/docs/AI-AUTHORING.md +109 -10
  78. package/docs/ASSETS.md +2 -1
  79. package/docs/AUTH-BACKUP.md +32 -0
  80. package/docs/AWS.md +4 -4
  81. package/docs/BEST-PRACTICES.md +17 -8
  82. package/docs/CAPABILITIES.md +30 -17
  83. package/docs/CAPACITY.md +128 -31
  84. package/docs/CI-FOLLOWUP-2026-09-19.md +97 -0
  85. package/docs/CI-RELEASE-AUDIT-2026-09-19.md +322 -0
  86. package/docs/CI.md +8 -3
  87. package/docs/CLOUDFLARE.md +1 -2
  88. package/docs/CODEBASE-AUDIT-2026-09-20.md +278 -0
  89. package/docs/COMPLIANCE.md +6 -9
  90. package/docs/DEPLOYMENT-CHECKS.md +1 -1
  91. package/docs/DEVELOPMENT-PIPELINE.md +181 -0
  92. package/docs/EXTENSIONS.md +193 -11
  93. package/docs/FRAMEWORK.md +53 -33
  94. package/docs/FUNCTION-SECURITY.md +173 -32
  95. package/docs/INSTALL.md +0 -5
  96. package/docs/LOAD-TESTING.md +4 -4
  97. package/docs/LOCAL-DEVELOPMENT.md +3 -0
  98. package/docs/MIDDLEWARE.md +27 -16
  99. package/docs/MONITORING.md +2 -19
  100. package/docs/OBSERVABILITY.md +7 -16
  101. package/docs/OPEN-DECISIONS.md +184 -0
  102. package/docs/OPERATIONAL-PROOF.md +26 -30
  103. package/docs/OPERATIONS.md +23 -32
  104. package/docs/POLICIES.md +27 -8
  105. package/docs/PRERENDER.md +25 -13
  106. package/docs/PROJECT-DIRECTION.md +35 -10
  107. package/docs/READINESS.md +6 -2
  108. package/docs/README.md +20 -41
  109. package/docs/RELEASE-0.4.0-alpha.3.md +50 -0
  110. package/docs/RELEASE-READINESS.md +50 -30
  111. package/docs/RELEASE-SECURITY.md +72 -86
  112. package/docs/RESILIENCE.md +16 -15
  113. package/docs/ROUTING.md +7 -10
  114. package/docs/SANDBOX-REVIEW.md +19 -6
  115. package/docs/SCAFFOLDING.md +0 -2
  116. package/docs/SECURITY-AUDIT.md +42 -2
  117. package/docs/SPECIFICATION.md +63 -27
  118. package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +288 -0
  119. package/docs/SPIKE-BUSINESS-SUITE.md +16 -0
  120. package/docs/SPIKE-CORE-LAYERING.md +368 -0
  121. package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +211 -0
  122. package/docs/SPIKE-LAMBDA-COMPILE.md +12 -2
  123. package/docs/STARTERS.md +1 -1
  124. package/docs/STATIC.md +105 -0
  125. package/docs/TOOLING.md +17 -12
  126. package/docs/TUNNELS.md +0 -3
  127. package/docs/TYPESCRIPT-AUTHORING.md +32 -12
  128. package/docs/TYPESCRIPT.md +25 -4
  129. package/docs/VERCEL.md +4 -5
  130. package/docs/VERSION-ALIGNMENT.md +46 -0
  131. package/docs/YAML-GUIDE.md +0 -3
  132. package/docs/YAML-REFERENCE.md +16 -6
  133. package/docs/archive/2026-09-19/EXTENSION-IMPLEMENTATION.md +68 -0
  134. package/docs/{MANAGEMENT-SECURITY.md → archive/2026-09-19/MANAGEMENT-SECURITY.md} +20 -0
  135. package/docs/{NEXT-PHASE-PLAN.md → archive/2026-09-19/NEXT-PHASE-PLAN.md} +26 -8
  136. package/docs/{NEXT-STEPS.md → archive/2026-09-19/NEXT-STEPS.md} +274 -43
  137. package/docs/archive/2026-09-19/OPEN-DECISIONS.md +277 -0
  138. package/docs/archive/2026-09-19/RELEASE-SECURITY.md +186 -0
  139. package/docs/archive/2026-09-19/ROADMAP.md +386 -0
  140. package/docs/{SPIKE-EXTENSION-MODEL.md → archive/2026-09-19/SPIKE-EXTENSION-MODEL.md} +12 -2
  141. package/docs/{SPIKE-EXTENSIONS.md → archive/2026-09-19/SPIKE-EXTENSIONS.md} +28 -12
  142. package/docs/archive/2026-09-19/SPIKE-MONOREPO.md +776 -0
  143. package/docs/{USABILITY-REVIEW.md → archive/2026-09-19/USABILITY-REVIEW.md} +18 -2
  144. package/docs/archive/README.md +27 -0
  145. package/docs/policies/agents.md +1 -1
  146. package/docs/policies/cache.md +13 -0
  147. package/docs/policies/compression.md +3 -2
  148. package/docs/policies/security.md +3 -2
  149. package/examples/assets/example.yaml +2 -2
  150. package/examples/aws/example.yaml +1 -1
  151. package/examples/cloudflare/example.yaml +1 -1
  152. package/examples/conditions/example.yaml +1 -1
  153. package/examples/cookbook/example.yaml +1 -1
  154. package/examples/cookbook/middleware/bucket.mjs +12 -2
  155. package/examples/cookbook/middleware/locale.mjs +7 -3
  156. package/examples/cookbook/route-index.json +1 -1
  157. package/examples/cookbook/routes/middleware.yaml +1 -1
  158. package/examples/egress/example.yaml +1 -1
  159. package/examples/extensions/example.yaml +1 -1
  160. package/examples/prerender/README.md +14 -6
  161. package/examples/prerender/example.yaml +1 -1
  162. package/examples/prerender/functions/page.mjs +4 -2
  163. package/examples/prerender/middleware/template.mjs +1 -1
  164. package/examples/prerender/prerender.mjs +1 -1
  165. package/examples/prerender/urlcode.yaml +8 -4
  166. package/examples/provider-conformance/example.yaml +1 -1
  167. package/examples/vercel/example.yaml +1 -1
  168. package/llms-full.txt +686 -239
  169. package/llms.txt +27 -15
  170. package/package.json +32 -5
  171. package/packaging/claude-plugin/.claude-plugin/plugin.json +2 -2
  172. package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +36 -22
  173. package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +16 -22
  174. package/recipes/authenticated-json-api/README.md +4 -3
  175. package/recipes/authenticated-json-api/functions/profile.mjs +2 -1
  176. package/recipes/authenticated-json-api/recipe.yaml +2 -2
  177. package/recipes/contact-form/functions/contact.mjs +2 -1
  178. package/recipes/contact-form/recipe.yaml +3 -3
  179. package/recipes/cors-api/README.md +2 -2
  180. package/recipes/cors-api/recipe.yaml +2 -2
  181. package/recipes/health-page/README.md +1 -1
  182. package/recipes/health-page/recipe.yaml +1 -1
  183. package/recipes/json-api/README.md +1 -1
  184. package/recipes/json-api/recipe.yaml +4 -4
  185. package/recipes/middleware/README.md +8 -4
  186. package/recipes/middleware/middleware/bucket.mjs +12 -2
  187. package/recipes/middleware/middleware/locale.mjs +7 -3
  188. package/recipes/middleware/recipe.yaml +1 -1
  189. package/recipes/protected-download/README.md +1 -1
  190. package/recipes/protected-download/recipe.yaml +2 -2
  191. package/recipes/redirect/recipe.yaml +1 -1
  192. package/recipes/static-plus-api/README.md +2 -2
  193. package/recipes/static-plus-api/public/index.html +1 -1
  194. package/recipes/static-plus-api/recipe.yaml +2 -2
  195. package/recipes/static-plus-api/urlcode.yaml +1 -1
  196. package/recipes/typescript/README.md +2 -1
  197. package/recipes/typescript/recipe.yaml +5 -5
  198. package/recipes/webhook-receiver/README.md +5 -1
  199. package/recipes/webhook-receiver/recipe.yaml +2 -1
  200. package/recipes/webhook-receiver/urlcode.yaml +7 -0
  201. package/schemas/recipe.schema.json +4 -3
  202. package/schemas/urlcode.schema.json +14 -41
  203. package/skills/urlcode/SKILL.md +32 -11
  204. package/starters/default/AGENTS.md +18 -18
  205. package/starters/default/urlcode.yaml +0 -1
  206. package/dist/link-api.js +0 -136
  207. package/dist/link-cli.js +0 -141
  208. package/dist/link-events.js +0 -76
  209. package/dist/link-records.js +0 -31
  210. package/dist/link-store-worker.js +0 -150
  211. package/dist/link-store.js +0 -250
  212. package/dist/management-policy.js +0 -40
  213. package/dist/sqlite-version.js +0 -6
  214. package/dist/types/link-api.d.ts +0 -30
  215. package/dist/types/link-cli.d.ts +0 -37
  216. package/dist/types/link-events.d.ts +0 -27
  217. package/dist/types/link-records.d.ts +0 -11
  218. package/dist/types/link-store-worker.d.ts +0 -1
  219. package/dist/types/link-store.d.ts +0 -130
  220. package/dist/types/management-policy.d.ts +0 -8
  221. package/dist/types/sqlite-version.d.ts +0 -1
  222. package/docs/DYNAMIC-LINKS.md +0 -61
  223. package/docs/links/cli.md +0 -110
  224. package/docs/links/limits.md +0 -175
  225. package/docs/links/management-api.md +0 -80
  226. package/docs/links/pools.md +0 -75
  227. package/docs/links/setup.md +0 -135
  228. package/docs/yaml/links.md +0 -30
  229. package/examples/live-links/README.md +0 -11
  230. package/examples/live-links/example.yaml +0 -21
  231. package/examples/live-links/tests/requests.json +0 -6
  232. package/examples/live-links/urlcode.yaml +0 -16
@@ -1,10 +1,20 @@
1
+ # Historical record
2
+
3
+ Archived 2026-09-19. This records an earlier implementation or proposal, not
4
+ current instructions. See the [current roadmap](../../../ROADMAP.md),
5
+ [current contract](../../SPECIFICATION.md) and [open decisions](../../OPEN-DECISIONS.md).
6
+ Remaining acceptance work is not declared complete by archiving this record.
7
+
8
+ <!-- trust-model-prose: historical-file -->
9
+ <!-- guidance-claims: ignore-file -->
10
+
1
11
  # Next steps: closing the gaps
2
12
 
3
13
  Status: plan written 2026-09-18 from the cleanup, the
4
14
  [usability review](USABILITY-REVIEW.md) and the AI-first framework brief.
5
15
  Each item says what it fixes, where the work is, how it is proven, and its
6
16
  size (S: a day, M: a week, L: more). Phases can overlap; order inside a phase
7
- is the recommended sequence. The [roadmap](../ROADMAP.md) owns what ships;
17
+ is the recommended sequence. The [roadmap](ROADMAP.md) owns what ships;
8
18
  this page owns how the gaps close.
9
19
 
10
20
  ## The rule everything below serves
@@ -16,7 +26,7 @@ policies, admin patterns and deployment glue on every project, and the person
16
26
  ends up owning it. URLCode's job is a small, deterministic, portable vocabulary
17
27
  in readable YAML, so generated code goes to the part that is the application.
18
28
  The agent describes what; the runtime owns how. The three tests that decide
19
- what gets built are in [project direction](PROJECT-DIRECTION.md#why-your-ai-should-build-your-application-not-your-framework):
29
+ what gets built are in [project direction](../../PROJECT-DIRECTION.md#why-your-ai-should-build-your-application-not-your-framework):
20
30
  the boundary test (do agents generate this across unrelated projects?), the
21
31
  feature test (does it reduce what the agent must know, generate, debug or
22
32
  maintain?) and the evidence test (measured repetition, not a feature list).
@@ -24,14 +34,41 @@ maintain?) and the evidence test (measured repetition, not a feature list).
24
34
  The order below follows from that. **Prove the thesis before building on
25
35
  it.** Phase 0 is the benchmark; if it shows a large saving, the rest is worth
26
36
  the work, and if it shows a small one, the abstraction is not doing enough yet
27
- and the next phases change. Nothing here weakens the security model: guest
28
- code stays untrusted, grants stay operator-owned, agents cannot self-authorize,
29
- unsupported behavior fails with the route named, and inspection tooling never
30
- becomes a privilege escalation path.
37
+ and the next phases change. Nothing here weakens the security model: a
38
+ `sandbox: true` route's isolation stays exactly as strict, grants stay
39
+ operator-owned regardless of a route's trust setting, agents cannot
40
+ self-authorize, unsupported behavior fails with the route named, and
41
+ inspection tooling never becomes a privilege escalation path.
42
+
43
+ **Status 2026-09-19 (sequence).** Most of Phases 1, 3 and 4 landed before the
44
+ Phase 0 benchmark produced a single model-backed run. The instrument is built
45
+ and tested (`benchmarks/agent/harness.ts`, `benchmarks/agent/count-lines.ts`,
46
+ `benchmarks/agent/adapters/anthropic.ts`), but `benchmarks/agent/runs/` holds
47
+ only `baseline.json`, a stub record, so the application-specific code ratio is
48
+ still unmeasured and the re-prioritization 0.1 describes has never been
49
+ exercised. This is an observation about the order the work happened in, not a
50
+ change of priorities: Phase 0 still owns the evidence, and Phase 5 is still how
51
+ each shipped phase gets measured. Items below are marked from the source at this
52
+ revision.
31
53
 
32
54
  ## Phase 0: prove the thesis (M, core `benchmarks/agent/`, before anything else)
33
55
 
34
- ### 0.1 The agent benchmark
56
+ ### 0.1 The agent benchmark — partly done
57
+
58
+ Done 2026-09-19, the instrument only: the runner, the counting rule, the tasks
59
+ and the storage format exist and are tested — `benchmarks/agent/harness.ts`
60
+ (`runArm`, `summarize`, `securityChecklist`, `writeRun`),
61
+ `benchmarks/agent/count-lines.ts` (`classify`, `codeRatio`),
62
+ `benchmarks/agent/adapters.ts` (`selectAdapter`, `stubAdapter`) with
63
+ `benchmarks/agent/adapters/anthropic.ts`, ten task directories under
64
+ `benchmarks/agent/tasks/`, both arm preambles under `benchmarks/agent/prompts/`,
65
+ `npm run benchmark:agent`, and `test/agent-benchmark.test.ts` ("the counting
66
+ rule: functions and declared modules are the idea, everything else is
67
+ plumbing"). The measurement is not done: `benchmarks/agent/runs/` holds only
68
+ `baseline.json`, whose `model` is `stub`, and `benchmarks/agent/README.md`
69
+ states that no number there is evidence until a stored run with a real model
70
+ adapter backs it. Running the tasks in both arms against a real model, storing
71
+ the runs and publishing only what they support remains the work below.
35
72
 
36
73
  Fixes: there is no evidence that URLCode saves agent effort, and the whole
37
74
  plan depends on it.
@@ -61,7 +98,16 @@ plan depends on it.
61
98
  too small or too hard to discover, and Phases 1, 3 and 4 are re-prioritized
62
99
  from what the runs show the agent still had to write.
63
100
 
64
- ### 0.2 Authoring regression evals (S, once 0.1 exists)
101
+ ### 0.2 Authoring regression evals (S, once 0.1 exists) — done
102
+
103
+ Done 2026-09-19: the five prompts are `benchmarks/agent/evals/*.yaml`
104
+ (`add-redirect`, `add-authenticated-endpoint`, `serve-directory`,
105
+ `add-middleware`, `create-webhook-endpoint`), scored against the eight criteria
106
+ by `scoreEval` and `summarizeEvals` in `benchmarks/agent/harness.ts`, gated
107
+ against `benchmarks/agent/runs/baseline.json` by `benchmarks/agent/gate.ts`, and
108
+ run weekly by `.github/workflows/evals.yml`. Caveat: the committed baseline is a
109
+ stub record and the scheduled job skips cleanly when no model key is configured,
110
+ so the recorded pass rate proves the pipeline, not a model's behavior.
65
111
 
66
112
  Prompts for common requests ("add a redirect", "add an authenticated
67
113
  endpoint", "serve this directory", "add middleware", "create a webhook
@@ -80,7 +126,17 @@ read-side tools (`inspectProject`, `validateProject`, `explainRoute`,
80
126
  Keep all of it. The gap is that an agent still has to read documents to find
81
127
  facts the runtime already knows.
82
128
 
83
- ### 1.1 Application-level `AGENTS.md` from `urlcode init` (S, core)
129
+ ### 1.1 Application-level `AGENTS.md` from `urlcode init` (S, core) — done
130
+
131
+ Done 2026-09-19: `renderAgentsGuide` in `src/agents-guide.ts` generates the file
132
+ from the installed capability catalog, `initProject` in `src/authoring.ts`
133
+ writes it, and `initProjectWith` in `src/init-with.ts` calls `initProject`, so
134
+ `init --with` writes it into the project directory too; `renderMcpConfig` writes
135
+ `.mcp.json` beside it. `test/cli.test.ts` asserts the commands, the packaged
136
+ skill path and the MCP tool names the file lists, its length bound, and that the
137
+ committed `starters/default/AGENTS.md` equals what `init` generates from this
138
+ runtime. Caveat: the public `urlcode-template` copy is outside this repository
139
+ and is not checked here; `npm run check:downstream-skills` stays advisory.
84
140
 
85
141
  Fixes: a project made with URLCode is not self-describing to Claude Code,
86
142
  Codex or any repository-aware agent. Today's `AGENTS.md` explains how to work
@@ -97,14 +153,22 @@ on the runtime, not on an application.
97
153
  - Proof: starter test asserts the file exists and lists the commands; the
98
154
  public `urlcode-template` gets the same file.
99
155
 
100
- ### 1.2 `llms-full.txt` and clean Markdown for the docs site (S, core; S, urlcode-docs)
156
+ ### 1.2 `llms-full.txt` and clean Markdown for the docs site (S, core; S, urlcode-docs) — partly done
157
+
158
+ Done 2026-09-19, the core side: `scripts/build-llms-full.ts` generates
159
+ `llms-full.txt` from 15 authoring documents in reading order with a table of
160
+ contents and a token estimate in the file header, `npm run check` runs it with
161
+ `--check`, and `test/llms-full.test.ts` covers determinism, rejection of a stale
162
+ copy and the conservative link rewriting. The docs-site half is not done here:
163
+ serving `/docs/<page>.md` beside `/docs/<page>` belongs to `urlcode-docs` and is
164
+ not verifiable from this repository.
101
165
 
102
166
  Fixes: `llms.txt` must stay a compact index, but an agent that wants complete
103
167
  context has to fetch forty files.
104
168
 
105
169
  - Work: `scripts/build-llms-full.ts` concatenates the authoring documents
106
170
  (framework, AI authoring, YAML guide, field reference, specification,
107
- routing, HTTP, middleware, assets, dynamic links, policies, extensions) in
171
+ routing, HTTP, middleware, assets, policies, extensions) in
108
172
  reading order with a table of contents; checked in `npm run check` for
109
173
  staleness like the field reference. The docs site serves `/docs/<page>.md`
110
174
  beside `/docs/<page>` so agents never parse HTML. Do not adopt `agents.txt`
@@ -112,7 +176,16 @@ context has to fetch forty files.
112
176
  - Proof: `npm run check` fails on a stale `llms-full.txt`; token estimate
113
177
  recorded in the file header.
114
178
 
115
- ### 1.3 `urlcode context` with a token budget (M, core)
179
+ ### 1.3 `urlcode context` with a token budget (M, core) — done
180
+
181
+ Done 2026-09-19: `urlcode context [--project] [--budget] [--json] [--stats]` in
182
+ `src/cli.ts` over `buildContext`, `renderContext`, `estimateTokens` and
183
+ `documentationTokens` in `src/context.ts`, derived from the compiled project and
184
+ the capability catalog; `--stats` writes the estimate to stderr so stdout stays
185
+ parseable. `test/context.test.ts` covers the cookbook and starter summaries,
186
+ byte-identical output across runs, the fixed budget drop order with the estimate
187
+ never exceeded, the CLI's YAML and JSON forms, and MCP `get_context`
188
+ (`src/mcp.ts`) returning the same data read-only.
116
189
 
117
190
  Fixes: the central gap. An agent needs a handful of facts about this project
118
191
  and this runtime and spends tens of thousands of tokens reading documentation
@@ -136,7 +209,17 @@ to get them.
136
209
  same project yields byte-identical output twice; budget test that output
137
210
  never exceeds the estimate; MCP tool `get_context` returns the same data.
138
211
 
139
- ### 1.4 Capability and schema fragment queries (M, core)
212
+ ### 1.4 Capability and schema fragment queries (M, core) — done
213
+
214
+ Done 2026-09-19: `urlcode capabilities <name>` and `urlcode schema <path>` in
215
+ `src/cli.ts` over `getCapability` in `src/capability-query.ts` and
216
+ `getSchemaFragment`/`schemaPathNames` in `src/schema-query.ts`, both re-exported
217
+ from `src/tooling.ts` and served as MCP `get_capability` and `get_schema`
218
+ (`src/mcp.ts`). `test/capability-query.test.ts` asserts that every catalog name
219
+ resolves with a valid, size-bounded fragment, that every schema path yields a
220
+ valid inline fragment and an unknown path lists the valid names, that entries
221
+ report bundled usage, grants and refusals from existing data, and that the CLI
222
+ fails closed on unknown names.
140
223
 
141
224
  Fixes: `urlcode capabilities` reports target support per handler; an agent
142
225
  cannot ask "what does `throttle` accept, where does it run, which recipe
@@ -152,7 +235,15 @@ shows it" or "give me only the schema for `redirect`".
152
235
  - Proof: a test that every capability name resolves and every fragment is
153
236
  valid JSON Schema; a size test that no fragment exceeds a fixed byte cap.
154
237
 
155
- ### 1.5 The URLCode agent skill (S, core `skills/urlcode/`)
238
+ ### 1.5 The URLCode agent skill (S, core `skills/urlcode/`) — done
239
+
240
+ Done 2026-09-19: `skills/urlcode/SKILL.md` is 104 lines, ships in the package,
241
+ and is named by the generated `AGENTS.md` through `skillPath` in
242
+ `src/agents-guide.ts`; `test/cli.test.ts` asserts the reference and
243
+ `test/release.test.ts` asserts the packaged starter copy. Caveat: the
244
+ with-and-without comparison in the proof line waits on 0.1 — the URLCode arm
245
+ preamble (`benchmarks/agent/prompts/urlcode.md`) assumes the skill, and no model
246
+ run has been stored to compare against.
156
247
 
157
248
  Fixes: agents that support skills have no packaged instruction for URLCode.
158
249
 
@@ -170,7 +261,7 @@ Fixes: agents that support skills have no packaged instruction for URLCode.
170
261
  ### 2.1 Publish the three extension packages (decision, S) — done
171
262
 
172
263
  Done 2026-09-18: `@jimhoyd/urlcode-ui`, `-auth` and `-admin` are on npm as
173
- `0.1.0-alpha.1` against core `0.4.0-alpha.1`. The alpha caveat stays: source
264
+ `0.1.0-alpha.x` against core `0.4.0-alpha.1`. The alpha caveat stays: source
174
265
  complete, independent review, deployment evidence and accessibility
175
266
  assessment pending ([issue 58](https://github.com/jimhoyd-com/urlcode/issues/58)).
176
267
 
@@ -198,9 +289,22 @@ Fixes: three disagreeing lists of verified peer commits (the CI workflows,
198
289
  - Work: `peers.json` in auth and admin; the workflows read it; the pack
199
290
  script defaults from it; `ACCEPTANCE.md` links to it. 2.1 has shipped, so
200
291
  the published versions (`@jimhoyd/urlcode@0.4.0-alpha.1`,
201
- `@jimhoyd/urlcode-ui@0.1.0-alpha.1`) replace the SHAs and the file can go.
202
-
203
- ### 2.3 `urlcode init --with auth,admin,ui` (M, core plus each extension)
292
+ `@jimhoyd/urlcode-ui@0.1.0-alpha.4`) replace the SHAs and the file can go.
293
+
294
+ ### 2.3 `urlcode init --with auth,admin,ui` (M, core plus each extension) — done
295
+
296
+ Done 2026-09-19: `--with` is parsed in `src/cli.ts` and implemented by
297
+ `parseWithNames`, `loadScaffold` and `initProjectWith` in `src/init-with.ts`,
298
+ which resolves `@jimhoyd/urlcode-<name>` from the invoking directory, refuses a
299
+ missing package or one without a `scaffold` export before writing anything,
300
+ merges the fragments into the starter through a last include, and writes one
301
+ `host.mjs` (`renderHost`), one `README.md` (`renderReadme`), `.mcp.json` and the
302
+ `AGENTS.md` from 1.1, printing the `inspectExtensionRevision` digest for
303
+ pinning. `test/init-with.test.ts` uses a fake `@jimhoyd/urlcode-<name>` package
304
+ in a temporary `node_modules` and, when companion checkouts are present,
305
+ composes the real auth and admin scaffolds. Caveat: each extension's own
306
+ `scaffold` export and admin's clean-project acceptance live in those
307
+ repositories and are not verified here.
204
308
 
205
309
  Fixes: three initializers with three directory conventions; no single command
206
310
  produces the layered project the framework page describes.
@@ -217,7 +321,20 @@ produces the layered project the framework page describes.
217
321
  `node_modules`; each extension tests that its `scaffold` output validates
218
322
  with core; admin's clean-project acceptance uses the new command.
219
323
 
220
- ### 2.4 Print extension schemas: `urlcode extensions` (M, core)
324
+ ### 2.4 Print extension schemas: `urlcode extensions` (M, core) — partly done
325
+
326
+ Done 2026-09-19, the command and the MCP tool: `urlcode extensions
327
+ [--host-file] [--json]` in `src/cli.ts` over `describeExtensions` in
328
+ `src/tooling.ts` prints each registration's name, version, targets,
329
+ configuration schema, policy schema, mounts, policy routes and revision-pin
330
+ verdict, and without a host file names the declared extensions and says schemas
331
+ need one. The same function is exported from `src/index.ts` and served as MCP
332
+ `get_extensions`, offered only when the operator started the server with a host
333
+ file, which `test/extensions.test.ts` asserts against the
334
+ `examples/extensions` registry. Not done: the fold-in. `urlcode context
335
+ --host-file` reports host extension names and a plugin count rather than their
336
+ schemas (`buildContext` in `src/context.ts`), and `urlcode capabilities auth`
337
+ takes no host file, so registered contracts are not part of either view.
221
338
 
222
339
  Fixes: an agent cannot discover what `extensions.auth.config` accepts without
223
340
  reading auth's source; `urlcode mcp` cannot serve it.
@@ -231,7 +348,21 @@ reading auth's source; `urlcode mcp` cannot serve it.
231
348
 
232
349
  ## Phase 3: retrieval instead of reading (M each, core)
233
350
 
234
- ### 3.1 Recipes as the vocabulary of common behavior
351
+ ### 3.1 Recipes as the vocabulary of common behavior — done
352
+
353
+ Done 2026-09-19: every bundled recipe carries `recipe.yaml`, and the catalog is
354
+ now ten — `authenticated-json-api`, `contact-form`, `cors-api`, `health-page`,
355
+ `json-api`, `middleware`, `protected-download`, `static-plus-api`, `typescript`
356
+ and `webhook-receiver` — which covers the seven this item names.
357
+ `urlcode recipes search|show|add` runs through `src/ecosystem-cli.ts` over
358
+ `searchRecipes` and `showRecipe` in `src/recipes.ts`, matching id, description,
359
+ tags and capabilities locally with no service, and MCP gained `search_recipes`.
360
+ `npm run check` validates the metadata and requires its derived fields to equal
361
+ the capability preflight (`checkCatalog` and `derivedDifferences` in
362
+ `scripts/check.ts`), and `test/recipes.test.ts` asserts a search hit per recipe
363
+ and that every recipe validates, passes its fixtures and audits with its
364
+ declared route count. Growing the catalog from the Phase 6 repetition log has
365
+ not started; the current ten are the seed list above.
235
366
 
236
367
  Fixes: four bundled recipes with a README each and no metadata; an agent
237
368
  cannot search them, and nothing tells it to look before generating.
@@ -248,14 +379,33 @@ cannot search them, and nothing tells it to look before generating.
248
379
  - Proof: schema for `recipe.yaml` checked in `npm run check`; a search test
249
380
  per recipe; every recipe still validates, tests and audits.
250
381
 
251
- ### 3.2 Examples become searchable the same way
382
+ ### 3.2 Examples become searchable the same way — done
383
+
384
+ Done 2026-09-19: each example carries `example.yaml` in the recipe metadata
385
+ shape, `urlcode examples search <text>` runs through `src/ecosystem-cli.ts` over
386
+ `searchExamples` in `src/examples.ts` and names the smallest runnable match with
387
+ its route, and the cookbook's per-route tags are generated into
388
+ `examples/cookbook/route-index.json` by `scripts/build-cookbook-index.ts`,
389
+ checked by `npm run check`. `scripts/check.ts` holds example metadata to the
390
+ same preflight as recipes, and `test/recipes.test.ts` ("examples carry the same
391
+ metadata shape and search returns the smallest runnable match with its route")
392
+ is the search test.
252
393
 
253
394
  - Work: `examples/*/example.yaml` with the same metadata shape; `urlcode
254
395
  examples search <text>` returns the smallest matching runnable example and
255
396
  its route. The cookbook's forty routes get per-route tags in one index file.
256
397
  - Proof: search test; count audit unchanged.
257
398
 
258
- ### 3.3 `urlcode explain` from compiled semantics
399
+ ### 3.3 `urlcode explain` from compiled semantics — done
400
+
401
+ Done 2026-09-19: `urlcode explain [/route] [--json]` in `src/cli.ts` over
402
+ `runExplainCommand` in `src/explain-cli.ts` and `explainRoute`/`explainProject`
403
+ in `src/explain.ts`, derived from the compiled IR, including extension policy
404
+ requirements when a host file is supplied. `test/explain.test.ts` covers the
405
+ project table and route detail through the CLI, the sandbox boolean, the
406
+ extension-protected route with a host registry, the nearest-route miss that
407
+ never carries binding values, and that explain agrees with the runtime on
408
+ methods and policies for every route.
259
409
 
260
410
  Fixes: `explainRoute` exists in the SDK and MCP; there is no CLI, and the
261
411
  output repeats matching rather than effective behavior.
@@ -268,7 +418,15 @@ output repeats matching rather than effective behavior.
268
418
  - Proof: snapshot tests on the cookbook; a test that `explain` and the
269
419
  runtime agree on methods and policies for every route.
270
420
 
271
- ### 3.4 A generated semantic manifest
421
+ ### 3.4 A generated semantic manifest — done
422
+
423
+ Done 2026-09-19: `urlcode manifest [--json]` shares the `src/explain-cli.ts`
424
+ entry and runs `buildManifest` in `src/manifest.ts`; `build` writes
425
+ `manifest.json` beside the artifact and MCP offers `get_manifest`.
426
+ `test/manifest.test.ts` asserts determinism, that the revision equals the
427
+ extension revision digest, that external requirements and recipe provenance are
428
+ listed by name and never by value, and that the CLI prints the bytes the build
429
+ writes.
272
430
 
273
431
  - Work: `urlcode manifest [--json]` (also written by `build` and offered by
274
432
  MCP as `get_manifest`) emits routes, capabilities, recipe provenance,
@@ -278,7 +436,17 @@ output repeats matching rather than effective behavior.
278
436
  - Proof: manifest equals `inspectProject` output for the same project;
279
437
  digest equals `inspectExtensionRevision`.
280
438
 
281
- ### 3.5 MCP authoring layer, separately authorized (M, core)
439
+ ### 3.5 MCP authoring layer, separately authorized (M, core) — done
440
+
441
+ Done 2026-09-19: `src/mcp-authoring.ts` adds `create_route`, `add_recipe` and
442
+ `scaffold_feature` plus the `run_validate`, `run_test` and `run_audit` runners,
443
+ enabled only by `--allow-authoring` on the operator's command line, which
444
+ `src/cli.ts` refuses for any other command and which no tool argument or
445
+ environment variable can set (`src/mcp.ts`). Every write is validated before it
446
+ lands and returns the verdict. `test/mcp-authoring.test.ts` asserts the tools
447
+ are absent without the flag, that absolute, parent, symlinked, dotenv, git and
448
+ operator paths are refused, and that a create is followed by validation in one
449
+ call.
282
450
 
283
451
  Fixes: MCP is read-only by design; an agent that wants to add a recipe or a
284
452
  route still has to write files by hand.
@@ -297,7 +465,20 @@ route still has to write files by hand.
297
465
 
298
466
  ## Phase 4: fewer lines for the common case (schema additions, `version: "1"` stays valid)
299
467
 
300
- ### 4.1 Short form for function routes (M, core)
468
+ ### 4.1 Short form for function routes (M, core) — done
469
+
470
+ Done 2026-09-19: `normalizeRoute` in `src/config.ts` expands
471
+ `function: functions/x.mjs` into `{source, args}` with an argument per `{param}`
472
+ and a required bounded path parameter for any the route does not declare itself
473
+ (`SHORT_FORM_PATH_SCHEMA`), and a string `middleware` entry into `{source}`; the
474
+ long form stays the IR. Both shapes are in
475
+ `schemas/urlcode.schema.json` (`$defs.route.properties.function` and
476
+ `.middleware`) and the generated field reference lists them as options.
477
+ `test/config.test.ts` ("function and middleware short forms normalize to the
478
+ long form the long form compiles to") asserts identical output, that a declared
479
+ parameter keeps its schema, and that a bad short-form string is refused with the
480
+ route named; the cookbook uses the short form in
481
+ `examples/cookbook/routes/middleware.yaml`.
301
482
 
302
483
  Fixes: the smallest function route is ten lines.
303
484
 
@@ -308,11 +489,27 @@ Fixes: the smallest function route is ten lines.
308
489
  - Proof: generated reference updated; cookbook gains a short-form route with
309
490
  fixtures; a test that short and long forms compile to identical IR.
310
491
 
311
- ### 4.2 Route-level `auth` as the semantic form (M, core plus auth)
492
+ ### 4.2 Route-level `auth` as the semantic form (M, core plus auth) — done
493
+
494
+ Done 2026-09-19: the route-level `auth` key is in the schema
495
+ (`$defs.route.properties.auth` over `$defs.routeAuth` in
496
+ `schemas/urlcode.schema.json`) and expanded by `normalizeRouteAuth` in
497
+ `src/config.ts`, which refuses a route that declares `auth` without an
498
+ `extensions.auth` declaration, alongside `policies.extensions.auth`, or with
499
+ `policies.extensions: false`; `required: false` documents intent and emits
500
+ nothing. The type is documented in `src/types.ts`, and `test/recipes.test.ts`
501
+ ("the authenticated recipes use the auth short form and never let credentials
502
+ reach the guest") covers both `auth: true` and a role requirement. The `cache`
503
+ short form this item defers to later shipped with it:
504
+ `$defs.route.properties.cache` and the cache branch of `normalizeRoute`, refused
505
+ alongside `policies.cache`. Caveat: the auth repository's HTTP tests are outside
506
+ this repository and were not run here.
312
507
 
313
508
  Fixes: protecting a route today is `policies: { extensions: { auth: {} } }`,
314
509
  which is the mechanism, not the intent. The form an agent should write is
315
- `auth: { required: true, roles: [admin] }`.
510
+ `auth: { required: true, role: admin }`. (Delivered in `0.4.0-alpha.1` with
511
+ `role` singular; `routeAuth` sets `additionalProperties: false`, so the plural
512
+ `roles` this plan originally proposed is rejected by the validator.)
316
513
 
317
514
  - Work: a route-level `auth` key that expands to the `policies.extensions.auth`
318
515
  requirement the auth extension validates; `roles` maps to the extension's
@@ -365,7 +562,15 @@ whether links become a collection. Decide after review; build nothing first.
365
562
  `hiddenField`, `postForm`, `withDeadline` in the ui main entry; auth and
366
563
  admin drop their copies (`admin-markup.ts`, `admin-deadline.ts`).
367
564
 
368
- ### 7.2 Auth and admin render through the kit (L)
565
+ ### 7.2 Auth and admin render through the kit (L) — partly done
566
+
567
+ Done 2026-09-19, the core prerequisite only: the immutable-cache exception for
568
+ hashed extension assets shipped. `ExtensionImmutableAssets` and
569
+ `validateAssetPrefix` in `src/extensions.ts` bound a declared prefix to literal
570
+ segments under the extension's mounts, and `immutableAssetResponse` is what
571
+ lets such a response carry an asset cache-control instead of `no-store`. The
572
+ rendering work itself is in the auth, admin and ui repositories and is not
573
+ verified from here.
369
574
 
370
575
  Auth exports its catalogue and templates with view models, takes an optional
371
576
  `ui` from the host, and renders with `ui.kit.page` when present; admin the
@@ -388,28 +593,54 @@ walkthrough. Retire the `presentation` option one minor version later.
388
593
  ## Phase 9: hardening left from the audit (core, S each)
389
594
 
390
595
  - Direct tests for the sandbox pool, worker crash recovery and timeout kill
391
- path (`src/functions.ts`, `src/function-worker.ts`, `src/guest-api.ts`).
392
- - Tests for `src/link-store-worker.ts` behind the WAL gate.
393
- - Re-verify the remaining line-number rows in `STANDARDS.md`; cite symbols.
394
- - Split the three longest reference documents (YAML guide, policies, dynamic
395
- links) into task pages under 200 lines, so retrieval returns one page.
596
+ path (`src/functions.ts`, `src/function-worker.ts`, `src/guest-api.ts`) —
597
+ done 2026-09-19: `test/sandbox-pool.test.ts` covers load shedding with slot
598
+ reuse, parallel workers with per-slot heaps, the 250 ms-to-30 s respawn
599
+ backoff, the deadline kill with slot replacement, an abrupt worker exit
600
+ failing the in-flight invocation, startup failure and close, and the guest
601
+ `Request`/`Response`/context surface.
602
+ - Re-verify the remaining line-number rows in `STANDARDS.md`; cite symbols —
603
+ done 2026-09-19: `docs/STANDARDS.md` records that every row was re-verified
604
+ at `8d7dd01` and now cites the implementing function or constant rather than
605
+ a line number, names the test that proves it, and says "unverified at
606
+ 8d7dd01" where a row could not be re-checked; no line-number citation
607
+ remains in the file.
608
+ - Split the longest reference documents (YAML guide, policies) into task pages
609
+ under 200 lines, so retrieval returns one page — done 2026-09-19:
610
+ `docs/yaml/` holds nine pages (largest `functions.md`, 160 lines) and
611
+ `docs/policies/` nine (largest `agents.md`, 182 lines), with
612
+ `docs/YAML-GUIDE.md` down to 57 lines. Caveat: `docs/POLICIES.md` is still
613
+ 203 lines as the index page.
396
614
  - A pre-test check in the extension repos that fails fast with the SQLite
397
- requirement named.
615
+ requirement named. Not verifiable from this repository.
398
616
 
399
617
  ## Sequence at a glance
400
618
 
619
+ What remains, as of 2026-09-19:
620
+
401
621
  ```
402
- Phase 0 agent benchmark + code-ratio metric (decides everything after it)
403
- Phase 1 AGENTS.md from init → llms-full → urlcode context → capability/schema queries → skill
404
- Phase 2 publish alphas → peers.json → init --with → extensions --schema
405
- Phase 3 recipe metadata + search → examples search → explain → manifest → MCP authoring
406
- Phase 4 short-form function route → route-level auth
407
- Phase 5 re-run the benchmark after each phase
408
- Phase 6 repetition log → collections spike, then decide
409
- Phase 7 shared helpers → kit adoption
622
+ Phase 0 instrument built and tested; no model-backed run stored, so the
623
+ code-ratio evidence is still missing. Evals (0.2) run weekly.
624
+ Phase 1 done: AGENTS.md from init, llms-full, urlcode context,
625
+ capability/schema queries, the skill
626
+ left: the docs site's /docs/<page>.md (urlcode-docs)
627
+ Phase 2 done: published alphas, init --with, urlcode extensions + get_extensions
628
+ left: peers.json (auth, admin); extension schemas folded into
629
+ urlcode context and capabilities <name>
630
+ Phase 3 done: recipe metadata + search, examples search, explain, manifest,
631
+ MCP authoring behind --allow-authoring
632
+ Phase 4 done: short-form function and middleware routes, route-level auth,
633
+ the cache short form; 4.3 stays a standing rule for new fields
634
+ Phase 5 waits on a Phase 0 run with a real model
635
+ Phase 6 not started: no docs/REPETITION-LOG.md, no docs/SPIKE-COLLECTIONS.md
636
+ Phase 7 extension repos; the core immutable-asset exception 7.2 needs is done
410
637
  Phase 8 proof gaps, in parallel, as people and environments allow
411
- Phase 9 hardening, in any gap
638
+ Phase 9 done: sandbox pool tests, STANDARDS symbol citations, split reference
639
+ pages; left: the extension repos' SQLite pre-test check
412
640
  ```
413
641
 
414
642
  Phase 0 decides whether the rest is worth doing and in what order. Phases 1
415
643
  and 3 are what an agent meets first; the rest makes that cheaper or proves it.
644
+ Because Phases 1, 3 and 4 landed ahead of the first model-backed run, that run
645
+ now measures what shipped rather than choosing it; Phase 5's re-runs are where
646
+ the choosing role returns.