---
title: Meeting
kind: resource
slug: meeting
summary: "A recurring session — Ops Core, Partner Core — with members, a schedule, and an agenda that builds itself from the decisions and informs queued for it."
---

# Meeting

A recurring session — Ops Core, Partner Core — with members, a schedule, and an agenda that builds itself from the decisions and informs queued for it.

A **meeting** is a recurring session the organisation actually holds. It carries three things: a **purpose** (what belongs here and what does not), **members** with roles, and an **agenda** — which nobody assembles by hand. Queue a decision or an inform for a meeting and it appears on that meeting's next sitting.

**Scheduling is week-precise, deliberately.** A meeting has a cadence (`WEEKLY` or `BIWEEKLY`) and a day, and `timeLabel` is display-only text like `"Tue 3:00 PM ET"` — it is never parsed. Real meetings move by a day or an hour and nobody re-files the calendar; committing to more precision than that would be committing to a lie. A bi-weekly meeting also needs an `anchorDate` — any date it actually sits — which is what tells the server which fortnight is the on week.

**Members mirror Spaces and User Groups**, on purpose: one vocabulary for "a named thing with people in it". A member is an `OWNER` (may edit the meeting and its roster) or a `PARTICIPANT` (in the room). There is no editor rung — there is nothing between running a meeting and attending it. A meeting always keeps at least one owner: demoting or removing the last one is refused, because a meeting with no owner has nobody who can appoint one.

**The agenda is access-filtered per topic.** Everyone in the beta can see that a meeting exists and who is on it; the topics on its agenda are each checked against your Droplet access, so you see only what you could already read. Adding a `@group` to the roster expands it to that group's members *at that moment* — the roster does not follow the group afterwards.

**What you can do:**

- **`list`** / **`retrieve`** — the inventory, and one meeting with its agenda: what is on deck for the next sitting, what closed since the last one, and what is queued further out. Pass `includeArchived` to `list` to find archived meetings.
- **`create`** / **`update`** — people admins create and edit; `archive` / `restore` take a meeting out of the listing without severing anything, so restoring brings the agenda back as it was.
- **`members`** — `list-attendees`, `add-attendees` (people and/or `@group` slugs), `remove-attendee`, `set-member-role`.
- **`set-topic`** / **`get-topic`** — queue a Droplet onto a meeting's agenda, or ask which meeting it is queued for. Queuing is a property of the TOPIC, so you do not need to own the meeting to put your own item on it.

Queuing writes `App.meetingId`, a real relationship rather than a field value — which is why archiving a meeting keeps its topics linked, and deleting one would clear the link rather than orphan it.

## The Meeting object

### Attributes

- **`slug`** `string` — Stable URL identifier, e.g. `ops-core`. Set at creation and never auto-derived afterwards, so links keep working.
- **`name`** `string` — Display name, e.g. "Ops Core".
- **`description`** `string · nullable` — The PURPOSE — what belongs at this meeting and what does not. This is the field that answers "does my topic go here or somewhere else".
- **`cadence`** `string` (enum: `WEEKLY` / `BIWEEKLY`) — How often it sits.
- **`dayOfWeek`** `int` — ISO-8601 weekday: 1 = Monday … 7 = Sunday.
- **`timeLabel`** `string · nullable` — Display-only, e.g. "Tue 3:00 PM ET". NOT parsed — the schedule's precision is the week.
- **`scheduleLabel`** `string` — Human rendering of cadence + day, e.g. "Tuesdays, every two weeks".
- **`nextWeekLabel`** `string` — When it next sits, relative: "this week", "next week", or "week of 15 Sep".
- **`nextWeekStart`** `string` — ISO date of the Monday starting the next occurrence's week. The machine-readable counterpart to `nextWeekLabel`.
- **`ownerName`** `string · nullable` — Display name of the creating owner. Permission follows member roles, not this field.
- **`attendeeCount`** `int` — How many members the meeting has.
- **`space`** `json · nullable` — The Space carrying this meeting's content, when one is linked: `{ name, slug }`.
- **`queuedCount`** `int` — Unclosed topics dated on or before the next occurrence — what is ON DECK.
- **`laterCount`** `int` — Unclosed topics dated beyond the next occurrence. Counted separately so something scheduled ahead is never invisible and never inflates this week.
- **`archivedAt`** `string · nullable · less-common` — Set once archived. Only returned when `includeArchived` was requested; without it, archived meetings are absent entirely.

