Turn your Krisp call recordings into a linked, navigable knowledge base — not a pile of summaries and a chat bot.
The pipeline is three trip2g fleet role-notes wired by change-webhooks. Drop a raw transcript into the vault and the knowledge base builds itself, in the same vault it lives in: a call note per recording, a growing glossary of people/tools/projects/terms, daily notes with action checkboxes, and append-only topic logs. Every claim quotes the exact transcript lines behind it.
A fully synthetic sample vault lives in example/vault/ — inputs and
the notes the cascade produced from them.
| Note | Folder | What it holds |
|---|---|---|
| transcript | transcripts/ |
the raw, verbatim transcript — the auditable source |
| call | calls/ |
inferred title, summary card, link to the transcript, and per topic a one-line takeaway above the verbatim quote below, cited by timerange |
| concept | concepts/ |
one note per person/org/project/tool/term, with aliases and mentions that quote the exact lines where it came up; grows across calls |
| daily | daily/ |
action checkboxes on top, dated log below, no summary; a "tomorrow" task lands on the next day |
| topic log | log/ |
recurring subjects, append-only, each mention under a ### [[YYYY-MM-DD]] heading |
Two navigation axes: by topic (concept graph + wikilinks) and by time (daily notes + the calls magazine). Time is authoritative: it is decoded from the call id (a UUIDv7 with a millisecond timestamp), never from the local clock.
Three role-notes in roles/; the fleet turns each into a webhook:
Krisp API ──(cron)── roles/ingest.md code via codellm, no LLM — verbatim transcripts
│ writes transcripts/**
▼ change-webhook
roles/segment.md LLM — topic boundaries, inferred title, quoted evidence
│ writes calls/**
▼ change-webhook
roles/extract.md LLM — concepts, daily notes, topic logs
writes concepts/** daily/** log/**
Ingest is the only source-specific stage. Everything after is source-agnostic: swap
Krisp for books, YouTube, or support threads by replacing roles/ingest.md alone.
Because the raw transcript is preserved verbatim, you can re-run the LLM stages any
time the prompt or model improves — no re-fetch.
- trip2g — provides both tools used here:
- memcli (
cli/memcli) — boots a local trip2g instance + two-way sync for a vault folder - fleet (
cmd/fleet) — the agent host that runs the role-notes
- memcli (
- A Krisp session token,
KRISP_TOKEN(only for ingesting your own calls) - An OpenRouter API key,
OPENROUTER_API_KEY(https://openrouter.ai/keys), or any OpenAI-compatible endpoint
Neither memcli nor fleet is published standalone yet — build them from the trip2g repo:
git clone https://github.com/trip2g/trip2g
cd trip2g
go build -o ~/bin/fleet ./cmd/fleet # the agent host (single static binary)
cd cli/memcli && npm install && npm run build # memcli -> dist/memcli.jsGet KRISP_TOKEN from your browser: open app.krisp.ai, DevTools → Network → any
api.krisp.ai request → copy the Authorization: Bearer <token> value.
Serve the committed synthetic example as a browsable site:
git clone https://github.com/trip2g/krisp_knowledge
cd krisp_knowledge
node /path/to/trip2g/cli/memcli/dist/memcli.js up --folder example/vaultOpen the printed URL: the calls magazine on the front page, /daily, /concepts,
/log. (Note URLs turn dashes into underscores: calls/2024-03-12-018e321a.md is
served at /calls/2024_03_12_018e321a.)
fleet --once runs a single role-note offline against a local folder — same engine as
the daemon, no trip2g connection. This is how you test the cascade (and how the
committed example/vault output was produced):
export OPENROUTER_API_KEY=sk-or-...
cd example/vault # or your own vault
# step 1: transcript -> call note (topic boundaries + inferred title)
fleet --once ../../roles/segment.md --vault . \
--target transcripts/2024-03-12-018e321a.md \
--llm-base-url https://openrouter.ai/api/v1 --llm-api-key $OPENROUTER_API_KEY
# step 2: call note -> concepts, daily note, topic logs
fleet --once ../../roles/extract.md --vault . \
--target calls/2024-03-12-018e321a.md \
--llm-base-url https://openrouter.ai/api/v1 --llm-api-key $OPENROUTER_API_KEYEach run prints a JSON result (status, tokens_used, the notes written) and writes
the notes into the folder. Cost is a few cents per call on openai/gpt-5.4-mini (the
default in the roles; override with the model: frontmatter field).
--once covers the LLM roles. The ingest role is a code body run by codellm on the
fleet daemon (below); for local testing, drop transcript files into transcripts/
yourself — any note with Name | MM:SS lines and a created_at in the frontmatter
works.
To have the cascade run by itself on every new transcript:
- Serve your vault:
memcli up --folder <your-vault>(two-way sync: notes the fleet writes appear back in your folder). - Copy
roles/into the vault — the fleet discovers role-notes underroles/. - Run two fleets and one codellm. A fleet serves exactly one LLM endpoint, and
code no longer runs inside the fleet process:
ingest.mdis executed by codellm, a service that speaks the OpenAI API and runs the fenced block instead of predicting text. Each role picks its fleet byfleet_id, so the two never collide. Seedocs/dev/fleet_run.mdfor the rest of the flags.
codellm holds the Krisp credentials and decides what a block may see:
CODELLM_ADDR=127.0.0.1:8082 \
CODELLM_ALLOWED_PROGRAMS=python \
CODELLM_SANDBOX_NETWORK=true \
CODELLM_API_KEY=$(openssl rand -hex 32) \
CODELLM_TRIP2G_URL=http://localhost:20181 \
CODELLM_EXPOSE_ENV=KRISP_TOKEN,KRISP_BASE_URL \
KRISP_TOKEN=... KRISP_BASE_URL=https://api.krisp.ai \
codellmThe LLM fleet, for segment.md and extract.md (fleet_id: krisp-llm):
fleet \
--fleet-id krisp-llm \
--trip2g-url http://localhost:20181 \
--callback-url http://127.0.0.1:9090 \
--listen :9090 \
--trip2g-admin-personal-token \
<OWNER_PERSONAL_TOKEN_VALUE from the vault's .trip2g-memory/env> \
--fleet-secret $(openssl rand -hex 32) \
--llm-base-url https://openrouter.ai/api/v1 \
--llm-api-key $OPENROUTER_API_KEYThe code fleet, for ingest.md (fleet_id: krisp-code) — same shape, pointed at
codellm instead of a model provider, and holding no Krisp secret of its own:
fleet \
--fleet-id krisp-code \
--trip2g-url http://localhost:20181 \
--callback-url http://127.0.0.1:9091 \
--listen :9091 \
--trip2g-admin-personal-token \
<OWNER_PERSONAL_TOKEN_VALUE from the vault's .trip2g-memory/env> \
--fleet-secret $(openssl rand -hex 32) \
--llm-base-url http://127.0.0.1:8082/v1 \
--llm-api-key $CODELLM_API_KEYThe cron ingest role pulls new Krisp calls every 15 minutes; each written transcript wakes segmentation; each call note wakes extraction.
A role without a fleet_id belongs to no fleet and is skipped with a warning — that is
deliberate, so two fleets can never both claim the same role.
memcli up generates OWNER_PERSONAL_TOKEN_VALUE into the vault's state dir and the
instance seeds it as an admin personal token at boot — that one value is the fleet's
whole access to the hub, and revoking the row in the admin UI cuts the fleet off
without stopping the instance. Both halves are recent: the instance must be new enough
to seed the token, and memcli new enough to generate it.
Caveat: trip2g's webhook SSRF guard blocks deliveries to loopback/private
addresses unless the server runs with DEV=true. The stock memcli container does not
set it, so an all-on-localhost live cascade currently needs a dev-mode trip2g (e.g.
the trip2g repo's docker-compose.test.yml stack, where this exact wiring is
exercised end-to-end in e2e/krisp-ingest.spec.js). fleet --once has no such
constraint — it needs no server at all.
vault-templates/ holds the magazine index pages (index.md,
daily/index.md, concepts/index.md, log/index.md) and _header.md/_footer.md.
Copy them into a fresh vault once and it renders as a browsable site.
Every claim cites its source, and the citation is the source: notes quote the verbatim
transcript lines behind each statement, with a timerange link. The LLM's summary is
the value-add; the quote underneath is the proof. Since the emit step is an LLM, a
quote can still occasionally be mislabeled — call notes carry needs_review: true so
a human confirms inferred titles and spot-checks quotes.
roles/ingest.md Krisp API -> transcripts/** (code via codellm, cron, no LLM)
roles/segment.md transcripts/** -> calls/** (LLM, change-webhook)
roles/extract.md calls/** -> concepts, daily, log (LLM, change-webhook)
vault-templates/ magazine index pages, _header/_footer
example/vault/ synthetic transcripts + the notes the cascade produced
.env.example the two keys you need
Nothing private is committed: your .env, vaults, and caches are gitignored. Only the
synthetic example/ ships in the repo.