# How Configuration is Managed in OpenWork: Global Files, Database Storage, and Runtime Generation

> Discover how OpenWork manages configuration using global files, database storage, and runtime generation. Learn about its dual-layer architecture for efficient settings management.

- Repository: [Different AI/openwork](https://github.com/different-ai/openwork)
- Tags: how-to-guide
- Published: 2026-08-02

---

**OpenWork manages configuration through a dual-layer architecture that stores global Opencode settings in [`/.opencode/opencode.json`](https://github.com/different-ai/openwork/blob/main//.opencode/opencode.json) while persisting workspace-specific data in a runtime database, automatically migrating legacy keys and generating a derived [`openwork-runtime.json`](https://github.com/different-ai/openwork/blob/main/openwork-runtime.json) file for the Electron engine process.**

OpenWork (from the `different-ai/openwork` repository) implements a sophisticated configuration system that separates global IDE preferences from per-workspace runtime parameters. Understanding how configuration is managed in OpenWork requires examining three distinct layers—global Opencode files, workspace database records, and the generated runtime configuration that feeds the engine process.

## The Three-Tier Configuration Architecture

OpenWork splits configuration across **global (Opencode) settings**, **per-workspace OpenWork settings**, and **derived runtime files**. This separation allows global defaults to coexist with workspace-specific overrides while maintaining a flat file interface for the underlying Electron process.

### Global Opencode Configuration ([`/.opencode/opencode.json`](https://github.com/different-ai/openwork/blob/main//.opencode/opencode.json))

The global Opencode file contains generic OpenWork settings such as default providers and MCP (Model Context Protocol) definitions. According to the source code in [`apps/server/src/workspace-files.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/workspace-files.ts), the system locates this file using the `opencodeConfigPath()` helper:

```typescript
// apps/server/src/workspace-files.ts
export const opencodeConfigPath = (workspaceRoot: string) =>
  join(workspaceRoot, ".opencode", "opencode.json");

```

The server reads this file using `readJsoncFile()`, which parses JSON-C (JSON with comments) and feeds the values into the startup sequence. This global layer serves as the foundation for default values across all workspaces.

### Workspace-Specific OpenWork Configuration (Runtime DB)

Unlike the global file, workspace-specific settings live in the **runtime database** rather than flat files. When a workspace initializes, the server seeds a minimal configuration record via `defaultWorkspaceOpenworkConfig()` in [`apps/server/src/workspace-init.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/workspace-init.ts):

```typescript
// apps/server/src/workspace-init.ts
export function defaultWorkspaceOpenworkConfig(
  workspaceRoot: string,
  preset: string,
): WorkspaceOpenworkConfig {
  return {
    version: 1,
    workspace: {
      name: basename(workspaceRoot) || "Workspace",
      createdAt: Date.now(),
      preset,
    },
    authorizedRoots: [workspaceRoot],
    reload: null,
  };
}

```

The `ensureWorkspaceFiles()` function guarantees this default record exists during startup. The runtime DB now owns the canonical source of truth, though legacy installations may still reference [`.opencode/openwork.json`](https://github.com/different-ai/openwork/blob/main/.opencode/openwork.json) as a fallback. The persistence layer is handled by `seedOpenworkWorkspaceConfigIfEmpty()` and related helpers in [`apps/server/src/openwork-workspace-config-store.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/openwork-workspace-config-store.ts).

### Derived Runtime Configuration ([`openwork-runtime.json`](https://github.com/different-ai/openwork/blob/main/openwork-runtime.json))

The Electron engine process consumes a concrete JSON file generated on-the-fly. The `buildOpenworkRuntimeConfigObject()` function in [`apps/server/src/openwork-runtime-config.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/openwork-runtime-config.ts) constructs this artifact by merging global and workspace configurations:

```typescript
// apps/server/src/openwork-runtime-config.ts
export async function buildOpenworkRuntimeConfigObject(
  config: ServerConfig,
  workspaceId: string,
): Promise<RuntimeOpencodeConfig> {
  const openwork = await readOpenworkWorkspaceConfig(config, workspaceId);
  const opencode = await readGlobalRuntimeOpencodeConfig(config);
  // merge legacy + user config
  const merged = mergeLegacyRuntimeConfig(opencode, legacy);
  // …
  return merged;
}

```

The resulting [`openwork-runtime.json`](https://github.com/different-ai/openwork/blob/main/openwork-runtime.json) file is written by `writeOpenworkRuntimeConfigFile()` and consumed by the engine via `openworkRuntimeConfigFilePath()`.

## Legacy Configuration Migration

Older OpenWork installations stored settings directly inside the global Opencode file. During server startup, the system automatically extracts these legacy keys and migrates them into the new runtime model. The `legacyRuntimeConfigFromOpenworkConfig()` function in [`apps/server/src/server.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/server.ts) handles this extraction:

```typescript
// apps/server/src/server.ts
function legacyRuntimeConfigFromOpenworkConfig(openwork: Record<string, unknown>) {
  const plugin = Array.isArray(openwork.plugin) ? ... : [];
  const mcp = isRecord(openwork.mcp) ? ... : {};
  // …
  return { config: { plugin, mcp, … }, keys };
}

```

This migration ensures backward compatibility while moving the canonical source of truth to the database-backed workspace configuration store.

## Runtime Config Generation Pipeline

The process of generating the final runtime configuration involves several discrete steps:

1. **Read workspace config** from the runtime DB using `readOpenworkWorkspaceConfig()`
2. **Read global config** via `readGlobalRuntimeOpencodeConfig()`
3. **Extract legacy values** with `legacyRuntimeConfigFromOpenworkConfig()` if present
4. **Merge configurations** using `mergeLegacyRuntimeConfig()` to resolve conflicts
5. **Write the artifact** to disk via `writeOpenworkRuntimeConfigFile()`

This pipeline ensures that workspace-specific overrides always take precedence over global defaults, while legacy values are preserved during the transition period.

## Programmatic Configuration Access

Developers can read or update workspace configurations through the server's HTTP API, defined in [`apps/server/src/routes/workspaces.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/routes/workspaces.ts).

### Reading Workspace Configuration

Send a `GET` request to retrieve the stored `WorkspaceOpenworkConfig`:

```typescript
// Example using the OpenWork client SDK
import { OpenWorkClient } from "@openwork/sdk";

const client = new OpenWorkClient({ baseUrl: "http://localhost:8787" });
const workspaceId = "my-workspace";

async function getConfig() {
  const config = await client.get(`/w/${workspaceId}/openwork`);
  console.log("Workspace config:", config);
}

```

### Updating Configuration (Owner Scope)

Authenticated owners can modify settings via `PATCH`, which persists changes to the runtime DB and triggers a workspace reload:

```typescript
// apps/server/src/routes/workspaces.ts
router.patch("/w/:workspaceId/openwork", async (ctx) => {
  const { workspaceId } = ctx.params;
  const body = await ctx.request.json();
  await writeOpenworkWorkspaceConfig(config, workspaceId, body);
  // schedule a reload for the affected workspace
  reloadBaselineRefreshers.get(config)?.(workspaceId, ["config"]);
  return jsonResponse({ ok: true });
});

```

Client-side implementation:

```typescript
import { OpenWorkClient } from "@openwork/sdk";

const client = new OpenWorkClient({
  baseUrl: "http://localhost:8787",
  token: process.env.OPENWORK_HOST_TOKEN, // owner token
});

async function setReloadAuto(workspaceId: string, enable: boolean) {
  await client.patch(`/w/${workspaceId}/openwork`, {
    reload: { auto: enable },
  });
  console.log(`Reload auto ${enable ? "enabled" : "disabled"} for ${workspaceId}`);
}

```

## Complete Configuration Flow Example

A typical lifecycle demonstrates how these layers interact:

1. **Server startup** reads the global Opencode file from [`/.opencode/opencode.json`](https://github.com/different-ai/openwork/blob/main//.opencode/opencode.json) using `readJsoncFile()`
2. **Workspace creation** invokes `defaultWorkspaceOpenworkConfig()` to seed a DB record with version metadata and authorized roots
3. **Legacy detection** triggers `legacyRuntimeConfigFromOpenworkConfig()` to extract old plugin and MCP definitions from the global file
4. **Runtime generation** calls `buildOpenworkRuntimeConfigObject()` to compose the final JSON, merging global defaults with workspace-specific overrides
5. **API mutation** allows clients to `PATCH` updates; changes trigger reloads via `reloadBaselineRefreshers` to synchronize the engine process

## Summary

- **Global settings** reside in [`/.opencode/opencode.json`](https://github.com/different-ai/openwork/blob/main//.opencode/opencode.json) (JSON-C) and are parsed by `readJsoncFile()` in [`apps/server/src/workspace-files.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/workspace-files.ts)
- **Workspace configuration** is stored in the runtime database, initialized by `defaultWorkspaceOpenworkConfig()` in [`apps/server/src/workspace-init.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/workspace-init.ts)
- **Legacy migration** automatically extracts old keys via `legacyRuntimeConfigFromOpenworkConfig()` in [`apps/server/src/server.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/server.ts)
- **Runtime artifacts** are generated by `buildOpenworkRuntimeConfigObject()` in [`apps/server/src/openwork-runtime-config.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/openwork-runtime-config.ts) and written to [`openwork-runtime.json`](https://github.com/different-ai/openwork/blob/main/openwork-runtime.json)
- **API access** is provided through `/w/:workspaceId/openwork` endpoints in [`apps/server/src/routes/workspaces.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/routes/workspaces.ts), with mutations triggering coordinated reloads

## Frequently Asked Questions

### Where does OpenWork store global configuration settings?

OpenWork stores global Opencode settings in [`/.opencode/opencode.json`](https://github.com/different-ai/openwork/blob/main//.opencode/opencode.json) (or any user-provided JSON-C file). The server reads this file using `readJsoncFile()` from [`apps/server/src/workspace-files.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/workspace-files.ts) during startup to establish baseline defaults for provider definitions and MCP configurations.

### How does OpenWork handle workspace-specific configuration?

Workspace-specific settings are stored in the **runtime database** rather than flat files. When a workspace initializes, `defaultWorkspaceOpenworkConfig()` in [`apps/server/src/workspace-init.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/workspace-init.ts) creates a default record containing the workspace name, creation timestamp, authorized roots, and reload settings. The `seedOpenworkWorkspaceConfigIfEmpty()` function in [`apps/server/src/openwork-workspace-config-store.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/openwork-workspace-config-store.ts) ensures this record persists.

### What is the purpose of the [`openwork-runtime.json`](https://github.com/different-ai/openwork/blob/main/openwork-runtime.json) file?

The [`openwork-runtime.json`](https://github.com/different-ai/openwork/blob/main/openwork-runtime.json) file is a **derived artifact** generated on-the-fly by `buildOpenworkRuntimeConfigObject()` in [`apps/server/src/openwork-runtime-config.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/openwork-runtime-config.ts). It merges global Opencode settings, workspace-specific database records, and any legacy configurations into a single consumable format for the Electron engine process.

### How can I programmatically update OpenWork configuration?

Use the server API endpoints defined in [`apps/server/src/routes/workspaces.ts`](https://github.com/different-ai/openwork/blob/main/apps/server/src/routes/workspaces.ts). Send a `GET` request to `/w/:workspaceId/openwork` to read configuration, or a `PATCH` request (requiring owner scope) to modify it. The server persists changes via `writeOpenworkWorkspaceConfig()` and automatically schedules a reload using `reloadBaselineRefreshers` to synchronize the workspace state.