### JSON example

```json
{
  "slug": "ops-core",
  "name": "Ops Core",
  "description": "Operations Core. Overlaps Partner Core on Tuesday afternoons — confirm alternating weeks.",
  "archivedAt": null,
  "cadence": "BIWEEKLY",
  "dayOfWeek": 2,
  "timeLabel": "Tue 3:00 PM ET",
  "scheduleLabel": "Tuesdays, every two weeks",
  "nextWeekLabel": "next week",
  "nextWeekStart": "2026-09-01",
  "ownerName": "Aurea Nunes",
  "attendeeCount": 6,
  "space": { "name": "Operations", "slug": "operations" },
  "queuedCount": 3,
  "laterCount": 1
}
```

## Methods

### Which meeting is a topic queued for

`GET /api/apps/{slug}/meeting`

The meeting a Droplet is queued for, or null. Exists because the picker has to render its CURRENT value: without it the control always read "No meeting" even on a topic that had one, so setting a meeting looked like it had not saved.

**CLI**

```bash
drop topics get-meeting ops-inform-infra
```

**MCP**

```json
{
  "tool": "drop_topic_get_meeting",
  "arguments": {
    "slug": "ops-inform-infra"
  }
}
```

**HTTP**

```bash
curl -X GET 'https://drop.himarley.ai/api/apps/ops-inform-infra/meeting' \
  -H "Authorization: Bearer $DROP_TOKEN"
```

**Response** (200)

```json
{
  "slug": "example",
  "meeting": "example"
}
```

### List meetings

`GET /api/meetings`

Every recurring meeting, with its cadence, when it next sits, and how many topics are queued for it. The answer to "what is coming up and where".

**CLI**

```bash
drop meetings list
```

**MCP**

```json
{
  "tool": "drop_meeting_list",
  "arguments": {}
}
```

**HTTP**

```bash
curl -X GET 'https://drop.himarley.ai/api/meetings' \
  -H "Authorization: Bearer $DROP_TOKEN"
```

**Response** (200)

```json
{
  "items": []
}
```

### Get a meeting and its agenda

`GET /api/meetings/{slug}`

A meeting with its generated agenda. The agenda is NOT stored — it is the unclosed topics pointing at this meeting, so it can never drift from their real state the way a written one does. Scoped to the caller: you only see topics you can read.

**CLI**

```bash
drop meetings get ops-core
```

**MCP**

```json
{
  "tool": "drop_meeting_get",
  "arguments": {
    "slug": "ops-core"
  }
}
```

**HTTP**

```bash
curl -X GET 'https://drop.himarley.ai/api/meetings/ops-core' \
  -H "Authorization: Bearer $DROP_TOKEN"
```

**Response** (200)

```json
{
  "slug": "example",
  "archivedAt": "example",
  "name": "example",
  "description": "example",
  "cadence": "WEEKLY",
  "dayOfWeek": 0,
  "timeLabel": "example",
  "scheduleLabel": "example",
  "nextWeekLabel": "example",
  "nextWeekStart": "example",
  "ownerName": "example",
  "attendeeCount": 0,
  "space": {
    "name": "example",
    "slug": "example"
  },
  "queuedCount": 0,
  "laterCount": 0,
  "canManage": false,
  "anchorDate": "example",
  "attendees": [],
  "onDeck": [],
  "recentlyClosed": [],
  "later": []
}
```

### Queue a topic for a meeting

`POST /api/apps/{slug}/meeting`

Put a decision or an inform on a meeting's agenda, or take it off. Editor-gated. Optional by design — a decision made without a room is still a decision.

**CLI**

```bash
drop topics set-meeting ops-inform-infra --meeting ops-core
```

**MCP**

```json
{
  "tool": "drop_topic_set_meeting",
  "arguments": {
    "slug": "ops-inform-infra",
    "meeting": "ops-core"
  }
}
```

**HTTP**

```bash
curl -X POST 'https://drop.himarley.ai/api/apps/ops-inform-infra/meeting' \
  -H "Authorization: Bearer $DROP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"meeting":"ops-core"}'
```

