@shaferllc/keel
v0.83.1
Published
The house framework for Node.js — a service container, providers, routing, JSX views, and a code-generating console.
Maintainers
Readme
Keel ⚓
The house framework for Node.js.
TypeScript · a real service container · convention-driven structure · a code-generating console.
Getting Started · Container · Routing · Providers · Console
Keel gives you the ergonomics that make you productive — a service container, service providers, dot-notation config, expressive routing, and a code-generating console — on a modern TypeScript stack. Hono powers the HTTP layer under the hood; everything above it is Keel's.
It is a house framework: small enough to read in an afternoon, opinionated enough to ship on, and yours to extend.
// routes/web.ts
router.get("/", [HomeController, "index"]);
router.get("/hello/:name", (c) => c.text(`Hello, ${c.req.param("name")}!`));// A controller — resolved from the container, so it gets dependency injection
export class HomeController {
constructor(private app: Container) {}
index(c: Ctx) {
return c.json({ app: config("app.name") });
}
}Why Keel?
- A real service container.
bind/singleton/instance/make. Everything resolves through it — the pattern that keeps apps testable and composable. - Service providers. A
register()→boot()lifecycle to configure the app in one place. - Convention over configuration.
app/,config/,routes/,bootstrap/— you always know where things live. - A code-generating console.
keel serve,keel routes, andmake:*generators. - Typed end to end. Strict TypeScript, no build step in dev (powered by
tsx). - Thin and legible. The whole framework is a few hundred lines in
src/core/. No magic you can't read.
Two repos: the framework and your app
Keel is distributed the same way most frameworks are — a library you install, plus an app that depends on it:
| Repo | Role |
|------|------|
| shaferllc/keel (this repo) | The framework. Published as @shaferllc/keel. |
| shaferllc/keel-app | The starter app — clone it to build something. Gets core updates via npm update. |
Install in your app
npm install @shaferllc/keelimport { Application, Router, config } from "@shaferllc/keel/core";Or clone the starter app and start from a working skeleton.
Hack on the framework itself
git clone https://github.com/shaferllc/keel.git
cd keel
npm install
npm test # 740 tests
npm run typecheck # src + tests
npm run build # compile the package to dist/
npm run verify:release # build from what's committed — what a consumer's install runsThis repo is the framework, and only the framework — there is no app in it. To
run one, clone the starter app and point it
at your checkout ("@shaferllc/keel": "file:../keel").
The console
keel routes # list every registered route
keel serve --port 8080 # start the server on a chosen port
keel make:controller Post # -> app/Controllers/PostController.ts
keel make:provider Billing # -> app/Providers/BillingServiceProvider.ts
keel make:middleware Auth # -> app/Http/Middleware/authMiddleware.ts
keel make:page users/[id] # -> resources/pages/users/[id].tsx
keel make:command greet # -> app/Commands/greet.ts
keel repl # a shell with the app booted
keel mcp # start the MCP server (docs + API for AI agents)These run in your app, from its own bin/keel.ts — which is a few lines that
hand the console your application factory (see the console guide).
Built for AI ⚓🤖
Keel is designed to be written with an AI agent. Alongside the human docs it ships a machine-readable surface that stays generated-in-sync, never stale:
- An MCP server.
keel-mcpexposes Keel's docs, its full public API (380+ exports), the generators, and its conventions to any MCP client. Connect it in Claude Code:
Tools:claude mcp add keel -- npx -y keel-mcpkeel_overview,keel_search_docs,keel_read_doc,keel_search_api,keel_list_generators,keel_scaffold. Resources:keel://overview,keel://llms-full,keel://docs/<slug>. AGENTS.md. The agent playbook — the one import rule, the folder map, the container/provider model, a "how to add X" table, and the guardrails.CLAUDE.mdpoints to it.llms.txt+llms-full.txt. A spec-compliant doc index and a one-file concatenation of every guide, both shipped in the npm package for drop-in context.- Generators an agent can drive.
keel_scaffold(orkeel make:*) emits the correct stub with the right imports and path for every construct.
Full guide: docs/ai.md. Regenerate the surface after doc or
export changes with npm run build:ai (also runs automatically on npm run build).
Project layout
src/core/ The framework
├─ container.ts Service container — bind / singleton / instance / make
├─ application.ts Kernel: env + config loading + provider lifecycle
├─ config.ts Dot-notation config repository + env() helper
├─ provider.ts ServiceProvider base class (register / boot)
├─ http/
│ ├─ router.ts Route facade (closures or [Controller, method] tuples)
│ └─ kernel.ts Global middleware + compiles routes onto Hono
├─ cli/ The console: commands, generators, the kernel that runs them
└─ index.ts Public surface — apps import "@shaferllc/keel/core"
src/db/ Database adapters (D1, Postgres, libSQL)
src/api/ CRUD REST resources from a model
src/openapi/ Generates an OpenAPI spec from the routes
src/billing/ Subscription billing — Stripe + Paddle
src/watch/ The debug dashboard
src/mcp/ The MCP server (docs + API for AI agents)
src/vite/ The Vite plugin
tests/ 767 tests
docs/ Every guide, plus type-checked examples of each
scripts/ build-ai (llms.txt, the MCP manifest), verify-releaseThere is no app/ here. Your application code — controllers, providers,
routes, config — lives in your repo, not the framework's. The
starter app has the layout.
The request lifecycle
bin/keel.ts servecallscreateApplication()inbootstrap/app.ts.- The
Applicationloads.env, then everyconfig/*.tsfile, then runs each provider'sregister()andboot(). - The HTTP kernel (
app/Http/Kernel.ts) applies global middleware and compiles the collected routes onto a Hono instance. @hono/node-serverserves it. Each request flows through middleware → route handler (a closure or a container-resolved controller) → response.
See docs/architecture.md for the full picture.
Documentation
| Guide | What it covers |
|-------|----------------|
| Getting Started | Install, run, first route and controller |
| The Service Container | Binding and resolving services, DI |
| Service Providers | Plugin system: register/boot lifecycle, options |
| Configuration | config/*.ts, dot-notation, env() |
| Routing | Closures, controller tuples, groups, resources, domains |
| URL Builder | Named-route URLs, signed URLs |
| Hashing & Encryption | Password hashing, AES value encryption |
| Controllers | Classes, DI, single-action, lazy-loaded |
| Request & Response | Input, cookies, output, abort() |
| Request Decorators | Lazy, memoized per-request values |
| Lifecycle Hooks | onReady/onShutdown, graceful shutdown, onRoute |
| Sessions | Cookie-backed sessions, flash messages |
| Authentication | Session auth, guards, user provider |
| Authorization | Gates & policies, can/authorize |
| Database | Driver-agnostic query builder |
| Models | Active-record: find/create/save, casts, relations |
| Migrations | Schema builder + migrator, dialect-aware |
| Factories & Seeders | Built-in Faker, model factories, seeders |
| Mail | Fluent mailer, pluggable transports, sendLater(), attachments |
| Queues & Jobs | Dispatch jobs, retries + backoff, dead-letter, workers |
| Task Scheduling | Cron-style recurring tasks, one trigger |
| Notifications | Multi-channel (mail/db), queueable |
| Broadcasting | Real-time channels, pluggable, presence auth |
| API Resources | CRUD REST API from a model; deny-by-default access, row-level scope |
| Transformers | Shape models into API JSON; conditional fields, relations |
| Events | Emit/listen decoupling, async listeners |
| Service Broker | Moleculer-style services, call/emit, pluggable transport |
| Cache | TTLs, the remember pattern, pluggable stores |
| Locks | Distributed locks with ownership + TTL, pluggable stores |
| Redis | Pluggable client, memory driver, cache adapter |
| Logger | Structured logging, sinks, per-request reqId, redaction |
| Static Files | serveStatic(), caching, dot-file safety |
| Storage | Pluggable disks (local/S3/R2), signed URLs, direct uploads |
| Health Checks | /health/live + /health/ready, pluggable checks |
| Telemetry | Tracing, W3C context, OTLP export — no SDK |
| Internationalization | ICU messages, Intl formatters, locale detection |
| Pages | Page-based routing — a file is a route |
| Packages | Redistributable slices of an app: routes, migrations, commands |
| Billing | Subscriptions, charges & webhooks — Stripe + Paddle |
| Watch | Debug dashboard — requests, queries, jobs, logs at /watch |
| Views | Hono JSX components, layouts, the View service |
| Templates | {{ }} + @-tag templating engine, edge-safe |
| Middleware | Global middleware, writing your own |
| Rate Limiting | rateLimiter() middleware, per-key buckets |
| Errors | HTTP exceptions, debug page, custom handlers |
| Testing | Inject requests, fakes, spies, time travel, db assertions |
| Debugging | dump() and dd() (dump-and-die) |
| Validation | validate() with Zod, auto-422 field errors |
| Inertia | Server-side Inertia.js adapter |
| Vite | Frontend build: HMR in dev, hashed manifest in prod |
| The Console | Typed commands, prompts, terminal UI, REPL, make:* |
| Architecture | Container, kernel, request lifecycle |
| Built on Hono | The Hono layer underneath, and using it directly |
| Building with AI | MCP server, AGENTS.md, llms.txt, agent workflow |
Testing
The core has a test suite (Node's built-in runner + tsx, no extra tooling):
npm test # run the suite
npm run test:coverage # with v8 coverageUnit tests cover the container, config, view, exceptions, and validation; an integration suite drives the HTTP kernel end-to-end (routing, request/response helpers, error rendering, middleware, validation). Coverage sits at ~99% lines / ~91% branches.
Requirements
- Node.js ≥ 22
- No database or build step required for the MVP core.
Roadmap
Keel's first release is the MVP core: container, routing, middleware, config, and the console. On deck:
- [x] View / templating layer (Hono JSX) — v0.2.0
- [x] Cloudflare Workers–safe core — v0.2.0
- [x] Global helpers:
config(),app(),view()— v0.3.0 / v0.4.0 - [x] Error & exception handling — v0.5.0
- [x] Request/response + container helpers — v0.6.0–v0.9.0
- [x] Validation (Zod-compatible) — v0.10.0
- [x] First-class routing (groups, resources, named routes) — v0.11.0
- [x] Domain routing, matchers, Inertia adapter — v0.12.0
- [x] Test suite (~99% coverage)
- [x] Query builder (driver-agnostic) — v0.28.0
- [x] Active-record Model layer — v0.29.0
- [x] Migrations (schema builder) — v0.30.0
- [x] Model relationships (hasMany / belongsTo / belongsToMany) — v0.31.0
- [x] Factories & seeders (built-in Faker) — v0.32.0
- [x] Model attribute casts + mass-assignment guarding — v0.33.0
- [x] Mail (fluent mailer, pluggable transports) — v0.34.0
- [x] Queues / background jobs (pluggable drivers) — v0.35.0
- [x] Notifications (multi-channel, queueable) — v0.36.0
- [ ] Publish
src/coreas the@keel/corepackage
See CHANGELOG.md for release history.
Contributing
Issues and PRs welcome. Run npm run typecheck before opening a PR.
License
MIT © 2026 Tom Shafer
