Atlas: Architecture Overview#
Atlas is a collection of composable, functional Bun/TypeScript packages for building APIs, full-stack applications, and CLI tools. This document describes the architecture, package relationships, and design philosophy.
Distribution and dependency graph#
Public imports use @wess/atlas/<module>. The facade forwards each entry point
to one implementation library, such as @wess/atlas-server; it has no mandatory
runtime dependencies or aggregate root entry point. A selected-entry dependency
catalog includes runtime imports, type imports, reexports, and literal dynamic
imports so isolated consumer builds have the packages needed for typechecking too.
Source modules remain focused folders under packages/. Distribution rewrites
cross-module relative imports to implementation package imports. Implementation
peers are optional because different entry points use different subsets. The CLI
installs each selected entry point's complete closure, rather than every peer.
| Entry point | Boundary |
|---|---|
auth/password, auth/token, auth/session | No database flows, server, or social providers |
auth/flows | Database queries and server pipes |
auth/social | Provider flows and server pipes; private cookie keeps PKCE verifier |
db/query | Query/schema API without either database driver |
db/postgres, db/sqlite | Only the chosen Bun driver |
db/changeset | Structural safeParse validation; no mandatory Zod dependency |
admin | Server routes and validation; no browser UI imports |
admin/ui, ui/<block> | Browser components and selected frontend peers |
cli, cli/command, cli/foreman | Runtime CLI APIs without scaffolding or docs |
cli/scaffold, cli/docs | Explicit development tooling |
Aggregate module entry points remain available when their whole feature set is wanted. Measure installed bytes, browser bundles, startup and sustained memory separately; a downloaded file is not necessarily loaded at runtime.
Core Packages#
Config#
@wess/atlas/config is the foundation. It provides typed environment variable loading that reads .env at startup and produces a frozen, immutable config object.
const config = defineConfig({
database: env("DATABASE_URL"),
port: env("PORT", { parse: Number, default: "3000" }),
})
All other packages optionally depend on config or accept config values directly. No forced wiring.
Database#
@wess/atlas/db is the largest package, with three layers:
- Query Builder — Ecto-inspired fluent chains for SELECT, INSERT, UPDATE, DELETE, JOIN operations. Fully immutable, functional API.
- Drivers — Uniform interface to Postgres (via
Bun.sql) and SQLite (viabun:sqlite) with transaction support. - Schemas & Changesets — Type-safe table definitions and safeParse-compatible input validation.
const users = defineSchema("users", {
id: column.serial().primaryKey(),
email: column.text().unique(),
})
const query = from(users).where(q => q("email").equals("[email protected]"))
const result = await db.one(query)
Server#
@wess/atlas/server wraps Bun.serve with a Plug-inspired pipe system. Requests flow through immutable Conn objects that pipes transform.
Sub-modules:
@wess/atlas/server— Core HTTP routing withget(),post(),put(),patch(),del()route builders, plus the adapter pattern (createAdapter,compose) for running multiple listeners@wess/atlas/server/ws— WebSocket support@wess/atlas/server/sse— Server-Sent Events
const logger = pipe(c => { console.log(c.method); return c })
const auth = pipe(c => {
const token = c.headers.get("authorization")
return token ? assign(c, { userId: decode(token).id }) : halt(c, 401)
})
serve({
routes: [
get("/users", pipeline(logger, auth)(handler)),
],
})
Pipes are composable via pipeline(), which short-circuits on halt(). This approach is borrowed from Elixir and is more testable and readable than middleware.
Edge#
@wess/atlas/edge is a TLS-terminating reverse proxy with built-in Let's Encrypt automation — the layer that would otherwise be Caddy or nginx in front of a Bun app.
- ACME v2 client — ECDSA P-256 account, JWS-signed requests, HTTP-01 challenge solver, hand-rolled CSR via a small DER encoder. No external deps.
- Reverse proxy — forwards requests with
X-Real-IP,X-Forwarded-For(appended),X-Forwarded-Proto,X-Forwarded-Host. Hop-by-hop headers stripped. Host rewritten unlesspreserveHost: true. - Cert lifecycle — certs persist to a configurable store (filesystem default, in-memory for tests). A renewal timer reissues 30 days before expiry and
server.reload({ tls })swaps without dropping connections. - Localhost dev — when every site host matches
isLocalHost, the edge runs plain HTTP on a non-privileged port. No certs, no sudo. The sameedge.tsruns in dev and prod.
import { defineEdge, proxy } from "@wess/atlas/edge"
defineEdge({
acme: { email: "[email protected]", storage: "/var/atlas/edge" },
sites: [{
host: process.env.DOMAIN!,
compress: ["gzip", "zstd"],
routes: [{ handler: proxy("http://app:3000") }],
}],
}).listen()
The templates/edge scaffold ships a complete deploy pattern: Procfile for local, Dockerfile + compose.yaml for production, with the cert volume and ACME staging-then-prod recipe pre-wired.
Auth#
@wess/atlas/auth provides:
- Primitives —
hash(),verify(),token.sign(),token.verify()built on Bun's crypto - Flows — Prebuilt pipes like
signup(),login(),requireAuth(),passwordReset()that work with@wess/atlas/serverand@wess/atlas/db - Social login (
@wess/atlas/auth/socialsubpath) — pluggable OAuth-client for Google, GitHub, Apple, Microsoft, Facebook, X (Twitter), and TikTok. PKCE-S256 mandatory, state + verifier held in a signed HttpOnly cookie so the flow stays stateless. Your app owns the user table —onSuccessreceives a normalizedSocialProfileand you decide upsert/link.
const signupPipe = signup({
db,
table: "users",
fields: ["email", "password"],
onSuccess: (c, user) => json(c, 201, user),
})
// Social — same Conn/PipeFn shape:
const social = socialAuth({
secret,
providers: {
google: google({ clientId, clientSecret, redirectUri }),
github: github({ clientId, clientSecret, redirectUri }),
tiktok: tiktok({ clientKey, clientSecret, redirectUri }),
// …apple, microsoft, facebook, twitter
},
})
get("/auth/google", social.start("google"))
get("/auth/google/callback", social.callback("google", {
onSuccess: async (c, { profile }) => json(c, 200, { profile }),
}))
Security#
@wess/atlas/security ships hardening primitives most apps end up writing themselves:
withSecurityHeaders()— strict default headers (HSTS, COOP/CORP, Permissions-Policy) and a CSP that defaults to'self'-only with no inline script in production. Also stashes the real Bun socket peer ontoreq.peerIpso downstream rate-limit / audit code does not have to trust client-suppliedX-Forwarded-For.createDbRateLimit()/createMemoryRateLimit()— atomic UPSERT on Postgres, transactional read-modify-write on SQLite, in-memory for tests.clientIp(req, { trustedProxies })— only honors forwarded headers when the request actually arrived from a configured trusted proxy.createSessionStore()— DB-backed, revocable JWT sessions withlast_used_attracking and a sweep helper. Pair with@wess/atlas/auth#requireAuth.generateSecret/verifyTotp/otpauthUrl/generateBackupCodes— purenode:cryptoTOTP with backup codes.decideInline()— safe-MIME allowlist forContent-Disposition: inline(never inlines SVG).createAuditLogger()— fire-and-forget audit-event recorder; never throws, never blocks the response.
OAuth#
@wess/atlas/oauth is an OAuth 2.1 server: PKCE-required authorization code, refresh-token rotation, device-code flow, RFC 8414 discovery, RFC 7009 revoke, and admin client management.
import { oauthRoutes } from "@wess/atlas/oauth"
import { requireAuth } from "@wess/atlas/auth"
serve({
routes: [
...oauthRoutes({
db,
secret,
scopes: ["read", "write"],
loadUser,
buildAccessTokenClaims,
requireUser: requireAuth({ secret }),
requireAdmin,
}),
...appRoutes,
],
})
oauthRoutes(cfg) returns every endpoint as a flat Route[] ready to spread into serve. Mount only what you need by calling the per-flow factories (oauthAuthorizeRoutes, oauthTokenRoutes, …) directly. Sweeps for expired auth codes / refresh tokens / device codes are exported separately so you can run them on a schedule.
Email#
@wess/atlas/email is a provider-agnostic transport plus a small HTML shell and two stock templates.
import { createEmailer, inviteEmail } from "@wess/atlas/email"
const emailer = createEmailer({ apiKey: process.env.RESEND_API_KEY, from: process.env.RESEND_FROM })
await emailer.send({ to: "[email protected]", ...inviteEmail({ inviterName, product, signupUrl }) })
createEmailer returns the real Resend transport when both env vars are set and a console transport otherwise — dev environments stay unblocked without configuring a sending domain. send never throws; failures come back as { ok: false, error }. The included layout() is a 560px Outlook-friendly card; always pass user-supplied strings through escapeHtml.
Share#
@wess/atlas/share is the smallest practical layer for "share this link" UX. Pure URL builders for the eight channels users actually use, plus a server-side shareEmail that dispatches through any @wess/atlas/email transport.
import { share, shareUrl, shareEmail } from "@wess/atlas/share"
shareUrl("twitter", { url, title, hashtags: ["atlas"] })
// → https://twitter.com/intent/tweet?url=…&text=…&hashtags=atlas
share({ url, title, text })
// → { twitter, facebook, linkedin, reddit, whatsapp, telegram, sms, email }
await shareEmail({
emailer,
to: "[email protected]",
sharerName: "Wess",
content: { url, title },
})
The URL builders have zero dependencies; shareEmail reuses the same layout() shell as inviteEmail/passwordResetEmail and escapes untrusted strings the same way.
Storage#
@wess/atlas/storage provides S3-compatible object storage with:
upload()— PUT file to bucketdownload()— GET file from bucketpresign()— Generate presigned URLs for direct client accesslist()— List objects by prefix
Uses AWS Signature V4 (implemented from scratch, ~250 lines) with no external dependencies.
Cache#
@wess/atlas/cache wraps Bun.redis with:
createCache()— Redis-backed cachecreateMemoryCache()— In-memory (for testing)cached()— Cache-aside pattern: fetch from cache, fallback to function, store resultinvalidate()— Bust cache keys
const getUser = cached(cache, "user", async (id) => {
return await db.one(from(users).where(q => q("id").equals(id)))
}, { ttl: 600 })
Request#
@wess/atlas/request is an HTTP client built on fetch with:
request()— One-off requestscreateClient()— Preconfigured clients with base URL, headers, retries- Providers — Drop-in configs for GitHub, Stripe, OpenAI, Resend (import from
@wess/atlas/request/providers) - Retry logic with exponential backoff
- Request/response interceptors
import { github } from "@wess/atlas/request/providers"
const gh = github({ token: process.env.GITHUB_TOKEN! })
const repos = await (await gh.get("/user/repos")).json()
CLI#
@wess/atlas/cli provides:
- Command parser — Define commands, flags, subcommands; parse argv
- Foreman — Procfile parser and concurrent process runner with colored output
- Built-in commands —
atlas init(scaffold project),atlas add(add packages),atlas dev(start dev server),atlas mcp(launch MCP server)
cli("myapp", [
command("serve", {
flags: { port: flag("p", { type: "number", default: 3000 }) },
run: ({ flags }) => startServer(flags.port),
}),
])
await foreman({ web: "bun run server.ts", worker: "bun run worker.ts" })
Migrate#
@wess/atlas/migrate manages timestamped SQL migrations with up/down support.
migrate.create("./migrations", "add_users")
await migrate.up(db, "./migrations")
await migrate.status(db, "./migrations")
Tracks applied migrations in schema_migrations table. Works with Postgres and SQLite.
UI#
@wess/atlas/ui is a modular React package with its own components and independent blocks:
@wess/atlas/ui/styles.css— The compiled stylesheet; import it once@wess/atlas/ui/components— Primitives (Button, TextInput, Table, Tabs, ...)@wess/atlas/ui/headless— Behavior hooks with no markup or styles@wess/atlas/ui/factory—component()andcreateField()for building new primitives@wess/atlas/ui/provider— Color scheme, light/dark/system mode, and layout shell@wess/atlas/ui/forms— Form primitives and helpers@wess/atlas/ui/table— Data tables with sort/filter/pagination@wess/atlas/ui/auth— Login, signup, password reset pages@wess/atlas/ui/storage— File upload and image preview@wess/atlas/ui/nav— Navigation components@wess/atlas/ui/cache— Cache inspector and status badge@wess/atlas/ui/ai— Chat panel, message list, streaming display
Each block is independently importable and tree-shakeable.
Admin#
@wess/atlas/admin auto-generates a Django-style admin panel from @wess/atlas/db schemas. Provides:
- API routes — CRUD endpoints for each model
- Admin SPA — React UI with list, detail, create views, search, filters, bulk actions, custom actions, query builder
- Metadata routes — Schema introspection, field info, relation discovery
const panel = admin({
db,
models: [
model({
schema: users,
searchFields: ["email", "name"],
filterFields: ["status"],
bulkActions: ["delete", "export"],
}),
],
})
serve({ routes: panel.mount([]) })
Serves SPA at /admin with full CRUD UI.
MCP#
@wess/atlas/mcp provides a Model Context Protocol server for AI/LLM debugging and introspection. It exposes your app's database, routes, config, and logs to AI agents through the standard MCP protocol.
import { collectTools, createContext, createMcpServer } from "@wess/atlas/mcp"
const ctx = createContext({ db, routes: myRoutes, config })
const mcp = createMcpServer(collectTools(ctx), ctx)
mcp.start()
Launch via CLI: atlas mcp. AI agents can then query your database, inspect routes, view config, and read logs interactively.
AI#
@wess/atlas/ai provides a unified interface for AI/LLM operations with zero external dependencies — it calls provider REST APIs directly via fetch.
- Providers —
createProvider({ provider, key })returns anAiProviderfor"openai","anthropic", or"ollama" - Chat —
provider.chat(opts)for completions,provider.chatStream(opts)for streamingStreamChunks - Conversations —
createConversation/sendfor immutable message-history tracking - Embeddings —
embed(provider, inputs)plus an in-memorycreateVectorStore() - RAG —
index(rag, id, text)+query(rag, question)over a{ ai, store, topK? }bag - Agents —
runAgent({ ai, system?, tools, maxIterations? }, prompt)for tool-using loops - Server pipe —
withAi(provider)attaches the provider toconn.assigns.ai
import { createProvider, send, createConversation, runAgent, tool } from "@wess/atlas/ai"
const openai = createProvider({ provider: "openai", key: process.env.OPENAI_API_KEY! })
const conv = createConversation("You are a helpful assistant")
const { response } = await send(openai, conv, "Hello")
for await (const chunk of openai.chatStream({ messages: [{ role: "user", content: "Hi" }] })) {
if (chunk.type === "text") process.stdout.write(chunk.content ?? "")
}
Works with OpenAI, Anthropic, Ollama, or any OpenAI-compatible endpoint (baseUrl override).
Templates#
Atlas ships with 10 project templates, scaffolded via atlas init --template <name>:
| Template | Description | Key Packages |
|---|---|---|
minimal | Just server + config | config, server |
api | REST API with db, auth, migrations | config, db, migrate, server, auth |
edge | App + TLS-terminating edge (replaces Caddy/nginx) | config, server, edge |
fullstack | API + React frontend | config, db, server, auth, ui |
admin | API + admin panel | config, db, server, auth, admin |
worker | Background job processor | config, db, cache, cli |
realtime | WebSocket + SSE | config, server |
socialnetwork | Users, posts, follows, likes, feeds, media, real-time | config, db, server, auth, cache, storage |
cms | Headless CMS with content types, publishing, webhooks | config, db, server, auth, storage, admin |
ai | Chatbot, RAG, agents, embeddings, streaming | config, server, ai |
Composition Patterns#
Typical Backend App#
// 1. Config
const config = defineConfig({ database: env("DATABASE_URL"), ... })
// 2. Database
const db = connect({ driver: "postgres", url: config.database })
// 3. Migrations
await migrate.up(db)
// 4. HTTP with pipes
serve({
routes: [
post("/auth/signup", signup({ db, table: "users", ... })),
post("/auth/login", login({ db, table: "users", ... })),
get("/api/users", pipeline(requireAuth({ secret }))(listUsers)),
post("/api/files", pipeline(requireAuth({ secret }), parseMultipart)(uploadFile)),
],
})
Full Stack#
Use @wess/atlas/ui on the client, and serve the same HTML for every client path:
// server.ts
import { get, pipe, putHeader, serve, text } from "@wess/atlas/server"
const page = await Bun.file("./index.html").text()
const shell = pipe((c) => putHeader(text(c, 200, page), "content-type", "text/html; charset=utf-8"))
serve({
routes: [...apiRoutes, get("/", shell), get("/app/*", shell)],
})
// app.tsx
import "@wess/atlas/ui/styles.css"
import { AtlasProvider } from "@wess/atlas/ui/provider"
import { createRoot } from "react-dom/client"
createRoot(document.getElementById("root")!).render(<AtlasProvider><App /></AtlasProvider>)
The admin panel needs none of this: admin() returns routes that serve its own prebuilt shell, bundle, and sign-in screen.
Skills#
skills/ holds small, task-focused instructions for coding agents, one directory per kind of work, shipped with the CLI. atlas skills install copies them into a project. They cost far less context than the references, which remain canonical, and bun run skills:verify typechecks every snippet against the source.
AGENTS.md Convention#
Each package includes an AGENTS.md at its root — a compact manifest (~80 lines) of the public API.
Structure:
- Exports — Each public function/type with signature and return type
- Types — Data shapes that users need to generate correct code
- Usage — Minimal working example
- Dependencies — Sibling and external packages
Why this matters:
LLMs can read packages/db/AGENTS.md instead of traversing 20+ source files. This is critical for token efficiency in prompt engineering and code generation workflows.
Conventions:
- Keep under 100 lines
- Every public export must be listed
- Include return types and argument types
- Update whenever the API changes
- Treat as part of the build process
Design Philosophy#
- Functional — No classes, immutable data, composition over inheritance
- Minimal dependencies — Wrap Bun's native APIs, don't reach for external packages
- Composable — Each package works independently or with others
- AI/LLM-friendly — Clear APIs, good types, predictable patterns, AGENTS.md reference
- No framework lock-in — Use what you need, combine with anything else
- Bun-native — Idiomatic to Bun's philosophy and APIs
- Shallow dependencies — Max 1 level of sibling package dependencies
External Dependencies#
| Package | Deps |
|---|---|
| config | none |
| db | zod |
| migrate | none |
| server | none |
| auth | none |
| security | none |
| oauth | none |
| edge | none |
| none | |
| notify | none |
| share | none |
| storage | none |
| cache | none |
| request | none |
| sso | none |
| cli | none |
| ui | react, react-dom, @tanstack/*, lucide-react |
| admin | react, react-dom, @tanstack/*, lucide-react |
| mcp | none |
| ai | none |
Total: Only zod on the backend. Frontend uses React + TanStack + lucide-react.
Development Environment#
- Monorepo — Bun workspaces
- Testing —
bun testacross all packages - TypeScript — Strict mode
- Linting — Biome (run
bun run check/bun run tidy) - File naming — All lowercase, no dashes or underscores, subdirectories for organization
- Environment —
.envin root (Postgres on localhost, SQLite in memory for tests)