**Response** (200)

```json
{
  "slug": "example",
  "meeting": "example"
}
```

### Create a meeting

`POST /api/meetings`

Define a recurring meeting. People-admin gated, because a meeting is org structure rather than personal content. Cadence is WEEKLY or BIWEEKLY plus a day; bi-weekly needs an `anchorDate` to establish which fortnight is the on week, and without one it falls back to weekly rather than guessing.

**CLI**

```bash
drop meetings create --name "Ops Core" --slug ops-core --cadence BIWEEKLY --day-of-week 2 --time-label "Tue 3:00 PM ET" --anchor-date 2026-08-31
```

**MCP**

```json
{
  "tool": "drop_meeting_create",
  "arguments": {
    "name": "Ops Core",
    "slug": "ops-core",
    "cadence": "BIWEEKLY",
    "dayOfWeek": 2,
    "timeLabel": "Tue 3:00 PM ET",
    "anchorDate": "2026-08-31"
  }
}
```

**HTTP**

```bash
curl -X POST 'https://drop.himarley.ai/api/meetings' \
  -H "Authorization: Bearer $DROP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Ops Core","slug":"ops-core","cadence":"BIWEEKLY","dayOfWeek":2,"timeLabel":"Tue 3:00 PM ET","anchorDate":"2026-08-31"}'
```

**Response** (201)

```json
{
  "slug": "example",
  "archivedAt": "example",
  "name": "example",
  "description": "example",
  "cadence": "WEEKLY",
  "dayOfWeek": 0,
  "timeLabel": "example",
  "scheduleLabel": "example",
  "nextWeekLabel": "example",
  "nextWeekStart": "example",
  "ownerName": "example",
  "attendeeCount": 0,
  "space": {
    "name": "example",
    "slug": "example"
  },
  "queuedCount": 0,
  "laterCount": 0
}
```

### Update a meeting

`PATCH /api/meetings/{slug}`

Change a meeting's name, schedule, owner or Space link. Owner or people admin. Every field is optional; omitted fields are left alone, and passing null clears the ones that allow it.

**CLI**

```bash
drop meetings edit ops-core --day-of-week 3 --time-label "Wed 3:00 PM ET"
```

**MCP**

```json
{
  "tool": "drop_meeting_update",
  "arguments": {
    "slug": "ops-core",
    "dayOfWeek": 3,
    "timeLabel": "Wed 3:00 PM ET"
  }
}
```

**HTTP**

```bash
curl -X PATCH 'https://drop.himarley.ai/api/meetings/ops-core' \
  -H "Authorization: Bearer $DROP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"dayOfWeek":3,"timeLabel":"Wed 3:00 PM ET"}'
```

**Response** (200)

```json
{
  "slug": "example",
  "archivedAt": "example",
  "name": "example",
  "description": "example",
  "cadence": "WEEKLY",
  "dayOfWeek": 0,
  "timeLabel": "example",
  "scheduleLabel": "example",
  "nextWeekLabel": "example",
  "nextWeekStart": "example",
  "ownerName": "example",
  "attendeeCount": 0,
  "space": {
    "name": "example",
    "slug": "example"
  },
  "queuedCount": 0,
  "laterCount": 0
}
```

### Archive a meeting

`DELETE /api/meetings/{slug}`

Retire a meeting that has stopped sitting. Owner or people admin. Archiving rather than deleting on purpose: `App.meetingId` is SetNull, so a real delete would silently empty every agenda the meeting ever had. Topics keep their link and simply stop being listed.

**CLI**

```bash
drop meetings archive ops-core
```

**MCP**

```json
{
  "tool": "drop_meeting_archive",
  "arguments": {
    "slug": "ops-core"
  }
}
```

**HTTP**

```bash
curl -X DELETE 'https://drop.himarley.ai/api/meetings/ops-core' \
  -H "Authorization: Bearer $DROP_TOKEN"
```

**Response** (200)

```json
{
  "slug": "example",
  "archived": false,
  "queuedTopics": 0
}
```

### Restore an archived meeting

`POST /api/meetings/{slug}/restore`

Bring an archived meeting back. Owner or people admin. Its topics reappear on the agenda exactly as they were, since the links were never broken.

**CLI**

```bash
drop meetings restore ops-core
```

