OpenWork Den Architecture Explained: den-api, den-web, and den-gateway Components
OpenWork Den uses a three-tier microservice architecture where den-api serves as the Hono-based control plane, den-web acts as a Next.js frontend proxy, and den-gateway provides a thin HTTP abstraction for automated workflows and CORS-free API access.
The OpenWork Den ecosystem—found in the different-ai/openwork repository—provides the central control plane for organization management, user authentication, billing, and cloud workspace orchestration. Understanding the OpenWork Den architecture requires examining how these three specialized components interact to provide both human-facing interfaces and programmatic control.
OpenWork Den Architecture Overview
The architecture follows a microservice pattern with clearly separated concerns:
| Component | Responsibility | Technology Stack |
|---|---|---|
| den-api | Backend control plane exposing HTTP APIs for auth, orgs, workers, and SCIM | Hono (Node.js), Zod, MySQL, Better Auth |
| den-web | Frontend web application with same-origin proxying to avoid CORS | Next.js (React/TypeScript), Tailwind CSS, Vercel |
| den-gateway | Thin HTTP gateway for test flows and cloud workspace scripts | TypeScript utilities, native fetch |
Authentication flows through Better Auth in den-api, with tokens propagated via den-web's proxy routes or directly injected by den-gateway utilities.
den-api: The Hono-Based Control Plane
The den-api package implements the entire Den API surface as modular Hono route groups. Located in ee/apps/den-api/, this component handles all persistent state for organizations, users, and cloud workers.
Modular Route Structure
Routes are organized by domain in ee/apps/den-api/src/routes/:
src/routes/auth/– Better Auth endpoints and desktop hand-off routes under/v1/auth/*src/routes/me/– Current user profile and organization list endpointssrc/routes/org/– Organization CRUD operations and SCIM managementsrc/routes/workers/– Worker lifecycle management, billing, and heartbeat monitoring
Each folder contains its own README.md for isolated discovery and documentation.
Shared Validation and Type Safety
Request and response schemas use TypeID validation defined in ee/packages/utils/src/typeid.ts and re-exported through ee/apps/den-api/src/openapi.ts. This ensures consistent type safety across the API surface using Zod validation.
Observability Configuration
The den-api supports pluggable observability via the DEN_OBSERVABILITY_BACKEND environment variable (none, otel, or sentry). Request access logs capture request-id, method, normalized route, status, and duration while redacting sensitive fields.
// Simplified example from ee/apps/den-api/src/routes/org/index.ts
router.get('/orgs/:orgId', orgContext, async (c) => {
const org = c.get('org');
return c.json(org);
});
den-web: Next.js Frontend and Same-Origin Proxy
The den-web component (ee/apps/den-web/) serves the user interface at https://app.openworklabs.com. Built with Next.js, it handles authentication flows and proxies requests to den-api to maintain same-origin security policies.
Same-Origin Proxy Architecture
To avoid cross-origin resource sharing (CORS) restrictions, den-web implements server-side proxy routes:
app/api/den/*– Forwards requests to the upstream Den API (DEN_API_BASE)app/api/auth/*– Proxies Better Auth callbacks for GitHub OAuth and email login
This architecture allows browser-based clients to call /api/den/v1/cloud/instance while the server forwards to the actual den-api endpoint with proper authentication headers.
Desktop Hand-Off Integration
UI components like den-admin-panel.tsx and den-marketing-rail.tsx generate deep-links using DEN_WEB_OPENWORK_APP_CONNECT_URL. These links open the OpenWork desktop client with pre-populated worker URLs and authentication tokens, bridging the web and desktop experiences.
Root Layout Structure
The application shell is defined in ee/apps/den-web/app/layout.tsx:
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className="h-full">
<body className="min-h-screen bg-[var(--dls-app-bg)] text-[var(--dls-text-primary)]">
<DenShell>{children}</DenShell>
</body>
</html>
);
}
den-gateway: Automated Flow Gateway
den-gateway is not a standalone service but a utility layer used by automated test flows, particularly in evals/flows/den-gateway.flow.ts. It provides CORS-free API access for cloud workspace overlay scripts and testing scenarios.
Token Handling and Request Utilities
The gateway abstracts authentication complexity through helper functions:
fetchJson– Wrapper aroundfetchwith JSON parsing and error handlinggatewayInstanceFetch– Pre-configured fetch with authorization headers and timeout handling viawithTimeout- Token injection – Automatically appends
Authorization: Bearer <token>headers to requests
Workspace Marker Operations
For testing persistence across updates, den-gateway provides utilities to write and read marker files in cloud workspaces. The writeWorkspaceMarker function in den-gateway.flow.ts demonstrates writing temporary files to verify workspace state persistence.
// From evals/flows/den-gateway.flow.ts
const signIn = async (ctx) => {
const res = await fetchJson(`${flowBase(ctx)}/api/auth/sign-in/email`, {
method: 'POST',
headers: { 'content-type': 'application/json', origin: flowBase(ctx) },
body: JSON.stringify({ email, password })
});
if (!res.response.ok) throw new Error('Sign-in failed');
return (res.body as any).token;
};
Practical Implementation Examples
Calling den-api from Node.js Scripts
When building automation outside the web interface, obtain a Bearer token through the Better Auth endpoint and call the API directly:
import fetch from 'node-fetch';
const API_BASE = 'https://api.openworklabs.com';
const token = '<bearer-token-from-sign-in>';
async function listOrgs() {
const res = await fetch(`${API_BASE}/v1/me/orgs`, {
headers: { Authorization: `Bearer ${token}` }
});
const data = await res.json();
console.log('Orgs:', data.orgs);
}
listOrgs().catch(console.error);
Using den-web's Proxy from Browser Context
For client-side code running within the den-web origin, leverage the same-origin proxy to avoid handling CORS:
async function getCurrentWorkspace() {
const res = await fetch('/api/den/v1/cloud/instance', {
credentials: 'include' // Cookies contain auth tokens from login flow
});
const { status, url } = await res.json();
console.log(`Workspace status: ${status}, URL: ${url}`);
}
Workspace File Operations via Gateway
For automated testing scenarios, use the gateway utilities to manipulate workspace files:
// Inside a den-gateway flow context
await gatewayInstanceFetch(ctx, `/workspace/${workspaceId}/files/content`, {
method: 'POST',
body: JSON.stringify({
path: 'demo-marker.txt',
content: 'proof of persistence',
force: true,
})
});
Summary
- den-api (
ee/apps/den-api/) provides the core Hono-based REST API with MySQL persistence, organized into domain-specific route folders undersrc/routes/ - den-web (
ee/apps/den-web/) delivers the Next.js frontend with critical proxy routes inapp/api/den/*that enable same-origin API access without CORS complications - den-gateway (implemented in
evals/flows/den-gateway.flow.ts) offers a TypeScript utility layer for automated flows, handling Bearer token injection and workspace file operations - Authentication flows through Better Auth in
den-api, accessible viaden-webproxy routes at/api/auth/*or directly for desktop hand-off at/v1/auth/* - Observability spans all components via the
DEN_OBSERVABILITY_BACKENDconfiguration supporting OpenTelemetry or Sentry
Frequently Asked Questions
What is the relationship between den-api and den-web?
den-api is the standalone backend service that exposes the full HTTP API for the OpenWork ecosystem, while den-web is the Next.js frontend that proxies requests to den-api through server-side routes in app/api/den/*. This proxy pattern allows the browser to make same-origin requests to /api/den/*, which the Next.js server then forwards to the actual den-api endpoint, eliminating CORS issues while maintaining security.
How does authentication work across the OpenWork Den architecture?
Users authenticate via Better Auth endpoints mounted under /api/auth/* in den-api. The den-web application proxies these endpoints through app/api/auth/* routes, allowing the browser to complete OAuth flows and email sign-in without cross-origin requests. Upon successful authentication, the system issues a Bearer token stored in localStorage (for web) or passed directly to the desktop client (via DEN_WEB_OPENWORK_APP_CONNECT_URL deep-links) to authorize subsequent API calls.
What is the purpose of den-gateway if den-api already provides HTTP endpoints?
den-gateway serves as a programmatic abstraction layer specifically designed for automated test flows and cloud workspace scripts. While den-api provides the raw HTTP interface, den-gateway (as seen in evals/flows/den-gateway.flow.ts) encapsulates token management, request timeouts, retry logic, and workspace file operations. This allows test scripts to interact with the Den ecosystem without implementing CORS workarounds or handling authentication header injection manually.
How are TypeID schemas validated across the Den architecture?
TypeID validation is centralized in ee/packages/utils/src/typeid.ts and consumed by den-api through src/openapi.ts. This shared validation layer ensures that request and response schemas for organizations, users, and workers remain consistent across the API surface. The den-api uses Zod to enforce these schemas at route boundaries, providing type safety from the HTTP layer down to the MySQL database interactions.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →