README.md
Rama main · réplica de lectura del repositorio original.
# URLCode
**A portable runtime for programmable URL behavior, and the framework that grows
from it.** Declare an application's public URL surface in YAML, add JavaScript
only where declarative handlers are not enough, and run the same
project locally, in a container, on your own infrastructure or on a provider
adapter. When the project gets serious, add accounts, data and tools as
operator-installed extensions instead of building them again.
**URL behavior as code.**
[](https://github.com/jimhoyd-com/urlcode/actions/workflows/ci.yml)
[Documentation](docs/README.md) · [Concepts][docs/CONCEPTS.md] · [The framework][docs/FRAMEWORK.md] · [For AI agents](llms.txt) · [URLCode AI](https://urlcode.ai/) · [Starter][docs/STARTERS.md] · [Contributing][CONTRIBUTING.md] · [Security](SECURITY.md)
**Your AI should build your application, not your framework.** Coding agents
rebuild the same routing, validation, middleware, policies and authentication
plumbing on every project, and the person ends up owning the plumbing. URLCode
represents those behaviors as a strict, portable YAML contract that both people
and agents can read: the agent describes what, the runtime owns how, and
generated code goes to the part that is actually the application. It is
infrastructure for AI-built software, not a framework for building AI models.
[Why][docs/PROJECT-DIRECTION.md#why-your-ai-should-build-your-application-not-your-framework] ·
[roadmap][ROADMAP.md].
## Install
URLCode needs Node.js 22.13 or later. Pick the installation channel that fits
your environment:
```sh
# npm
npm install --global @jimhoyd/urlcode@latest
# Homebrew
brew tap jimhoyd-com/urlcode
brew trust jimhoyd-com/urlcode
brew install urlcode
# Generic installer (downloads a release tarball and verifies its SHA-256)
curl -fsSL https://raw.githubusercontent.com/jimhoyd-com/urlcode/main/install.sh | sh
```
For project-local installs, exact version pins, and provenance details, see
[the installation guide][docs/INSTALL.md].
## Try it
```sh
urlcode init my-urls && cd my-urls
urlcode dev
```
Without a global install, pin the runtime in the project and run the installed
copy (`--no` refuses to fetch anything from the registry):
```sh
mkdir my-urls && cd my-urls && npm init -y
npm install --save-dev --save-exact @jimhoyd/urlcode
npx --no --package @jimhoyd/urlcode urlcode init .
npm run dev
```
The starter deliberately has no routes. Ask the local MCP `get_context` tool
(or run `urlcode context` in the site; the route project is `app/`), then add the smallest declarative route
or custom code the application needs. `urlcode test` runs the project's HTTP
fixtures, and `urlcode studio` opens a read-only page on localhost showing
what each route does and what needs attention
([review report and studio](docs/TOOLING.md#review-report)). The [install guide][docs/INSTALL.md] covers the checksum-verified
script, project-local installs, the container image and signed provenance. To
work from a clone: `git clone … && make dev`.
## A URL that runs your function
```yaml
version: "1"
routes:
/hello/{name}:
parameters:
- { name: name, in: path, required: true, schema: { type: string, minLength: 1, maxLength: 80 } }
function:
source: functions/hello.mjs
args: { name: { from: path, name: name } }
env:
GREETING: { value: Hello }
```
```js
export default function hello(request, { args, env }) {
return Response.json({ message: `${env.GREETING}, ${args.name}!` });
}
```
Add `middleware: [{ source: middleware/headers.mjs }]` to wrap any handler with
`await next()`. Fourteen ready-made middleware patterns ship in the cookbook
and as `urlcode recipes add middleware`. See [functions and the sandbox](docs/FUNCTION-SECURITY.md)
and [middleware][docs/MIDDLEWARE.md].
## Documentation
New to the vocabulary? Read [Concepts][docs/CONCEPTS.md] first — route,
handler, middleware, policy, extension; project vs operator; trusted vs
sandbox; extension vs artifact.
Start with the [YAML guide and recipe book][docs/YAML-GUIDE.md],
[complete field reference](docs/YAML-REFERENCE.md), and
[runnable 40-route cookbook](examples/cookbook/README.md). For AI-assisted
authoring, use [the AI guide](docs/AI-AUTHORING.md), the bundled agent skills
([authoring](.claude/skills/urlcode-authoring/SKILL.md),
[operations](.claude/skills/urlcode-operations/SKILL.md)) and [llms.txt](llms.txt).
For optional hosted reference and shared skills, use [URLCode AI](https://urlcode.ai/);
its anonymous remote MCP augments, rather than replaces, the local project server.
Agents can also read installed artifacts (inert extension schemas and examples)
through the read-only MCP tools described in [artifacts][docs/EXTENSIONS.md#artifacts].
Follow [organization and readability practices][docs/BEST-PRACTICES.md] as your
project grows. Operators should read [capacity/concurrency][docs/CAPACITY.md] and the
[DDoS and recovery playbook][docs/RESILIENCE.md]. Embedding the runtime from
TypeScript is covered in [TypeScript][docs/TYPESCRIPT.md]. [All documentation](docs/README.md).
All of it lives in [`docs/`](docs/README.md) in this repository. See
[the roadmap][ROADMAP.md#history] for the retired `urlcode-docs` site repository.
## The framework
Core plus three optional bundled extensions and one artifact, one site shape. A project climbs from redirects to a
full application by adding YAML; the operator wires trusted extensions in one
host file outside the project. The full map, the composition contract and the
rules an AI agent must follow are in [the framework][docs/FRAMEWORK.md].
| Component | Adds | Distribution |
|---|---|---|
| [urlcode](https://github.com/jimhoyd-com/urlcode) (this repository) | Runtime, CLI, policies, provider adapters, extension contract | [npm](https://www.npmjs.com/package/@jimhoyd/urlcode), [GitHub Releases](https://github.com/jimhoyd-com/urlcode/releases), Homebrew |
| [auth][packages/auth] extension | Accounts and sessions from [Better Auth](https://better-auth.com/) on one mount; `auth: true` routes receive the signed-in user id | add-on on core's GitHub Release |
| [store][packages/store] extension | Durable bounded JSON collections exposed as a typed CRUD API, with an optional audit log kept in the same database and a tap to forward it | add-on on core's GitHub Release |
| [mcp][packages/mcp] extension | Declarative MCP tool server over a project-declared tool map | add-on on core's GitHub Release |
| [store-schema][artifacts/store-schema] artifact | Inert store configuration schema and example, for tooling | add-on on core's GitHub Release |
Only core is published to npm. Every add-on is released as a tarball on the
same GitHub Release, at core's version, and core pins each by URL and sha512.
A site adds them with `urlcode extensions add <name>` or `urlcode artifacts add
<name>` ([add-ons][docs/EXTENSIONS.md#add-ons-extensions-and-artifacts]);
`urlcode upgrade` moves core and every add-on together. See [package and channel
alignment](docs/VERSION-ALIGNMENT.md).
`urlcode-dynamic-link` and `urlcode-short` were published once as
`0.1.0-alpha.1` and have since been retired: both were unpublished from npm and
their repositories deleted, and neither has a direct successor. A project that
wants stored short links declares a collection through the `store` extension
(see [docs/STORE.md][docs/STORE.md]) instead. Anything still pinned to
`@jimhoyd/urlcode-dynamic-link@0.1.0-alpha.1`
also has to deal with its exact declared peer `@jimhoyd/urlcode: 0.4.0-alpha.1`,
which cannot be installed beside core `0.4.0-alpha.2` and never will be.
`urlcode-middleware` was retired too: **per-route middleware is native to
core**, through the `middleware:` array documented in
[docs/MIDDLEWARE.md][docs/MIDDLEWARE.md]. See [the roadmap][ROADMAP.md#history]
for that retirement's history and migration note.
```yaml
version: "1"
extensions:
auth: { version: "1", config: {} }
routes:
/go: { redirect: { url: https://example.com, status: 302 } }
/api/auth/*: { extension: auth, methods: [GET, POST] }
/private:
respond: { text: Signed in }
auth: true
```
The YAML names logical extensions; it never names packages, code, databases
or credentials. `urlcode init site --with auth` writes the route project in
`site/app/` with auth's `/api/auth/*` mount, the operator host `site/host.mjs`
and a private `data/auth.secret`; `npx urlcode-auth migrate` creates Better
Auth's tables, and `urlcode serve --host-file host.mjs` loads it. Browsers sign
in through Better Auth's own client. Cross-repository acceptance is tracked in
[issue 58](https://github.com/jimhoyd-com/urlcode/issues/58).
## What it is
A project is a `urlcode.yaml` with `version: "1"`. Each route has exactly one
handler: `redirect`, `respond`, `page`, `static`, `download`, `function`,
`proxy`, `conditional` or an `extension` mount, with optional ordered
`middleware`. The runtime validates the whole project before serving it,
compiles it once, and refuses anything a target cannot enforce with the route
named. Functions and middleware run trusted, in-process, with full Node
access by default; a route opts into an isolated QuickJS/WebAssembly sandbox
with a fresh heap per call and no Node, filesystem or network by declaring
`sandbox: true`. Either way, the `env`/`secrets` the runtime *hands* a route
come only from operator grants pinned to the project revision; grants govern
that injected context, not the ambient Node environment a trusted, in-process
module can reach on its own like any other code in the host.
URLCode is not a URL shortener: stored short links are declared through the
operator-installed `store` extension's collections, not core's job. It is not a
general Node web framework: routing, validation, middleware wiring and
policies are declared in YAML, not hand-wired; isolating a specific route's
code from the host is an explicit `sandbox: true` opt-in, not something every
route gets by writing a handler. It is not a provider configuration format:
infrastructure settings stay out of route YAML.
See [project direction][docs/PROJECT-DIRECTION.md], or [Concepts][docs/CONCEPTS.md]
for the vocabulary these two paragraphs use.
## Status
<!-- urlcode-current-version:start -->
This checkout prepares the `0.6.6` core release. The auth, store
and mcp extensions and the store-schema artifact are workspace packages
released as add-on tarballs with core, not npm packages. Package availability
remains a live registry fact: see the GitHub Releases page or
`npm view @jimhoyd/urlcode dist-tags`. A stable core
version does not close the review and deployment evidence gaps
below. `0.4.0-alpha.1`
added the extension contract, capabilities and provider conformance, strict
redirect interchange (since removed), bulk import, recipes and search, TypeScript guest
authoring, conditions, bounded proxy and signals, and the MCP read and
authoring modes. `0.4.0-alpha.2` then made `function` and `middleware` routes
run trusted and unsandboxed by default, with `sandbox: true` as a per-route
opt-in, and removed the native `link:`/`dynamicLinks:` YAML shape. That is a
behaviour change for existing projects with no YAML edit; read
[the roadmap entry][ROADMAP.md] before upgrading. Use the schema and docs from
the runtime revision you run.
<!-- urlcode-current-version:end -->
The [roadmap][ROADMAP.md] separates implemented from planned, and
[production readiness][docs/RELEASE-OPERATIONS.md#production-readiness] records what is proven and
what is not: provider deployments, soak and independent security review
remain open.
URLCode is free and open-source software licensed under the
[Apache License 2.0](LICENSE). Commercial use, modification, redistribution and
self-hosting are permitted under its terms.
## Start your own project
`urlcode init` creates a bare, agent-ready site with no routes yet. The
runtime is a pinned dependency of the site; no separate checkout or global
installation is needed.
```sh
npx @jimhoyd/urlcode init my-links
cd my-links
npm install
npm run dev
```
## Start from YAML
Already wrote `urlcode.yaml`? Run `urlcode scaffold --project ./my-links --dry-run`,
then remove `--dry-run` to create missing modules, pages and directories. Existing
files are preserved; code placeholders return 501 until implemented.
[Scaffolding guide][docs/SCAFFOLDING.md]. Node 22.13+ installed, 22.18+ to run
the TypeScript source. The `auth` extension runs on the Node target only
([auth][packages/auth/README.md]).
## Everything else in YAML
- **Pages, files, downloads:** `page`, `static`, `download` with MIME detection,
ETags, ranges and safety limits. [Assets][docs/ASSETS.md].
- **HTTP:** methods, validated path/query/header inputs, body limits, response
headers and cookies. [HTTP][docs/HTTP.md].
- **Policies and site conventions:** throttle, agents, security headers,
compression, cache; robots, sitemap, favicon, security.txt, llms.txt.
[Policies][docs/POLICIES.md], [site][docs/SITE.md].
- **Conditions, proxy, signals:** exact predicates with disjoint cases; a bounded
HTTPS proxy and best-effort webhooks behind operator grants.
[Conditions][docs/CONDITIONS.md], [egress][docs/EGRESS.md].
- **Organization:** `includes` across folders; strict CSV/JSON/YAML redirect
import; searchable recipes and examples. [Organization][docs/ORGANIZATION.md],
[bulk][docs/BULK.md], [recipes][docs/RECIPES.md].
- **Checks:** `validate`, `test`, `routes`, `audit --expect-routes`,
`capabilities`, deployment verification and a GitHub Action.
[Readiness][docs/READINESS.md], [CI][docs/CI.md].
## Deploy
Self-hosted Node process or container first. `@jimhoyd/urlcode/vercel` and
`@jimhoyd/urlcode/aws` serve declarative projects as native handlers;
`urlcode build --target cloudflare` compiles redirects and declared responses
into a Worker; `urlcode build --target static` compiles redirects and static
files into plain objects and redirect metadata for S3 + CloudFront, with no
server at all. Each target refuses at activation or build time what it cannot
run, with the route named. None has been exercised on its provider yet; the
adapters have local conformance tests only. [Operations][docs/OPERATIONS.md],
[capabilities][docs/CAPABILITIES.md], [Vercel][docs/VERCEL.md], [AWS][docs/AWS.md],
[Cloudflare][docs/CLOUDFLARE.md], [static hosting][docs/STATIC.md].
## For AI agents
[llms.txt](llms.txt) is the compact index; [the framework][docs/FRAMEWORK.md]
is the map; [AI authoring](docs/AI-AUTHORING.md) is the contract with the
capability matrix and a copyable task prompt. `urlcode mcp` exposes read-only
inspection, validation and conversion previews over stdio, and
`--allow-authoring` adds project-confined authoring tools and runner tools that
execute the project's code ([tooling](docs/TOOLING.md)).
[URLCode AI](https://urlcode.ai/) is the optional hosted companion for
version-pinned reference and shared skills; its anonymous remote MCP endpoint is
documented in [tooling](docs/TOOLING.md#optional-hosted-ai-mcp).
## Built with URLCode
No public application built on URLCode is currently listed. The reference
application is the [private-requests proof][proofs/private-requests/README.md]
in this repository: owner-private records, a reviewed approval and a reviewer
permission declared over the auth and store extensions, with no application
server code. Its [client][proofs/private-requests/client/main.js] is the
frontend pattern: the application's own code calling the JSON mounts with
`fetch`.
The two earlier
ones were built on the public runtime as ordinary consumers and have since been
retired: `urlcode-docs`, a static documentation site
rendered through its own middleware at build time and served through native
page/static/download routes, and `urlcode-short`, an account-free short-link
demo combining expiring links, QR downloads and a shadcn/ui frontend — URLCode
supplied the pages, assets and routing, the application supplied anonymous
creation, link storage and its own limits. `urlcode-short`'s repository is
deleted, so its build retrospective is no longer reachable; what it recorded
about the gap between the runtime and a real application is carried in
[principles and open decisions][docs/OPEN-DECISIONS.md] and [roadmap][ROADMAP.md].
## License and contributing
Apache-2.0. Commercial use, modification, redistribution and self-hosting are
permitted. See [contributing][CONTRIBUTING.md], [security](SECURITY.md),
[governance][GOVERNANCE.md] and the [roadmap][ROADMAP.md].
<!-- urlcode-current-version:start -->
[docs/CONCEPTS.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/CONCEPTS.md
[docs/FRAMEWORK.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/FRAMEWORK.md
[docs/STARTERS.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/STARTERS.md
[CONTRIBUTING.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/CONTRIBUTING.md
[docs/PROJECT-DIRECTION.md#why-your-ai-should-build-your-application-not-your-framework]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/PROJECT-DIRECTION.md#why-your-ai-should-build-your-application-not-your-framework
[ROADMAP.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/ROADMAP.md
[docs/INSTALL.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/INSTALL.md
[docs/MIDDLEWARE.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/MIDDLEWARE.md
[docs/YAML-GUIDE.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/YAML-GUIDE.md
[docs/EXTENSIONS.md#artifacts]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/EXTENSIONS.md#artifacts
[docs/BEST-PRACTICES.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/BEST-PRACTICES.md
[docs/CAPACITY.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/CAPACITY.md
[docs/RESILIENCE.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/RESILIENCE.md
[docs/TYPESCRIPT.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/TYPESCRIPT.md
[ROADMAP.md#history]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/ROADMAP.md#history
[packages/auth]: https://github.com/jimhoyd-com/urlcode/tree/v0.6.6/packages/auth
[packages/store]: https://github.com/jimhoyd-com/urlcode/tree/v0.6.6/packages/store
[packages/mcp]: https://github.com/jimhoyd-com/urlcode/tree/v0.6.6/packages/mcp
[artifacts/store-schema]: https://github.com/jimhoyd-com/urlcode/tree/v0.6.6/artifacts/store-schema
[docs/EXTENSIONS.md#add-ons-extensions-and-artifacts]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/EXTENSIONS.md#add-ons-extensions-and-artifacts
[docs/STORE.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/STORE.md
[docs/PROJECT-DIRECTION.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/PROJECT-DIRECTION.md
[docs/RELEASE-OPERATIONS.md#production-readiness]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/RELEASE-OPERATIONS.md#production-readiness
[docs/SCAFFOLDING.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/SCAFFOLDING.md
[packages/auth/README.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/packages/auth/README.md
[docs/ASSETS.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/ASSETS.md
[docs/HTTP.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/HTTP.md
[docs/POLICIES.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/POLICIES.md
[docs/SITE.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/SITE.md
[docs/CONDITIONS.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/CONDITIONS.md
[docs/EGRESS.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/EGRESS.md
[docs/ORGANIZATION.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/ORGANIZATION.md
[docs/BULK.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/BULK.md
[docs/RECIPES.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/RECIPES.md
[docs/READINESS.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/READINESS.md
[docs/CI.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/CI.md
[docs/OPERATIONS.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/OPERATIONS.md
[docs/CAPABILITIES.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/CAPABILITIES.md
[docs/VERCEL.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/VERCEL.md
[docs/AWS.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/AWS.md
[docs/CLOUDFLARE.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/CLOUDFLARE.md
[docs/STATIC.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/STATIC.md
[proofs/private-requests/README.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/proofs/private-requests/README.md
[proofs/private-requests/client/main.js]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/proofs/private-requests/client/main.js
[docs/OPEN-DECISIONS.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/docs/OPEN-DECISIONS.md
[GOVERNANCE.md]: https://github.com/jimhoyd-com/urlcode/blob/v0.6.6/GOVERNANCE.md
<!-- urlcode-current-version:end -->