**MCP**

```json
{
  "tool": "drop_meeting_restore",
  "arguments": {
    "slug": "ops-core"
  }
}
```

**HTTP**

```bash
curl -X POST 'https://drop.himarley.ai/api/meetings/ops-core/restore' \
  -H "Authorization: Bearer $DROP_TOKEN"
```

**Response** (200)

```json
{
  "slug": "example",
  "archivedAt": "example",
  "name": "example",
  "description": "example",
  "cadence": "WEEKLY",
  "dayOfWeek": 0,
  "timeLabel": "example",
  "scheduleLabel": "example",
  "nextWeekLabel": "example",
  "nextWeekStart": "example",
  "ownerName": "example",
  "attendeeCount": 0,
  "space": {
    "name": "example",
    "slug": "example"
  },
  "queuedCount": 0,
  "laterCount": 0
}
```

### List members

`GET /api/meetings/{slug}/attendees`

The meeting's members, owners first. Same shape as a Space's members: everyone who belongs, each with a role.

**CLI**

```bash
drop meetings members list ops-core
```

**MCP**

```json
{
  "tool": "drop_meeting_list_members",
  "arguments": {
    "slug": "ops-core"
  }
}
```

**HTTP**

```bash
curl -X GET 'https://drop.himarley.ai/api/meetings/ops-core/attendees' \
  -H "Authorization: Bearer $DROP_TOKEN"
```

**Response** (200)

```json
{
  "slug": "example",
  "attendees": []
}
```

### Add members

`POST /api/meetings/{slug}/attendees`

Add people to the meeting, individually or by group. They join as PARTICIPANT; use set-role to make someone an owner. Owner or people admin. Groups expand server-side at the moment of adding and are not tracked afterwards. Idempotent — re-adding someone is a no-op, so pasting a full list is safe.

**CLI**

```bash
drop meetings members add ops-core --emails neil.murphy@himarley.com --groups 
```

**MCP**

```json
{
  "tool": "drop_meeting_add_members",
  "arguments": {
    "slug": "ops-core",
    "emails": [
      "neil.murphy@himarley.com"
    ],
    "groups": []
  }
}
```

**HTTP**

```bash
curl -X POST 'https://drop.himarley.ai/api/meetings/ops-core/attendees' \
  -H "Authorization: Bearer $DROP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"emails":["neil.murphy@himarley.com"],"groups":[]}'
```

**Response** (200)

```json
{
  "slug": "example",
  "attendees": []
}
```

### Remove a member

`DELETE /api/meetings/{slug}/attendees/{email}`

Take someone off the meeting. Owner or people admin. Idempotent — removing someone who is not a member is a no-op. Refuses to remove the last OWNER, which would leave a meeting nobody can edit.

**CLI**

```bash
drop meetings members remove ops-core neil.murphy@himarley.com
```

**MCP**

```json
{
  "tool": "drop_meeting_remove_member",
  "arguments": {
    "slug": "ops-core",
    "email": "neil.murphy@himarley.com"
  }
}
```

**HTTP**

```bash
curl -X DELETE 'https://drop.himarley.ai/api/meetings/ops-core/attendees/neil.murphy@himarley.com' \
  -H "Authorization: Bearer $DROP_TOKEN"
```

**Response** (200)

```json
{
  "slug": "example",
  "attendees": []
}
```

### Change a member's role

`PATCH /api/meetings/{slug}/attendees/{email}`

Promote a member to OWNER or return them to PARTICIPANT. Owner or people admin. Refuses to demote the last owner — a meeting with no owner has nobody who can appoint one.

**CLI**

```bash
drop meetings members set-role ops-core aurea.nunes@himarley.com --role OWNER
```

**MCP**

```json
{
  "tool": "drop_meeting_set_member_role",
  "arguments": {
    "slug": "ops-core",
    "email": "aurea.nunes@himarley.com",
    "role": "OWNER"
  }
}
```

**HTTP**

```bash
curl -X PATCH 'https://drop.himarley.ai/api/meetings/ops-core/attendees/aurea.nunes@himarley.com' \
  -H "Authorization: Bearer $DROP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"role":"OWNER"}'
```

**Response** (200)

```json
{
  "slug": "example",
  "attendees": []
}
```
