Turn meeting transcripts into a temporal context graph for coding agents.
Project description
Meeting → Context Graph
Turn meeting transcripts into a temporal context graph that a coding agent
reads to write and update code. Each meeting updates the same graph.json, and
git history records how decisions evolved.
Meetily (capture + transcribe, free) ─► context_graph CLI ─► graph.json (git) ─► coding agent
Why a graph, not just notes
Every node has a status (active / superseded / deprecated) and a
supersedes list. When a later meeting reverses a decision, the old node is
marked superseded and a new active node links to it via a SUPERSEDES edge.
So the graph always shows current truth and what changed.
Setup
pip install meetmind # core CLI
pip install "meetmind[all]" # + Slack bot, graph images, doc/PDF ingest, embeddings
export GROQ_API_KEY=... # free key from console.groq.com (PowerShell: $env:GROQ_API_KEY="...")
A shared Groq key ships as a fallback, so
meetmindworks out of the box for light use. Set your ownGROQ_API_KEYto avoid the shared rate limit.
Usage
# --- recommended: pull straight from Meetily's local DB (recording -> transcript) ---
meetmind meetily-list # see recent Meetily meetings
meetmind ingest --meetily # ingest the LATEST Meetily meeting
meetmind ingest --meetily-id <id> # ingest a specific Meetily meeting
# --- batch: catch up on many meetings at once (oldest first, one commit each) ---
meetmind ingest --new # every Meetily meeting not yet in the graph
meetmind ingest --since 2026-07-01 # meetings created on/after a date
meetmind ingest --since 2026-07-01 --new # both filters combined
meetmind ingest --all # every Meetily meeting
# --- other input sources ---
meetmind ingest transcripts/m1.txt --meeting-id 2026-07-12-kickoff
meetmind ingest --paste "we'll use REST and Postgres" --meeting-id m1
meetmind ingest --audio meeting.mp3 --meeting-id m1 # Groq Whisper fallback
meetmind ingest ... --dry-run # preview changes, no write/commit
meetmind show # print current active nodes
meetmind delta # git diff of last meeting's changes
# render the graph from the terminal (no Slack needed)
meetmind viz --out graph.png # PNG
meetmind viz --format mermaid --out g.mmd # Mermaid text
meetmind viz --format dot --active-only # DOT, hide superseded
# check graph integrity (dangling edges, supersedes cycles, duplicate concepts)
meetmind validate
# export the ACTIVE-only spec for the coding agent (grouped by feature)
meetmind export --format md --out spec.md
meetmind export --format json --out spec.json
# scope to a separate project graph -> context-graphs/<name>.json
meetmind ingest samples/m1-kickoff.txt --meeting-id m1 --project payments
meetmind export --project payments
# multi-project meeting: split ONE transcript across per-project graphs automatically
meetmind ingest big-meeting.txt --meeting-id m1 --route
Multi-project meetings (routing)
When one meeting discusses several projects, --route makes the extractor label
each node with a project and fans the nodes out into separate
context-graphs/<project>.json files — each with its own temporal history,
supersession, and export spec. Known projects are discovered from the existing
graph files, so labels stay consistent meeting to meeting; a genuinely new project
name auto-creates its graph. Cross-cutting items go to general.
Cross-project dependencies are preserved: an edge between nodes in different
projects (e.g. Billing DEPENDS_ON an Auth decision) is stored in the source
project's graph as a namespaced reference auth:decision-api-graphql, surfaced in
that project's export spec (so the coding agent sees the dependency) and exempt
from validation's dangling-edge check.
In the Slack bot, set CG_ROUTE_PROJECTS=1 and the bot routes each uploaded
meeting by content, replying with a per-project breakdown + one graph image per
project touched (instead of assuming the channel = the project).
Entity resolution (how meetings merge without duplicating)
When a later meeting revises a decision, the pipeline decides NEW vs DUPLICATE vs CHANGE (supersede) using, in order:
- Explicit supersession — the extractor is shown the current active nodes and
emits
supersedes: [id]when a statement replaces one. Most reliable. - Embedding similarity (optional) — if
sentence-transformersis installed (orGEMINI_API_KEYis set) nodes are matched semantically, soreq-user-loginandreq-authentication-flowcan still merge.pip install sentence-transformersto enable; without it the system falls back to string/concept matching (no error). - String/concept matching — id-prefix + token overlap. Always available.
Use export to hand the coding agent a clean current-state spec (no history), and
validate in CI to catch a corrupt graph before an agent acts on it.
Meetily integration (recording → transcript)
Meetily records system+mic audio locally and transcribes it for free — no meeting bot needed. It stores everything in a SQLite database, which this CLI reads read-only:
| OS | Database path |
|---|---|
| Windows | %APPDATA%\com.meetily.ai\meeting_minutes.sqlite |
| macOS | ~/Library/Application Support/com.meetily.ai/meeting_minutes.sqlite |
| Linux | ~/.local/share/com.meetily.ai/meeting_minutes.sqlite |
The path is auto-detected; override with --meetily-db PATH if needed. With
--meetily the meeting-id is auto-derived from the meeting's date + title (e.g.
2026-07-12-design-review), so you don't pass --meeting-id. Speaker source is
labeled You: (mic) / Others: (system audio).
Meetings need not be live. A previously-recorded call works two ways:
(1) import the recording into Meetily (its audio-import feature transcribes it into
the same DB, then --meetily picks it up), or (2) point the CLI straight at the
file with --audio old-meeting.mp3 (Groq Whisper transcribes it, no Meetily needed).
Other inputs: pasted minutes (--paste), a plain transcript file, or the built-in
Groq Whisper fallback for a raw audio file (--audio).
Slack bot (audio in → graph image out)
Let anyone on the team drop a meeting recording into a channel and get the context graph back as a rendered image — no CLI needed.
User uploads meeting.wav ─► bot transcribes (Groq) ─► ingest ─► posts changelog
└─► uploads graph PNG
Mentions: @bot graph (post the image), @bot show (list active nodes),
@bot delta (git diff since last meeting).
Run it (Socket Mode — no public URL needed)
pip install "meetmind[bot]" # includes slack-bolt, requests
export SLACK_BOT_TOKEN=xoxb-... # bot token
export SLACK_APP_TOKEN=xapp-... # app-level token, scope connections:write
export GROQ_API_KEY=...
export CG_GRAPH_PATH=graph.json # optional
meetmind-bot
Slack app setup: enable Socket Mode; subscribe to events message.channels
and app_mention; bot scopes app_mentions:read, channels:history,
files:read, files:write, chat:write (add groups:history for private
channels). Invite the bot to the channel.
Graph rendering
The image is rendered by context_graph/viz.py:
- Graphviz (preferred, fully offline) — install the system binary
(
choco install graphvizon Windows,apt install graphviz,brew install graphviz); thegraphvizpip package wraps it. - mermaid.ink (automatic fallback if
dotisn't found) — renders via a free web service. ⚠️ This sends the graph to an external host; install Graphviz to keep confidential meetings local.
Encoding: node color = status (green active / grey superseded / amber open
question), shape = type (Decision ◆, Requirement ▢, Constraint ⬡, …), and
SUPERSEDES edges are red dashed. Check viz.available_renderer() to see which
backend is active.
Contract for the coding agent
Read graph.json and treat it as follows:
- Current requirements = every node with
"status": "active". Obey these. - Ignore nodes with
"status": "superseded"or"deprecated"as current truth — but use them to know what to remove or replace. OpenQuestionnodes are NOT decided — do not assume an answer; flag them.- What changed since last meeting =
git diff HEAD~1 HEAD -- graph.json(ormeetmind delta). A node flipping tosupersededplus a newactivenode linked by aSUPERSEDESedge = "replace the old implementation with the new one." - Edges tell you structure:
IMPLEMENTS,DEPENDS_ON,BLOCKS,SUPERSEDES,DECIDED_IN,RELATES_TO.
Node shape
{
"id": "decision-api-style",
"type": "Decision",
"title": "API uses GraphQL",
"content": "Switch the public API from REST to GraphQL.",
"status": "active",
"source_meeting": "2026-07-19-review",
"created_at": "2026-07-19T10:00:00+00:00",
"supersedes": ["decision-api-rest"],
"confidence": 0.9,
"owner": "Priya"
}
Scope (v1)
Included: transcript/paste/audio input, Groq extraction, temporal merge with supersession, JSON graph + git history, CLI.
Deferred: MCP server, Neo4j/Graphiti engine, meeting bot, embedding-based dedup, GUI. See the plan file for rationale.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file meetmind-0.1.1.tar.gz.
File metadata
- Download URL: meetmind-0.1.1.tar.gz
- Upload date:
- Size: 49.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ce23307a0c89fda0eb139462df992a1f2aa984b473eca305f872d1ec2485e472
|
|
| MD5 |
427225eef357d28a1ca81c9613e7b1e9
|
|
| BLAKE2b-256 |
271670d079d3b94a46e0cea43824a1b10cfb8ce6ac2708b905525d2cf71d3adf
|
File details
Details for the file meetmind-0.1.1-py3-none-any.whl.
File metadata
- Download URL: meetmind-0.1.1-py3-none-any.whl
- Upload date:
- Size: 47.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
93ff18714cf64131ec98a15a2aa9f2388f9e6337bc39d1f8260a46af1ebcc6ab
|
|
| MD5 |
862c93f21032189fadc87115ea9bf6a9
|
|
| BLAKE2b-256 |
c1b0856c88565991bdb11109b94d6759ea25f36d40a76aa320468000f9794d66
|