Meetings app
The Meetings app transcribes a live meeting and fans each line out to a small
crew of background agents. A file-backed agent (widget_type markdown or
html) owns exactly ONE output file and rewrites it in full after every batch.
An agent whose widget_type is chat has no output file — its output IS its
chat replies, it gets no OUTPUT_FILE line, and none of the file rules below
apply to it.
Only a markdown agent's output is user-editable in the app (the editable
minutes), so a markdown agent re-reads its output file before every rewrite —
the user may have edited it since the last write. An html output is not
user-editable.
Only one meeting may be active at a time; starting a second answers 409. The
server enforces the lifecycle transition table, not just the UI: active and
paused may only reach ended through reviewing (the action-item review
gate), ended may be reopened to active, and a same-status POST is an
idempotent no-op.
A live translation panel translates each transcript line as it lands, using one
tool-less kirocrew-lite call per line in an ephemeral session — deliberately
NOT the agent batch path, because latency is the point. It is sequential per
meeting and drops the oldest pending line when it falls behind, so gaps in
translations.json are expected, not a bug.
Where the data lives
All paths are under ~/.kiro/crew/apps/meetings/data/:
| Path | What it is |
|---|---|
config.json |
app config: the agent roster, the task/calendar provider ids, presets |
dictionary.toml |
speech-to-text correction terms ([[term]] blocks) |
calendar-cache.json |
the last calendar sync's events |
task-ledger.json |
tasks filed through the local task provider |
meetings/<id>/session.json |
one meeting's metadata (title, status, attendees, attachments, outputs map) |
meetings/<id>/tasks.json |
that meeting's extracted action items |
meetings/<id>/<agent-id>.md |
a markdown agent's output (e.g. note-taker.md) |
meetings/<id>/<agent-id>.html |
an HTML agent's output (e.g. sketch-artist.html) |
meetings/<id>/transcript.jsonl |
the raw transcript, one finalized speech segment per line — read this instead of asking the user to re-summarize |
meetings/<id>/translations.json |
per-line translations for the live translation panel |
<id> is the meeting id with : replaced by _. Only [A-Za-z0-9._-] is
legal in it — the backend rejects anything else, so do not construct a path from
a raw calendar UID.
Lifecycle
idle— the meeting folder exists, nothing is running.active— transcription is flowing; agents receive batched lines every ~30s.paused— transcription stopped, the session and its queues are intact.reviewing— the meeting is over and the user is triaging extracted tasks.ended— finished; outputs are final.
The agents
| Agent | Writes | Notes |
|---|---|---|
meetings-note-taker |
note-taker.md |
structured notes: topics, decisions, action items, open questions |
meetings-sketch-artist |
sketch-artist.html |
one self-contained HTML/Mermaid diagram, revised in place |
meetings-task-extractor |
tasks.json |
always runs; the app's core output |
A file-backed agent's first message carries an OUTPUT_FILE: line. Write to that
exact path, character for character, and rewrite the FULL file after every batch —
never accumulate content in memory, because a context limit would lose it. A
chat agent gets no such line and writes no file.
Lines prefixed [chat] are typed by the user, not transcribed: treat them as
corrections or added context and act on them immediately.
Providers
Two things are pluggable, and which implementation is active comes from
config.json:
task_provider— where a reviewed action item is filed. The shipped provider islocal, which appends totask-ledger.json.calendar.provider— where upcoming meetings come from.none(default, meetings are created by hand) orics, which reads the iCalendar document atcalendar.source(a local.icsfile path, or a publishedhttps://URL).
To sync the calendar, call POST /api/apps/meetings/calendar/sync — do not try
to fetch or parse the calendar yourself. With a provider configured the app also
syncs on its own every calendar.poll_interval_secs (default 300) and creates
the meeting directory for an event calendar.precreate_lead_minutes (default 15)
before it starts, so an imminent meeting usually already exists as idle;
calendar.auto_sync: false turns the background poll off, and a lead of 0
keeps the sync but stops pre-creation.
Speech-to-text
Transcription uses KiroCrew's own streaming endpoint (/api/ws/stt), driven from
the browser. Cloud transcription is optional
(pip install 'boto3>=1.34,<2' 'amazon-transcribe>=0.6,<1'); when it is not
installed the app says so and the user can still type into the broadcast bar to
feed the agents.
Correcting recurring mistranscriptions
When the user complains that a project noun keeps coming through wrong, add a dictionary term rather than correcting it in the notes:
POST /api/apps/meetings/dictionary
{"correct": "DynamoDB", "aliases": ["dynamo db", "dynamo d.b."]}
Matching is case-insensitive with word boundaries and the longest alias wins, so every later meeting gets it right at the point of transcription.