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 endpoints
  • src/routes/org/ – Organization CRUD operations and SCIM management
  • src/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 around fetch with JSON parsing and error handling
  • gatewayInstanceFetch – Pre-configured fetch with authorization headers and timeout handling via withTimeout
  • 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 under src/routes/
  • den-web (ee/apps/den-web/) delivers the Next.js frontend with critical proxy routes in app/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 via den-web proxy routes at /api/auth/* or directly for desktop hand-off at /v1/auth/*
  • Observability spans all components via the DEN_OBSERVABILITY_BACKEND configuration 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →