Types & tags
Tags are how Droplets find each other. Free-form tags are short labels anyone can attach; Types are curated tags that carry typed-field schemas the system renders, filters, and sorts.
Tags are how Droplets find each other. Most tags are free-form — short labels (onboarding, q3-2026, vendor-risk) that anyone with edit permission can attach. A small curated set are Types, which carry a schema of structured fields the system understands.
Tags (free-form)
A tag is a short string label on a Droplet. Anyone with edit permission can add or remove one. Tags aren't validated, they're not typed, and they don't carry extra information beyond the string itself. Most tags fit here — use them for whatever vocabulary your team finds useful.
The dashboard autocompletes against tags you and your collaborators have used. The search bar accepts tag:onboarding as a filter. Tags live on each Droplet as a normalized list (lowercased, trimmed, deduplicated).
Types
A Type is a tag that's been promoted into the typed-field registry. Promotion attaches a schema to the tag name — a curated set of structured fields the system expects when a Droplet wears it. Per feat/044, Types live at one of three scopes (USER / SPACE / GLOBAL); the scope determines who can curate the row.
For example, the recommendation Type carries:
status— one ofdraft,in-flight,decided,blocked(configurable per Type)progress— an integer 0–100 the system renders as a progress barpriority— one oflow,medium,high,urgentdue— a date the system renders as a countdown (or "Nd overdue")trafficLight— one ofred,yellow,greenowner— a user reference (renders as avatar + name)rice— a free-form numeric custom field for the RICE score
A Droplet wearing the recommendation Type has these fields available; their values render with their special widgets on the Droplet detail page, the /view strip below the Drop Bar, dashboard cards, and search results.
You don't pick "what type of Droplet this is" from a dropdown — you just add the Type to the Droplet like any other tag, and the schema kicks in. Removing the Type clears the structured fields; the Droplet's other tags stay put.
A Droplet can wear multiple Types. Fields from multiple type schemas combine additively; if two Types both declare a status field, the values are namespaced (recommendation.status vs decision.status) and rendered separately.
Primitive fields
The system knows how to render a small registry of primitive field types. A Type's schema opts into any subset of these. Primitives can't be redefined — they're baked into the platform so that progress always means the same thing across every Type.
| Field | Type | Renders as |
|---|---|---|
status | enum (per-tag values) | Coloured status pill |
progress | int 0–100 | Progress bar with percent label |
priority | enum: low / medium / high / urgent | Coloured swatch |
due | date | Countdown (in 12d) or overdue indicator (3d overdue, coral) |
trafficLight | enum: red / yellow / green | Coloured dot |
owner | user-ref | Avatar + display name |
The registry is hardcoded in lib/type-fields.ts — adding a new primitive is a code change, not a runtime config. This is deliberate: the renderable set stays small and well-understood. Anything more exotic lives in custom fields.
Type-bound custom fields
Beyond the primitives, a Type can declare custom fields of these basic types:
string— short label, max 100 charsint— integer (e.g.rice,impact-score)date— ISO datebool— true / falseenum— type-defined enum valuesuser-ref— pointer to a @himarley useruser-list— ordered list of users and/or user-groups (RAPID-style multi-principal). Stored as[{kind:'user'|'group', id}, …]. Group references resolve dynamically on read — if the group's membership changes, every Droplet referencing the group reflects the new membership without an edit.
Custom fields render as compact key:value pills in the chip rail (or, for user-list, a chip cluster of users + groups). They don't get the rich primitive widgets. They're searchable and sortable like primitives — except user-list, which is not yet wired into the search-operator parser (agreedBy:alice@himarley.com is on the roadmap).
Namespaced tags
Any tag with a colon is treated as namespaced — customer:acme, team:security, quarter:q3-2026. Namespacing is a visual convention, not a separate kind of tag: the chip renders the prefix in a muted style and the value in foreground, and the autocomplete groups suggestions by namespace.
Namespaced tags are still plain tags — no schema, no validation. They become useful when a vocabulary settles: customer:* for the customers your team works with, quarter:* for the quarter a piece of work belongs to. The tag can later be promoted to a Type if the team needs structured fields against it (per-scope curation permissions apply — see "Who can create Types" below).
Filtering & sorting
Structured fields extend the existing search operators. Examples:
tag:recommendation progress:>50 # ⌘K — recommendations more than half done
tag:incident priority:urgent due:<2026-07-01
tag:decision status:decided trafficLight:green
customer:acme tag:recommendation # namespace and Type combined
Sorting by a structured field uses the same syntax: sort:due-asc, sort:progress-desc. Saved Views can pin these queries.
Who can create Types
Tags: anyone with edit permission on a Droplet can add or remove them. No gate.
Types: scoped curation per feat/044. From the /types page in the sidebar (open to any authenticated user), curators can:
- Promote an existing tag to a Type, choosing which primitive fields opt in and declaring any custom fields
- Create a new Type from scratch
- Edit the schema of an existing Type (add fields, edit enum values, deprecate fields)
- Demote a Type back to a plain tag, optionally retaining or dropping its field values
Who can do each of those, on each tier:
- USER scope — the owner of the row (anyone authenticated, on their own row)
- SPACE scope — Space OWNER or EDITOR of the owning Space
- GLOBAL scope — LIBRARY_ADMIN (members of
@drop-library-admins)
Every promotion / demotion / schema edit lands in the audit log with the actor and timestamp. Demoted Types are retained for 30 days, after which orphaned field values are garbage-collected.
Drop is not Notion
Types are deliberately curated, not self-serve at every tier. Anyone can mint a USER-scope Type in their own namespace; SPACE Types require Space admin; GLOBAL Types require LIBRARY_ADMIN. The escalation is what keeps shared vocabularies coherent — anyone can experiment locally, but landing a Type in the org-wide namespace takes deliberate sign-off.
The right shape of the registry is small, well-defined, and shared. The wrong shape is "anything anyone needed once."
Operations
Add a tag to a Droplet
Any editor of a Droplet can add a tag from the chip editor on the detail page, or via the CLI at deploy time. Tags are normalized (lowercase, trimmed, deduped) on write. Maximum 20 tags per Droplet, 50 chars per tag.
# Set tags at deploy time
drop deploy my-page.html --slug my-droplet --tag onboarding --tag q3-2026
# Or update existing tags
drop tags add my-droplet onboarding q3-2026Promote a tag to a Type
Promotion attaches a schema to the tag name. The CLI surfaces the existing usage count as a courtesy, then mints the registry row. Existing Droplets wearing the tag don't change — their tag chip becomes a Type chip (navy-dot prefix) and the field widgets render in empty state until editors set values. Per feat/044, the gate is the target tier: USER tier = anyone; SPACE tier = Space admin; GLOBAL tier = LIBRARY_ADMIN.
drop tags promote recommendation \
--description "A proposal awaiting decision." \
--primitive status:enum:draft,in-flight,decided,blocked \
--primitive progress \
--primitive priority \
--primitive due \
--primitive trafficLight \
--primitive owner \
--custom rice:int \
--custom quarter:stringSet structured field values on a Droplet
Once a Droplet wears a Type, its editors can set the structured field values. Click any widget in the header strip or use the CLI. Values are validated against the Type's schema; null clears a field.
drop set onboarding-redesign \
--tag recommendation \
--field status=in-flight \
--field progress=74 \
--field due=2026-06-30 \
--field priority=high
# Inspect
drop get onboarding-redesign --fieldsSearch by structured field
The type: operator filters by Type-by-name — type:decision, type:inform, type:recommendation. Structured-field operators filter and sort by per-Type values. Mix freely with from:, before:, etc. Operators are exact match; typos fall back to free-text pg_trgm matching.
The command palette (⌘K) autocompletes values for every operator — type status: and press Tab to pick from the active Types' enum vocabulary.
# Recommendations in flight — Jonathan's go-to query
drop search "type:recommendation status:in-flight"
# Recommendations with a yellow traffic light
drop search "type:recommendation light:yellow"
# Open recommendations more than halfway done, high priority
drop search "type:recommendation status:in-flight progress:>50 priority:high"
# Incidents due this week, sorted by due ascending
drop search "type:incident due:thisweek sort:due-asc"
# Everything that's overdue, regardless of Type
drop search "due:overdue sort:due-asc"
# All work for the Acme customer
drop search "customer:acme"
# Combine with a person and a date
drop search "type:decision from:kate before:2026-09-01"Operator cheatsheet
Every operator the search bar understands. Combine with spaces — they AND together. The palette's bottom panel (? to toggle) renders the same list grouped by purpose.
Filter by Type type:recommendation type:decision
Match a status status:in-flight status:decided
Priority priority:high priority:urgent
Progress progress:>50 progress:<=20
Due date due:overdue due:thisweek
due:<2026-07-01 due:>2026-06-01
Traffic light light:yellow light:red
Sort sort:due-asc sort:progress-desc
Owner (field) owner:jonathan
Author (Droplet) from:jonathan @jonathan
Tag tag:design #design
Namespaced tag customer:acme team:eng
Scope to Space space:engineering >engineering
Audience access:private access:everyone
Shared with me shared:me
Starred is:starred
Archived is:archived
Updated date before:2026-01-01 after:2026-05-01