# How to Configure app.json Manifest for Permissions, Windows, and Security Policies in Native SDK

> Learn to configure the app.json manifest for Native SDK permissions, security policies, and window configurations. Control global capabilities and bridge command restrictions effectively.

- Repository: [Vercel Labs/native](https://github.com/vercel-labs/native)
- Tags: how-to-guide
- Published: 2026-07-18

---

**The Native SDK uses an `app.zon` manifest file (Zig Object Notation) to declare global capabilities, window-specific security policies, and bridge command restrictions, which are parsed by `src/tooling/manifest.zig` and enforced at runtime by the security layer in `src/runtime/builtin_bridge.zig`.**

The vercel-labs/native repository provides a Native SDK that requires explicit capability declarations through a manifest file. While developers often search for [`app.json`](https://github.com/vercel-labs/native/blob/main/app.json) configuration patterns, this SDK implements a strict schema using `app.zon` (Zig Object Notation) to define permissions, window properties, and security policies that the runtime validates before executing privileged operations.

## Understanding the Manifest Format and Location

Unlike traditional Electron or React Native apps that use [`app.json`](https://github.com/vercel-labs/native/blob/main/app.json), the Native SDK expects a root-level `app.zon` file. This file is parsed during the build process by `src/tooling/manifest.zig`, specifically through the `readMetadata` function, which validates the schema defined in `src/tooling/raw_manifest.zig`.

The manifest structure consists of three primary security layers:

- **Global permissions** – Capabilities granted to the entire application
- **Window configurations** – Individual window properties with optional security overrides
- **Bridge commands** – API endpoints with explicit permission requirements and origin whitelists

## Configuring Global Permissions

Global permissions are defined in the root `permissions` array. According to `src/primitives/app_manifest/types.zig` (around lines 231-239), valid permission strings include `"window"`, `"filesystem"`, `"network"`, `"clipboard"`, and `"credentials"`.

The `parsePermissions` function in `src/tooling/manifest.zig` processes these entries, using `duplicateStringList` to allocate the permission strings. Invalid entries trigger diagnostics via `manifest.printDiagnostic`, while the `validatePermissions` function in `src/primitives/app_manifest/validation.zig` ensures only recognized capability tokens are accepted.

```zon
{
  name = "my-app",
  version = "1.0.0",
  
  // Global permissions required by the app
  permissions = .{ "window", "filesystem", "network" },
}

```

## Defining Window Configurations and Security Policies

Window definitions reside in the `windows` array, where each object can optionally include a `security` block to override global permissions or restrict origins.

### Window-Specific Permission Overrides

When a window defines a `security.permissions` array, the runtime uses these instead of the global set. As implemented in `src/runtime/builtin_bridge.zig`, the security check logic evaluates:

```zig
if (self.options.security.permissions.len > 0) {
    // Use the provided list
    policy.permissions = self.options.security.permissions;
} else {
    // Fallback to global permissions
    policy.permissions = metadata.permissions;
}

```

If the security block is omitted, the window inherits all global permissions defined in the root `permissions` array.

### Origin Whitelisting

The `security.origins` array restricts which contexts can execute bridge commands within a specific window. This prevents unauthorized code from accessing privileged APIs even if the global permissions would otherwise allow it.

```zon
windows = .{
  {
    name = "main",
    width = 800,
    height = 600,
    security = {
      permissions = .{ "window", "clipboard" },
      origins = .{ "zero://app", "https://example.com" },
    },
  },
},

```

## Bridge Commands and Security Enforcement

Bridge commands declared in the `bridge_commands` array define explicit permission requirements via the `permissions` field. The runtime enforces these through `security.hasPermission` in `src/runtime/builtin_bridge.zig`, checking both the permission token and the origin against the whitelist before executing the command.

```zon
bridge_commands = .{
  {
    name = "native.ping",
    permissions = .{ "filesystem" },
    origins = .{ "zero://app" },
  },
},

```

If a command originates from a context not listed in `origins`, or if the required permission is missing from either the window-specific or global permission set, the bridge denies the call and logs a security error.

## Complete Configuration Examples

### Minimal Manifest with Global Permissions

```zon
{
  name = "hello",
  version = "0.1.0",
  permissions = .{ "window", "network" },
}

```

### Window-Specific Security Overrides

```zon
{
  name = "notes",
  version = "2.0.0",
  permissions = .{ "window", "filesystem", "network" },

  windows = .{
    {
      name = "viewer",
      width = 400,
      height = 800,
      security = {
        permissions = .{ "window" },
      },
    },
    {
      name = "editor",
      width = 800,
      height = 600,
    },
  },
}

```

### Strict Origin and Permission Restrictions

```zon
{
  name = "secure-app",
  version = "1.0.0",
  permissions = .{ "window", "network" },

  windows = .{
    {
      name = "main",
      width = 1024,
      height = 768,
      security = {
        permissions = .{ "window" },
        origins = .{ "zero://app", "https://trusted.example.com" },
      },
    },
  },

  bridge_commands = .{
    {
      name = "native.secure.fetch",
      permissions = .{ "network" },
      origins = .{ "https://trusted.example.com" },
    },
  },
}

```

## Summary

- The Native SDK uses `app.zon` (Zig Object Notation) rather than JSON, parsed by `src/tooling/manifest.zig` via the `readMetadata` function.
- Global permissions are defined in the root `permissions` array and validated through `src/primitives/app_manifest/validation.zig`.
- Windows can override global permissions through a `security` block containing a `permissions` array and optional `origins` whitelist.
- Bridge commands enforce runtime security checks using `security.hasPermission` in `src/runtime/builtin_bridge.zig`, requiring both the permission token and origin validation.
- The concrete implementation example is available in `tools/guest-mac/app.zon` within the vercel-labs/native repository.

## Frequently Asked Questions

### Is the manifest file JSON or ZON format?

The Native SDK uses `app.zon` (Zig Object Notation), not JSON. While the syntax resembles JSON with structural types, it uses Zig-specific constructs like anonymous lists (`.{ "item" }`) and assignment syntax (`=` instead of `:`). The tooling in `src/tooling/manifest.zig` parses this format natively.

### How do window-specific permissions interact with global permissions?

Window-specific permissions defined in `windows[*].security.permissions` completely replace the global permission set for that window. If the security block is absent, the window inherits all global permissions. This is handled by the conditional logic in `src/runtime/builtin_bridge.zig` that checks `self.options.security.permissions.len` before falling back to `metadata.permissions`.

### What happens if a bridge command lacks the required permission?

The runtime denies the command execution. When a bridge command is invoked, `src/runtime/builtin_bridge.zig` validates that the command's required permissions exist in the current security context (either window-specific or global). If validation fails, the SDK logs a security error and rejects the operation without executing the native code.

### Where is the manifest validation logic located?

Validation occurs across three files: `src/tooling/manifest.zig` handles parsing and structural validation, `src/primitives/app_manifest/types.zig` defines the permission constants and structures, and `src/primitives/app_manifest/validation.zig` contains the `validatePermissions` function that verifies permission strings against the allowed set.