# How OpenWork Den Enforces Organization-Level Desktop Policies

> Learn how OpenWork Den enforces organization-level desktop policies by fetching configurations from OpenWork Cloud API and gating UI features with effective permissions.

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

---

**OpenWork Den enforces organization-level desktop policies by fetching a scoped configuration from the OpenWork Cloud API, caching it locally, and exposing typed React hooks that gate UI features based on calculated effective permissions.**

The `different-ai/openwork` repository implements a three-layer architecture that separates policy definition, delivery, and consumption. This design ensures that enterprise administrators can centrally control desktop application capabilities while maintaining consistent enforcement across the Den web interface and desktop clients.

## Policy Architecture Overview

The enforcement system relies on a strict separation between **what can be restricted**, **how restrictions are delivered**, and **how features consume those restrictions**. Each layer has a dedicated source file that handles its specific responsibility without leaking implementation details to other layers.

- **Definition Layer**: Canonical schema and calculation logic in [`packages/types/src/den/desktop-policies.ts`](https://github.com/different-ai/openwork/blob/main/packages/types/src/den/desktop-policies.ts)
- **Delivery Layer**: Cloud API integration and React context in [`apps/app/src/react-app/domains/cloud/desktop-config-provider.tsx`](https://github.com/different-ai/openwork/blob/main/apps/app/src/react-app/domains/cloud/desktop-config-provider.tsx)
- **Consumption Layer**: Typed hooks that components use to check permissions at render time

## Policy Definition Layer

### Canonical Policy Schema

All desktop policies originate from [`packages/types/src/den/desktop-policies.ts`](https://github.com/different-ai/openwork/blob/main/packages/types/src/den/desktop-policies.ts), which exports a comprehensive catalog of boolean restriction flags. Each policy entry includes an `id`, user-facing `name`, `description`, `notice` text shown when disabled, and a safe `defaultValue`.

The file also exports `calculateEffectiveDesktopPolicy()`, the core function that determines what a user can actually do based on their organization's policy assignments:

```typescript
export function calculateEffectiveDesktopPolicy(input: {
  orgPolicyCount: number;
  defaultPolicy?: unknown;
  assignedPolicies: unknown[];
}): Required<DesktopPolicyValue>

```

This function implements a safe-by-default security model:

1. Initializes all policy keys to `false` (restricted)
2. If the organization has **no policies**, returns `allDesktopPolicies(true)` — granting full access
3. Otherwise, performs an **OR-union** across the default policy and all assigned policies, where any `true` value for a key lifts the restriction

This logic ensures that organizations can only tighten restrictions (set values to `false`); missing or undefined policy data defaults to allowing the feature, preventing accidental lockouts.

## Policy Delivery and Caching

### DesktopConfigProvider Implementation

The `DesktopConfigProvider` in [`apps/app/src/react-app/domains/cloud/desktop-config-provider.tsx`](https://github.com/different-ai/openwork/blob/main/apps/app/src/react-app/domains/cloud/desktop-config-provider.tsx) manages the lifecycle of policy data. On initialization, it fetches the organization-scoped configuration via `GET /v1/me/desktop-config` using the active organization ID.

The provider implements a cache-first strategy:

- **Initial load**: Reads from `localStorage` via `readCachedDenDesktopConfig()` for instant UI rendering
- **Fresh fetch**: Calls `createDenClient(...).getDesktopConfig(activeOrgId)` to retrieve the latest policy
- **Cache update**: Writes the fresh payload to `localStorage` via `writeCachedDenDesktopConfig()`

### Refresh and Synchronization Strategy

The provider maintains policy freshness through multiple triggers:

- **Timed refresh**: Automatically re-fetches every `DESKTOP_CONFIG_REFRESH_MS` (1 hour)
- **Event-driven refresh**: Listens for `denSessionUpdatedEvent` and `denSettingsChangedEvent` to update immediately when authentication or Den settings change
- **Manual refresh**: Exposes `refresh()` and `refreshFresh()` methods via the React context for forced updates

## Policy Consumption and Enforcement

### The Hook API

Feature components consume policies through three specialized hooks exported from the provider:

- **`useCheckDesktopRestriction()`** – Returns a stable checker function for dynamic key evaluation
- **`useDesktopRestriction(key)`** – Returns a boolean for a specific policy flag
- **`useDesktopConfig()`** – Returns the raw config object, loading state, and manual refresh function

These hooks internally call `checkDesktopAppRestriction()`, which consults the effective policy calculated by `calculateEffectiveDesktopPolicy()`.

### UI Gating Examples

Components gate functionality by checking restrictions before rendering or enabling interactions:

**Hiding a feature based on policy:**

```tsx
import { useCheckDesktopRestriction } from "../domains/cloud/desktop-config-provider";

function ModelPicker() {
  const check = useCheckDesktopRestriction();
  const zenRestricted = check({ restriction: "allowZenModel" });
  
  return zenRestricted ? null : <ZenModelPicker />;
}

```

**Disabling UI elements:**

```tsx
import { useDesktopRestriction } from "../domains/cloud/desktop-config-provider";

function AddWorkspaceButton() {
  const multipleWorkspacesBlocked = useDesktopRestriction("allowMultipleWorkspaces");
  
  return (
    <button disabled={multipleWorkspacesBlocked}>
      Add workspace
    </button>
  );
}

```

**Accessing raw configuration for debugging:**

```tsx
import { useDesktopConfig } from "../domains/cloud/desktop-config-provider";

function DesktopPolicyDebug() {
  const { config, loading } = useDesktopConfig();
  
  if (loading) return <Spinner />;
  return <pre>{JSON.stringify(config, null, 2)}</pre>;
}

```

## Summary

- **Policy definitions** live in [`packages/types/src/den/desktop-policies.ts`](https://github.com/different-ai/openwork/blob/main/packages/types/src/den/desktop-policies.ts) as a type-safe catalog of boolean flags with safe defaults
- **Policy calculation** uses `calculateEffectiveDesktopPolicy()` to OR-union multiple policy sources, defaulting to permissive when no policies exist
- **Policy delivery** occurs through `DesktopConfigProvider`, which fetches from `GET /v1/me/desktop-config` and caches in `localStorage`
- **Auto-refresh** happens hourly and on authentication events, with manual refresh options available
- **Feature gating** uses `useCheckDesktopRestriction()` or `useDesktopRestriction()` hooks to conditionally render or disable UI elements

## Frequently Asked Questions

### How does OpenWork Den handle missing or empty organization policies?

When an organization has no assigned policies (`orgPolicyCount === 0`), the `calculateEffectiveDesktopPolicy()` function returns `allDesktopPolicies(true)`, enabling every feature. This safe default prevents accidental lockouts while allowing administrators to explicitly opt into restrictions by assigning policies that set specific flags to `false`.

### What hooks are available for checking desktop restrictions?

OpenWork Den provides three hooks in [`desktop-config-provider.tsx`](https://github.com/different-ai/openwork/blob/main/desktop-config-provider.tsx): `useCheckDesktopRestriction()` returns a checker function suitable for dynamic evaluations; `useDesktopRestriction(key)` returns a boolean for a specific policy ID; and `useDesktopConfig()` exposes the raw configuration object along with loading states and refresh controls.

### How often does the desktop app refresh policy configurations?

The `DesktopConfigProvider` refreshes policy data automatically every hour (`DESKTOP_CONFIG_REFRESH_MS` constant) and immediately upon `denSessionUpdatedEvent` or `denSettingsChangedEvent` events. Additionally, components can trigger manual refreshes via the `refresh()` method exposed through the context.

### Where are desktop policies defined in the codebase?

Desktop policies are defined in [`packages/types/src/den/desktop-policies.ts`](https://github.com/different-ai/openwork/blob/main/packages/types/src/den/desktop-policies.ts), which contains the canonical schema, Zod validation, normalization utilities, and the effective policy calculation logic. High-level documentation exists in [`docs/desktop-app-policies.md`](https://github.com/different-ai/openwork/blob/main/docs/desktop-app-policies.md), while the React integration lives in [`apps/app/src/react-app/domains/cloud/desktop-config-provider.tsx`](https://github.com/different-ai/openwork/blob/main/apps/app/src/react-app/domains/cloud/desktop-config-provider.tsx).