How to Set Up OpenWork Desktop Policies for Enterprise‑Wide Configuration Management

OpenWork uses desktop policies backed by the Den backend to enforce consistent security and feature settings across every desktop client in an organization through a version‑stable REST API.

OpenWork's desktop policy system gives enterprise administrators centralized control over how desktop clients behave throughout their organization. This guide walks through the complete setup—from policy definition to client enforcement—using the actual source code implementation in the different-ai/openwork repository.


Core Concepts of OpenWork Desktop Policies

Understanding the policy architecture starts with four fundamental building blocks defined in packages/types/src/den/desktop-policies.ts.

The Desktop‑Policy Catalog

OpenWork maintains a canonical catalog of all possible policy items at packages/types/src/den/desktop-policies.ts (lines 11–15). Each catalog entry includes a safe default value, ensuring organizations without explicit configuration still receive predictable behavior.

// Canonical desktop policy catalog.
// Each key represents a configurable behavior with enterprise-safe defaults

Policy Value Normalization

All policy values—whether from API payloads or the KV store—pass through normalization functions to guarantee type safety. The normalizeDesktopPolicyValue function (lines 326–330) coerces and validates raw data:

const policy = normalizeDesktopPolicyValue(coerced);
// Guarantees proper shape and types regardless of input source

For default values, use normalizeDefaultDesktopPolicyValue instead.

The Default Policy Requirement

Every organization must maintain exactly one default policy flagged isDefault: true. When clients cannot locate a specific policy assignment, they fall back to this default (lines 371–376):

if (policy.isDefault === true) {
  // This policy serves as the organization-wide fallback
}

Policy Boolean Conventions

Policy flags follow an "allow‑style" naming convention: allowFileSharing, requireSignIn, allowAutoUpdates. The evaluation logic treats any absent or unknown flag as false (lines 22–25), making policies secure by omission.


Policy Storage and API Architecture

Backend Storage: Den KV Store

Policies persist in Den's KV store via the WorkspaceKvStore class:

// apps/server/src/workspace-kv-store.ts (lines 1-20)
export class WorkspaceKvStore {
  // Handles persistence for desktop policies and other workspace data
}

REST API Endpoints

The /v1/desktop-policies endpoints expose full CRUD operations, protected by organization‑level authentication:

Method Path Purpose
GET /v1/desktop-policies List all organization policies
GET /v1/desktop-policies/:policyId Retrieve specific policy
POST /v1/desktop-policies Create new policy
PATCH /v1/desktop-policies/:policyId Update existing policy or change default
DELETE /v1/desktop-policies/:policyId Remove non‑default policy

Implementation details reside in apps/server/src/workspaces.ts.


Step‑by‑Step: Setting Up Enterprise Desktop Policies

Step 1: Define Your Policy Configuration

Select values from the catalog. Common enterprise settings include:

const enterprisePolicy = {
  policyName: 'Enterprise-Standard',
  isDefault: false,      // Will set as default in Step 3
  isEnabled: true,
  // Security and feature flags
  allowFileSharing: true,
  requireSignIn: true,
  allowAutoUpdates: false,
  allowExternalIntegrations: false,
};

Step 2: Create the Policy via API

const response = await fetch('https://your-den.example.com/v1/desktop-policies', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${ORG_ADMIN_TOKEN}`,
  },
  body: JSON.stringify(enterprisePolicy),
});

const createdPolicy = await response.json();
// Save createdPolicy.id for Step 3

Step 3: Designate the Default Policy

const { id: policyId } = createdPolicy;

await fetch(`https://your-den.example.com/v1/desktop-policies/${policyId}`, {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${ORG_ADMIN_TOKEN}`,
  },
  body: JSON.stringify({ isDefault: true }),
});

Step 4: Verify Client‑Side Consumption

Desktop clients poll /v1/desktop-policies/:orgId at startup. Implement policy reading with normalization:

import { normalizeDesktopPolicyValue } from '@/packages/types/src/den/desktop-policies';

export function useDesktopPolicy() {
  const [policy, setPolicy] = useState(null);

  useEffect(() => {
    fetch('/v1/desktop-policies')
      .then(r => r.json())
      .then(policies => {
        const raw = policies.find((p) => p.isDefault) ?? policies[0];
        setPolicy(normalizeDesktopPolicyValue(raw));
      });
  }, []);

  return policy;
}

Step 5: Conditional UI Enforcement

const policy = useDesktopPolicy();

return (
  <>
    {policy?.allowFileSharing ? (
      <FileSharingPanel />
    ) : (
      <DisabledFeature message="File sharing is disabled by your organization." />
    )}
    
    {policy?.requireSignIn && <MandatorySignInGate />}
  </>
);

Client‑Side Policy Evaluation

The desktop client implementation in packages/ui/src/react/platform-detect.ts demonstrates how policy values drive runtime behavior. Always normalize API responses before use:

import { normalizeDesktopPolicyValue } from '@/packages/types/src/den/desktop-policies';

// rawPolicy comes from /v1/desktop-policies endpoint
const policy = normalizeDesktopPolicyValue(rawPolicy);

if (policy.allowFeatureX) {
  // Enable corresponding UI or capability
}

This pattern ensures forward compatibility—new policy fields added to the catalog won't break existing clients.


Enterprise Roll‑Out Best Practices

Adding New Policy Fields

The catalog design enables safe extension through three steps:

  1. Add comment documentation in desktop-policies.ts
  2. Define a secure default value
  3. (Optional) Add UI hook for client-side enforcement

Existing clients ignore unknown fields, making enterprise-wide rollouts predictable.

Policy Update Propagation

Changes propagate automatically:

  • New launches: Clients fetch current policy on startup
  • Running clients: Receive updates via live-reload channel (if implemented)
  • Verification: Check evals/specs/models-available.slow.test.ts for CRUD and default-policy test patterns

Summary

  • Desktop policies in OpenWork centralize configuration through Den's KV-backed REST API at /v1/desktop-policies
  • Every organization requires exactly one default policy (isDefault: true) as defined in packages/types/src/den/desktop-policies.ts lines 371–376
  • Always normalize values using normalizeDesktopPolicyValue before consumption to guarantee type safety
  • Secure by omission: Unknown or missing boolean flags evaluate to false
  • Three-step extension: Adding catalog fields requires only documentation, default value, and optional UI hook

Frequently Asked Questions

How does OpenWork handle policy conflicts when multiple policies exist?

Organizations may create multiple policies for different use cases, but only one can be isDefault: true. When clients request their policy assignment, the backend returns either a directly assigned policy or the default. The normalizeDesktopPolicyValue function ensures consistent interpretation regardless of which policy applies.

Can I migrate an existing policy to become the default?

Yes. Use the PATCH endpoint to set isDefault: true on any existing policy. The backend automatically removes the default flag from the previous default policy. Reference the implementation in apps/server/src/workspaces.ts and the test verification in evals/specs/models-available.slow.test.ts.

What happens if a client receives a policy with unknown fields?

Unknown fields are preserved through normalization but ignored by client code. This forward-compatibility design—implemented in normalizeDesktopPolicyValue at lines 326–330—allows enterprises to preview new policy features before updating desktop clients organization-wide.

How do I validate policy changes before enterprise deployment?

Create policies with isDefault: false initially, then assign them to test users or groups. Once validated, PATCH the policy to isDefault: true or assign it to production users. The normalization functions in packages/types/src/den/desktop-policies.ts ensure test and production policies behave identically.

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 →