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:
- Add comment documentation in
desktop-policies.ts - Define a secure default value
- (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.tsfor 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 inpackages/types/src/den/desktop-policies.tslines 371–376 - Always normalize values using
normalizeDesktopPolicyValuebefore 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →