{}
StrictJSON
Productivity

Meeting Action Items

Every meeting ends the same way: a page of notes, a few decisions everyone remembers differently, and action items that quietly evaporate before the next call. This prompt turns a transcript or a set of meeting notes into a structured follow-up — a list of actions with an owner and a deadline, the decisions that were actually taken, and the date of the next meeting. The traps are all in the details: “someone should check with legal” has no owner, “next Friday” is not a date until it is converted to YYYY-MM-DD, and a decision buried halfway through a debate is easy to miss entirely. When no deadline was agreed, the field stays null instead of a made-up date, and when no next meeting was scheduled, it stays null too. The result drops straight into a task tracker, so nothing agreed in the room gets lost on the way out.

System Prompt

You are a precise meeting notes extractor. Read the provided meeting transcript or notes and return ONLY a valid JSON object matching the schema below. Do not add explanations, markdown, or extra fields. action_items is a list with one object per action agreed in the meeting, each with task, owner, and due_date; use an empty array when no action was agreed. task and owner are required non-empty strings: extract the best values stated in the meeting and never invent a person or a task that was not mentioned. due_date is the agreed deadline as a YYYY-MM-DD date, or null when no deadline was set — never use an empty string for a missing deadline. decisions is a list of the decisions taken, as short plain sentences; use an empty array when nothing was decided. next_meeting is the date of the next meeting as YYYY-MM-DD, or null when no next meeting was scheduled — never use an empty string. If the text is not a meeting transcript or notes, do not produce any output.

Raw JSON Schema

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "additionalProperties": false,
  "properties": {
    "action_items": {
      "items": {
        "additionalProperties": false,
        "properties": {
          "due_date": {
            "minLength": 1,
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "type": [
              "string",
              "null"
            ]
          },
          "owner": {
            "minLength": 1,
            "type": "string"
          },
          "task": {
            "minLength": 1,
            "type": "string"
          }
        },
        "required": [
          "task",
          "owner",
          "due_date"
        ],
        "type": "object"
      },
      "type": "array"
    },
    "decisions": {
      "items": {
        "minLength": 1,
        "type": "string"
      },
      "type": "array"
    },
    "next_meeting": {
      "minLength": 1,
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "type": [
        "string",
        "null"
      ]
    }
  },
  "required": [
    "action_items",
    "decisions",
    "next_meeting"
  ],
  "title": "MeetingActionItems",
  "type": "object"
}

Zod (TypeScript)

import { z } from "zod";

const ActionItemSchema = z
  .object({
    task: z.string().min(1),
    owner: z.string().min(1),
    due_date: z.string().min(1).regex(/^\d{4}-\d{2}-\d{2}$/).nullable(),
  })
  .strict();

export const MeetingActionItemsSchema = z
  .object({
    action_items: z.array(ActionItemSchema),
    decisions: z.array(z.string().min(1)),
    next_meeting: z.string().min(1).regex(/^\d{4}-\d{2}-\d{2}$/).nullable(),
  })
  .strict();

Pydantic v2 (Python)

from typing import Annotated

from pydantic import BaseModel, Field, field_validator


class ActionItem(BaseModel):
    task: str = Field(..., min_length=1)
    owner: str = Field(..., min_length=1)
    due_date: str | None = Field(
        ..., min_length=1, pattern=r"^\d{4}-\d{2}-\d{2}$"
    )

    @field_validator("task", "owner", "due_date", mode="before")
    @classmethod
    def _strip_strings(cls, v):
        if not isinstance(v, str):
            return v
        return v.strip()


class MeetingActionItems(BaseModel):
    action_items: list[ActionItem] = Field(...)
    decisions: list[Annotated[str, Field(min_length=1)]] = Field(...)
    next_meeting: str | None = Field(
        ..., min_length=1, pattern=r"^\d{4}-\d{2}-\d{2}$"
    )

    @field_validator("next_meeting", mode="before")
    @classmethod
    def _strip_next_meeting(cls, v):
        if not isinstance(v, str):
            return v
        return v.strip()

    @field_validator("decisions", mode="before")
    @classmethod
    def _strip_decisions(cls, v):
        if not isinstance(v, list):
            return v
        return [item.strip() if isinstance(item, str) else item for item in v]

Try it in the StrictJSON tool →