---
title: "DropletManifest, DroppyKit"
description: "The contents of a droplet&#x27;s droplet.json."
canonical: "https://getdroppy.app/docs/droppykit/api/droplet-manifest"
last-updated: "2026-09-09"
---

# DropletManifest

The contents of a droplet's droplet.json.

`struct DropletManifest`

```
{
  "id": "worldclock",
  "name": "World Clock",
  "version": "1.0.0",
  "summary": "Every timezone you care about, on the shelf",
  "category": "Productivity",
  "kit": { "abi": 1, "minAPI": "1.0.0" },
  "minAppVersion": "15.3.0",
  "capabilities": ["shelf-read"],
  "surfaces": ["shelf-widget", "settings-pane"],
  "icon": "WorldClock.icon",
  "creator": {
    "name": "Jane Doe",
    "kind": "community",
    "url": "https://jane.example",
    "avatar": "Creator.png"
  },
  "source": {
    "repository": "https://github.com/jane/worldclock-droplet",
    "commit": "9f1c2ab5c0e4d3f6a7b8c9d0e1f2a3b4c5d6e7f8",
    "license": "MIT"
  }
}
```

## Initializers

### init(from:)

`init(from decoder: Decoder) throws`

### init(id:name:version:summary:description:category:kit:minAppVersion:capabilities:surfaces:icon:creator:source:screenshots:keywords:)

`init(id: DropletID, name: String, version: SemanticVersion, summary: String, description: String? = nil, category: String, kit: DropletKitRequirement, minAppVersion: String, capabilities: [DropletPermission] = [], surfaces: [DropletSurface], icon: String, creator: DropletCreator, source: DropletSource? = nil, screenshots: [String] = [], keywords: [String] = [])`

### init(id:name:version:summary:description:category:kit:minAppVersion:minMacOS:capabilities:surfaces:icon:creator:source:screenshots:keywords:)

`init(id: DropletID, name: String, version: SemanticVersion, summary: String, description: String? = nil, category: String, kit: DropletKitRequirement, minAppVersion: String, minMacOS: String?, capabilities: [DropletPermission] = [], surfaces: [DropletSurface], icon: String, creator: DropletCreator, source: DropletSource? = nil, screenshots: [String] = [], keywords: [String] = [])`

Creates a manifest that names a minimum macOS. A second initializer rather than a defaulted parameter, so the 1.0 initializer keeps its symbol.

## Type properties

### summaryCharacterLimit

`static let summaryCharacterLimit: Int`

The longest summary the Store's row renders without truncating.

## Properties

### capabilities

`let capabilities: [DropletPermission]`

Capabilities the droplet needs. The user sees these before installing, so ask for what you use and nothing else — a long list is the single biggest reason a submission is sent back.

### category

`let category: String`

The Store section this droplet appears under: one of [`DropletCategory`](https://getdroppy.app/docs/droppykit/api/droplet-category)'s values, matched case-insensitively, so `"Productivity"` and `"productivity"` are the same shelf.

Kept as a `String` rather than the enum so a manifest written against a later SDK still decodes here; `validate(submission:)` is what refuses a value no Store section can show.

### creator

`let creator: DropletCreator`

Who made it.

### description

`let description: String?`

The long description on the detail page. Markdown is not rendered; keep it plain paragraphs separated by blank lines.

### icon

`let icon: String`

Filename of the Icon Composer document, relative to the droplet's root. **Required**, and it must be a real `.icon` document rather than a PNG — see [`DropletIcon`](https://getdroppy.app/docs/droppykit/api/droplet-icon).

### id

`let id: DropletID`

Stable identifier. Must match [`id`](https://getdroppy.app/docs/droppykit/api/droplet#id) and the bundle's `DroppyDropletID`. Lowercase for public submissions.

### keywords

`let keywords: [String]`

Search keywords beyond the name and summary.

### kit

`let kit: DropletKitRequirement`

Which DroppyKit this was built against.

### minAppVersion

`let minAppVersion: String`

Oldest Droppy this droplet runs in, for example `"15.3.0"`.

### minMacOS

`let minMacOS: String?`

Oldest macOS this droplet runs on, for example `"26.0"`, when it needs more than Droppy does. The Store does not offer it to an older Mac and Droppy does not load it there. Omit it to run wherever Droppy runs. Since 1.12.0.

### name

`let name: String`

Display name, sentence case.

### screenshots

`let screenshots: [String]`

Screenshot filenames, relative to `Assets/`. The first is the one the Store shows on the droplet's card.

### source

`let source: DropletSource?`

Where the source lives. Required for community droplets; omitted for first-party ones, whose source is not public.

### summary

`let summary: String`

One line, shown under the name in the Store. Aim for under 60 characters so it does not truncate at the Store's row width.

### surfaces

`let surfaces: [DropletSurface]`

Surfaces this droplet provides.

### version

`let version: SemanticVersion`

Droplet version, `major.minor.patch`. Numeric-dotted only: a pre-release tag cannot be published, because the fleet's catalog decode is strict and would refuse the whole catalog.

## Type methods

### isNumericDotted(_:)

`static func isNumericDotted(_ version: String) -> Bool`

Whether a version string is components of digits separated by dots, and nothing else.

The rule everywhere: `DropletHostDescriptor.numericVersionCompare` reads each component as an integer and an unparseable one as zero, so anything that is not this compares as something other than what it reads as.

### isReleaseVersion(_:)

`static func isReleaseVersion(_ version: String) -> Bool`

Whether a release artifact has the exact three-component version the Store and repository updater publish.

## Methods

### validate(submission:)

`func validate(submission: Bool = false) throws`

Checks everything that can be checked from the manifest alone.

Pass `submission: true` for a community submission, which adds the rules that only apply to third-party droplets: a lowercase id, a declared public repository, and `creator.kind == .community`.

This is the same check `Scripts/validate-droplet.sh` runs, so a droplet that validates locally validates at intake.
