Skip to main content
Glama
aminehamlouchi

InterLogue

InterLogue

Brief it the way an editor briefs a reporter. It interviews the subject and returns a published piece with every quote cited to a timestamp in the transcript.

InterLogue is an MCP server. Inside a host such as Claude, the host writes the piece and InterLogue is the fact-checker: nothing is stored as a piece until every quoted span resolves, verbatim, to a subject turn at the cited timestamp. A product with no host model calls write_piece instead and the server writes the piece, then puts it through the same check. The spine is:

brief -> approve_contact -> interview (place_call + fetch_transcript, or run_interview) -> draft_piece -> [the host writes] -> check_citations
                                                                                          or -> write_piece (the server writes, same check)

The output leads with the story. Pull quotes come second, each with its timestamp. The per-question answers come third, as a secondary view. Every piece ends with a line that says whether a recorded call stands behind it.

The one-sentence brief

The brief tool needs three things: the person's name, their phone number, and one sentence in the user's words about who they are and what the piece is about.

Interview Marisol Teague, +1-502-555-0142, founder of Ridgeline Provisions, about switching her order entry to Tallyhook, for Tallyhook's marketing team.

Role, company, client, product, topic, angle and genre are inferred from the sentence or defaulted, and the result names every choice. Four genres share the same seven story beats: a subject at another company than the client gets the customer case study plan; a subject whose company is the client gets the founder story plan; a sentence that says podcast or episode gets the podcast segment plan (a hook question first, a closing question that invites a story); one that says testimonial gets the testimonial plan (five beats, ending on a recommendation). An explicit genre field overrides all of that, and question_templates lists what each genre asks. A phone number, email address or street address inside the sentence is stripped before anything is inferred, so it never becomes the angle.

Related MCP server: Mission

The three rules

  1. Output leads with the story. A bulleted question-and-answer summary is meeting minutes, not a piece. The checker fails a piece that is not prose first.

  2. No cold outreach. A human approves the specific person and number before any dial. The agent states it is an AI and asks permission to record at the top of the call. A subject who declines to be recorded stops the interview: nothing is stored.

  3. No agenda steering. The user sets an angle, which shapes which questions are asked and what is emphasized. It never shapes what the subject is portrayed as having said. Every claim and quote links to a timestamp in the transcript.

The tools as a host sees them

Tool

Inputs

What it does

brief

subject_name, subject_phone, about; optional genre, subject_role, subject_company, client_company, client_product, topic, angle, content_needed

Stores the brief and builds the question plan from the sentence, in one of four genres, and says how the genre was chosen. Nobody is contacted.

approve_contact

brief_id, approved_by, statement; optional subject_name, phone, consent_basis, confirm

Over stdio: records that a named human approved contacting this brief's subject at this brief's number. Over HTTP: records nothing and returns a one-time approval link for a person to click; only the click counts. A name or number that differs from the brief refuses. See "What the approval record is" below.

run_interview

brief_id; fixture or turns

Text-only interview from the fictional fixture or from turns supplied inline. Refuses without an approval on file and refuses a transcript whose subject declined to be recorded.

place_call

brief_id; optional confirm_dial (ignored)

Phone path, step 1. Refused by the dial gate without the approval record. Places one outbound call through the ElevenLabs agent over Twilio. Present only when the ElevenLabs variables are set.

fetch_transcript

brief_id; optional wait_secs

Phone path, step 2. Waits for the call to end, fetches and normalizes the transcript with real timestamps, runs the consent check, stores it append-only. A refusal to be recorded stores nothing and marks the call consent_failed. Answers at once for a call the post-call webhook already stored. Present only with the ElevenLabs variables.

draft_piece

brief_id

Returns the reporter's packet: brief, question plan, writing contract, ranked verbatim quote candidates with timestamps, and the full transcript, with contact details masked.

check_citations

brief_id + markdown, or piece_id

The fact-checker and, with write_piece, the only path by which a piece is stored. Validates section order, every quoted span and its (MM:SS), numbers outside quotes, quotes in the dek or byline, repeated frames. On a pass it appends the per-question view, masks contact details, and stores the piece. With piece_id it re-checks a stored piece.

write_piece

brief_id; optional writer (model or deterministic)

The server writes the piece from the stored transcript, with the configured Claude model when ANTHROPIC_API_KEY is set (model from INTERLOGUE_WRITER_MODEL, default claude-sonnet-5) or the deterministic reporter otherwise, submits it to the same check as check_citations, retries once with the failing spans fed back, and stores only a clean pass.

generate_piece

brief_id

The deterministic fallback writer for the no-host run. Registered only when INTERLOGUE_ALLOW_FALLBACK=1.

status

brief_id

Where a brief sits in the spine and what to call next. Names a withdrawn brief as withdrawn. With a transcript on file it also names the planned beats the call never reached and the questions to send the subject by email.

withdraw_subject

brief_id, or subject_name + phone; confirm, confirm_token, optional requested_by

Replaces every record of a subject with tombstones at their request, after a preview. Returns the external references the operator must delete by hand.

ledger

optional brief_id

Cost and duration per brief and in total from the call records (credits and USD as ElevenLabs reported them), pieces per brief, a per-ten-minutes figure, and what one stored interview costs against the two hours of a marketer's time it replaces (dollars with INTERLOGUE_MARKETER_HOURLY_USD). Metadata only: no transcript is opened, no name or number printed.

quote_check

brief_id, optional piece_id; to relay an answer: subject_response, disputed_quotes, note, relayed_by

The subject sees exactly the words a stored piece attributes to them, each with its timestamp, and confirms or disputes them before anything is published. Hosted: a signed one-time page, delivered through the operator's channel when one is configured. Stdio: the message to send, and the answer relayed by a person. Recorded per piece, shown by status, withdrawn with the subject's other records.

derive_assets

brief_id, optional piece_id

A LinkedIn post, a short post under 280 characters and an email teaser from a stored piece, built only from the piece's own sentences and pull quotes, every quote re-verified against the transcript and kept with its timestamp. Nothing stored.

discover_contacts

query

Stub: "not in this build". Automated contact discovery is not part of InterLogue.

question_templates

optional genre

The four genres and the questions each asks, with placeholders.

download_recording

transcript_id

Stub: "not in this build". The timestamped transcript is the record.

Every tool returns readable text: a heading line, the facts, then a Next: line naming the tool to call next. A refusal sets isError. Phone numbers are never echoed beyond their last four digits.

A judge can try it two ways

Requires Node 20 or newer. No env file, no API keys.

Path 1: one command, no Claude needed (the fallback writer)

git clone https://github.com/aminehamlouchi/interlogue.git interlogue && cd interlogue && npm install && npm run spine

npm run spine builds the server, starts it over stdio, and drives the tools in order with the fictional fixture using the deterministic reporter as the writer. It prints the generated piece and the citation check, and exits non-zero if any quote fails to resolve. It also proves the gate: it calls run_interview before approve_contact and confirms the refusal.

npm test

Runs the test suite: the dial gate, the append-only store and its tombstones, consent detection and the consent gate, the redaction of contact details, the fallback writer, the host-piece checker with tamper tests, withdrawal, the server-side writer behind the citation gate (with a fake writer and a canned piece carrying a quote the subject never said), the hosted entry (bearer token, session isolation, health check, the approval link, the post-call webhook with signed and tampered payloads, tenants), the four genres, the ledger, and the partner sidecar. Nothing in the suite reads a real transcript unless INTERLOGUE_REAL_DATA_DIR names a directory that holds one, nothing in the suite can reach the phone path, and no test calls a model: the Anthropic writer runs against a fake client.

Path 3: the hosted flow, one command, no keys

npm run demo:hosted

Starts the hosted entry in-process on a loopback port with a token and an approval secret minted for the run, then drives it the way a partner's product would, with the sidecar example over plain JSON-RPC: brief, an approval link issued and nothing recorded, the gate refusing before the click, the link opened and the button pressed (by the script here; by the person the operator sent it to in a deployment), the fixture interview, write_piece with the deterministic reporter, the subject's quote_check (the one-time page opened and "These are my words" pressed by the script; by the subject in a deployment), derive_assets with the LinkedIn post printed, status and ledger. It prints the piece and exits non-zero if any step refuses. No call is placed, no model is called, no key is used. This is the flow to show a partner first.

Path 2: inside Claude, where Claude writes the piece

Claude Desktop: after npm install && npm run build in the cloned folder, quit Claude Desktop fully (it rewrites its config from memory while running) and run:

npm run register-desktop

It backs up the config, adds or refreshes only the interlogue entry (with the env-file flag when .env exists), and leaves every other entry alone. Or add the entry by hand:

{
  "mcpServers": {
    "interlogue": {
      "command": "node",
      "args": ["/absolute/path/to/interlogue/dist/src/index.js"]
    }
  }
}

Claude Code: the repo ships a .mcp.json, so opening the folder registers the interlogue server after npm run build.

Paste the one-sentence brief above into Claude and add: "I approve contacting her at that number. Use the founder-case-study fixture instead of calling, then write the piece and show it to me." Claude calls brief, approve_contact, run_interview, draft_piece, writes the piece, and check_citations stores it or returns every failing span with the closest transcript turn.

From a shell, without a host:

npm run tool -- brief '{"subject_name":"Marisol Teague","subject_phone":"+1-502-555-0142","about":"founder of Ridgeline Provisions, about switching her order entry to Tallyhook, for Tallyhook'"'"'s marketing team"}'
npm run tool -- approve_contact '{"brief_id":"<brief_id>","approved_by":"Your Name","statement":"I approve contacting this person at this number."}'
npm run tool -- run_interview '{"brief_id":"<brief_id>","fixture":"founder-case-study"}'
npm run tool -- draft_piece '{"brief_id":"<brief_id>"}'
npm run tool -- check_citations '{"brief_id":"<brief_id>"}' --markdown-file my-piece.md

The writing contract

draft_piece hands the writer a contract and check_citations enforces the parts it can enforce mechanically:

  • Order: H1 headline, story as prose, then ## Pull quotes. The per-question view is appended by the checker from the transcript.

  • Every quoted span is verbatim from a subject turn and is followed by its (MM:SS). A span without a timestamp, or a timestamp without a span, fails. One ellipsis is allowed inside a single turn, in order, with fragments of at least three words.

  • No quotes in the dek or the byline: they would sit above the fold with no timestamp.

  • Connective prose may frame and sequence but may not assert a fact about the subject outside a cited quote. A number outside a quote fails.

  • The angle chooses emphasis, never words. More than one sentence starting with "Asked", or "said:" more than once, fails.

  • Three to seven pull quotes. Plain, reported voice.

  • A thin interview must say so in the headline; draft_piece grades the interview and the packet says when that clause applies.

Hosted deploy on your own keys

src/remote.ts serves the same tools over the MCP Streamable HTTP transport, for a partner who wants to run InterLogue on their own infrastructure with their own ElevenLabs account.

  • Endpoint: POST, GET and DELETE on /mcp. Every request must carry Authorization: Bearer <INTERLOGUE_TOKEN>. A missing or wrong token, or a server with no token set, is refused with 401 before the request body is read.

  • /healthz answers GET without a token with liveness only: { ok, version, token_configured, sessions }. With a tenant's bearer token it adds that tenant's own tools, phone_tools, webhook_configured and approval_links. No subject data, no list of tenants.

  • /approve/<token>: the approval page. Over HTTP approve_contact records nothing and returns this link for a person to open; the page shows the subject's name, the masked number, the client and the approver with one button, "I approve this call". The click records the approval and the dial gate accepts only such a record. The token is an HMAC keyed with INTERLOGUE_APPROVAL_SECRET (never the bearer token, so a caller holding the token cannot mint a link; without the secret no link is issued); the URL carries only ids, an expiry and a nonce, nothing about the person; it expires after 24 hours (INTERLOGUE_APPROVAL_TTL_SECS, capped at a week), works once, is replaced by a newer link for the same brief, and a tampered, stale or superseded link records nothing. The signature is checked before anything is read from disk. INTERLOGUE_PUBLIC_URL sets the host in the link. With INTERLOGUE_APPROVAL_DELIVERY_URL set, the link is posted there (signed with INTERLOGUE_APPROVAL_DELIVERY_SECRET, last four digits of the number only) instead of being returned to the caller, which then learns only that it was sent: the operator's own channel is what hands the link to a person, and the calling program never holds it.

  • /webhooks/elevenlabs: the ElevenLabs post-call webhook, verified with ELEVENLABS_WEBHOOK_SECRET against the raw body (ElevenLabs-Signature: t=<seconds>,v0=<HMAC-SHA256 over "<timestamp>.<body>">, 30 minute tolerance). A verified transcript is stored through the same path as fetch_transcript, consent check included; polling stays as the fallback.

  • Several operators on one server: INTERLOGUE_TOKENS="id:token,id2:token2" with per-tenant INTERLOGUE_<ID>_* variables for the data root, the public URL, the ElevenLabs keys and webhook secret, the Anthropic key and writer model, the approval secret and the link lifetime. Each tenant's sessions, data and keys are its own; data roots must be distinct and must not nest, or the server refuses to start; the webhook is /webhooks/elevenlabs/<id>. INTEGRATION.md lists the variables.

  • The server-side writer: with ANTHROPIC_API_KEY set, write_piece writes with Claude (INTERLOGUE_WRITER_MODEL, default claude-sonnet-5); without it, with the deterministic reporter. Either way the piece goes through check_citations's check and is stored only on a clean pass.

  • One data directory per MCP session under INTERLOGUE_DATA_ROOT (default data/sessions). Two clients of the same deployment never see each other's briefs. A session's directory stays on disk when the session ends, so withdrawal can still find it.

  • The phone tools (place_call, fetch_transcript) are registered only when ELEVENLABS_API_KEY, ELEVENLABS_AGENT_ID and ELEVENLABS_PHONE_NUMBER_ID are all set. Without them the deployment is text-only and cannot dial.

  • PORT defaults to 3000. INTERLOGUE_ALLOW_FALLBACK=1 adds the deterministic writer.

Run it locally:

npm run build && INTERLOGUE_TOKEN=$(openssl rand -hex 24) npm run start:remote

Docker (Node 20, npm ci, npm run build, runs as a non-root user, copies no .env):

docker build -t interlogue . && docker run -p 3000:3000 -e INTERLOGUE_TOKEN=<secret> -v interlogue-data:/data interlogue

render.yaml is a Render blueprint for the same image. Every secret in it is declared unset (sync: false) and is entered in the Render dashboard; autoDeploy is off. Nothing in the repo deploys anything. The Dockerfile was written and read, not built, during the run that added it; the first build is on whoever deploys it.

A client connects with the SDK's StreamableHTTPClientTransport and a requestInit.headers.authorization of Bearer <token>, or with plain JSON-RPC over HTTP as examples/sidecar/sidecar.ts does. INTEGRATION.md has the request and response shapes, the approval and webhook flows, and the tenant variables; OPERATIONS.md has what to set, what to watch, how to rotate a secret and how to handle a withdrawal.

Withdrawal

The consent script promises a subject can ask afterwards to have their interview thrown out. withdraw_subject honours that:

  1. Called with a brief_id, or with a subject_name and phone that match exactly one approval record (two matches refuse as ambiguous, none refuse), it previews what would be removed and returns a confirm_token. Nothing is removed.

  2. Called again with confirm: true and that token, it replaces the brief, the approval, the call record, the transcript and every piece with a tombstone that holds only the id, the time and the reason "withdrawn". A tombstone is never overwritten by a later save, and every loader treats it as withdrawn: the dial gate refuses, status reports it, draft_piece has nothing to draft from.

  3. Two audit lines go to data/audit/withdrawals.jsonl, the first before any record is touched. They carry ids and external references only: no name, number or text.

  4. The result names what the operator must delete by hand: the ElevenLabs conversation id (audio and their transcript copy) and the Twilio call SID (the call log). The tool never calls either service.

Withdrawal is the one sanctioned exception to the append-only transcript rule, and it removes rather than edits.

Redaction of contact details

The stored transcript is verbatim. Everything derived from it for display is masked: a phone number becomes [phone number removed], an email address [email removed], a street address [address removed]. That covers the reporter's packet (quote candidates and the full transcript), the per-question view of a piece, the story and pull quotes of a stored piece, the citation report, the opening lines fetch_transcript shows, and the hints in a failing check. The matchers are written for speech: "five oh two, five five five, oh one four two" and "marisol at ridgeline dot com" count; year ranges, money and business figures do not.

The citation check runs against the verbatim turn first. A quote that wholly contains a contact detail resolves and is stored masked. A quote that cuts through one fails. A quote copied from the masked packet, mask token included, resolves against the masked rendering of the turn. After a clean check the piece is masked and a leak check confirms no cited contact detail survives; if one did, the check is marked failed and nothing is stored.

Where data lives

Everything at runtime goes under data/, which is gitignored, so subject names and numbers never enter git. The hosted entry uses one such tree per session under INTERLOGUE_DATA_ROOT; the stdio server uses INTERLOGUE_DATA_DIR or data/.

data/briefs/<brief_id>.json          name, phone, role, company, client, topic, angle, question plan
data/approvals/<brief_id>.json       who approved, when, their statement verbatim; earlier approvals under "replaced"
data/transcripts/<brief_id>.json     append-only; turns with time_in_call_secs and MM:SS; consent evidence
data/pieces/<brief_id>_pc_<id>.json  story, pull quotes, per-question view, citation check, markdown (contact details masked)
data/calls/<brief_id>.json           conversation id, call SID, timing, cost, last four digits only
data/audit/withdrawals.jsonl         withdrawal events: ids and external references only

A withdrawn record is { "id", "withdrawn_at", "reason": "withdrawn" } at the same path. The fixture under fixtures/ is fictional and committed; every name, company and number in it is invented, and the 555-01XX range is reserved for fiction.

The quote check: the subject's word on their words

A piece attributes quotes to a person. quote_check shows that person those quotes, each with the minute in the call it was said, and records one answer per piece: confirmed, or disputed with the quote numbers and a note of up to 500 characters. Hosted, the page at /quotes/<token> is signed with the approval secret, verified before any disk is read, answers once, expires with the approval lifetime, and shows no phone number; with a delivery channel the link goes to the operator's endpoint as a quote_check payload and the calling program never holds it. Over stdio the tool returns the message to send and a person records the answer with relayed_by. A disputed piece blocks derive_assets; the fix is a new piece from the same transcript without the disputed quotes. The page and the message both tell the subject that the whole interview can be withdrawn on request, which is what withdraw_subject does. Nothing publishes on its own either way: the check is a record for the human review, not a gate the server enforces.

Security: what the approval record is and is not

The approval record is the only thing that unlocks a dial, so it is worth being exact about what it proves.

It is: a file under data/approvals/ that says a named person (approved_by) approved contacting this brief's subject at this brief's number, with the statement they made stored verbatim, and the time. place_call and run_interview both call the same assertDialApproved in src/gate/dialGate.ts, which requires that file to exist, not be a tombstone, and name the brief's exact subject and number. A name or number that differs from the brief is refused at approve_contact, so the record can only ever cover the person on the brief. Replacing an approval keeps the earlier ones inside the record.

It is not, over stdio: an identity check, a login, or proof that a human was in the loop. There is no user authentication. approved_by and statement are whatever the host passes, and the tool descriptions tell the host that a user request which names the person and asks to contact them already counts as the approval. In a Claude session the human is the one typing that request; in any other host the operator has to make sure that is still true.

Over HTTP the hosted entry supplies the human-only surface: approve_contact records nothing and returns a signed one-time link; a person opens it, sees the name, the masked number, the client and the approver, and clicks "I approve this call"; the record that click makes (approved_via: "click") is the only kind the dial gate accepts there. Be exact about what that proves: that whoever held the link pressed the button. The calling program receives the link from approve_contact in order to hand it to a person, so it could press the button itself; the server cannot tell a browser from a program. The link is signed with a secret the caller does not hold, so it cannot mint links, but it can use the one it was given. The human step is therefore the operator's delivery of the link to a person and nobody else. A deployment that sets INTERLOGUE_APPROVAL_DELIVERY_URL closes that gap: the server posts the link to the operator's own channel and the calling program never receives it, so the click can only come from someone that channel reached.

Other facts a partner should rely on, each verified by a test:

  • Credentials are read from process.env only, never from a file by this code, never printed, and the ElevenLabs base URL is fixed so no environment value can redirect a request carrying the key.

  • Nothing reaches placeOutboundCall except place_call, after the gate. The test suite deletes every ELEVENLABS_* variable before the tools load and fails on any network call.

  • Transcripts are append-only. A piece is regenerated from its transcript, never the other way round. Withdrawal replaces, it never edits.

  • A subject's explicit refusal to be recorded stores nothing. A missing AI disclosure or recording ask is stored with a notice; the disclosure and the ask themselves live in the ElevenLabs agent's configuration, outside this repository.

  • The elision rule allows one ellipsis inside a single turn with fragments in order; the checker cannot see what was dropped between them. A reviewer should read elided quotes against the transcript.

  • A transcript can come from the fixture or from turns the host supplies, and the check confirms quotes against whatever was stored. The footer of every piece names its source so a reader knows whether a recorded call stands behind it.

The phone path

The phone path places a real call through an ElevenLabs agent over the native Twilio integration. It is two tools, because a live call outlasts one MCP tool call:

  1. place_call with brief_id. Refused unless the dial gate finds the approval for the brief's exact name and number. It triggers the outbound call, passing six dynamic variables built from the brief (subject_name, subject_role, client_name, genre, angle, question_plan), records the conversation id under data/calls/, and returns.

  2. fetch_transcript with brief_id. Waits for the call to end, fetches the conversation, normalizes it to one timestamped turn per entry, runs the consent check on the real opening, and stores the transcript append-only. A refusal stores nothing. A voicemail greeting is NO ANSWER. Each call waits up to about three minutes and answers STILL IN PROGRESS if the interview is still running; a ten-minute interview needs about four calls. If a host cancels a wait early, the next call for that brief stays under that limit.

Credentials for a local stdio run go in app/.env and are loaded by Node's own flag:

ELEVENLABS_API_KEY=...
ELEVENLABS_AGENT_ID=...
ELEVENLABS_PHONE_NUMBER_ID=...
npm run start:phone

That runs node --env-file=.env dist/src/index.js. For Claude Desktop, use the same two arguments with absolute paths. The agent itself is configured in ElevenLabs: its first message must state that it is an AI and ask permission to record, its prompt reads the six dynamic variables, and the Twilio number is imported under Phone Numbers. Endpoints used: POST /v1/convai/twilio/outbound-call and GET /v1/convai/conversations/{id}, authenticated with the xi-api-key header.

Layout

src/index.ts                  MCP server entry, stdio
src/remote.ts                 the same tools over Streamable HTTP, bearer token, one data dir per session, tenants, approval page, webhook
src/hosted.ts                 hosted-mode context and the signed approval token
src/writer/                   the server-side writers: interface, deterministic reporter, Anthropic API writer
src/phone/ingest.ts           one path from a finished conversation to a stored transcript (polling and webhook)
src/phone/webhook.ts          ElevenLabs post-call webhook signature and payload
examples/sidecar/sidecar.ts   a partner's sidecar over plain JSON-RPC, no SDK
src/tools/*.ts                one tool per file
src/gate/dialGate.ts          the only unlock for a dial
src/store/fileStore.ts        JSON persistence under data/, tombstones, audit lines
src/withdraw.ts               withdrawal: plan, preview token, execute
src/consent.ts                AI disclosure, recording ask, refusal and voicemail detection
src/generate/packet.ts        the reporter's packet for the host writer
src/generate/contract.ts      the writing contract
src/generate/markdownPiece.ts the host-piece checker and assembler
src/generate/citations.ts     the citation rule and re-check
src/generate/redact.ts        contact-detail matchers and masking
src/generate/maskPiece.ts     masking a checked piece, leak check
src/generate/reporter.ts      the deterministic fallback writer
src/questionBank.ts           question banks and angle weighting
src/phone/elevenlabs.ts       ElevenLabs REST client (outbound call, conversation fetch)
src/phone/normalize.ts        brief -> dynamic variables; conversation -> timestamped turns
fixtures/                     the fictional text-only fixture
scripts/run-spine.ts          end-to-end fallback runner over stdio
scripts/demo-hosted.ts        the hosted flow in one command over loopback HTTP, no keys
scripts/call-tool.ts          generic one-tool client over stdio
scripts/register-desktop.ts   writes the Claude Desktop config entry
test/                         node:test suite
Dockerfile, render.yaml       the hosted entry's image and blueprint
CHANGELOG.md, INTEGRATION.md  history, and the contract for another product
OPERATIONS.md, SECURITY.md    running the hosted entry; what is enforced and what is asked for

Available Tools

12 tools
approve_contactRecord human approval to contact the subjectA

A human records that InterLogue may contact exactly this person at exactly this number for this brief. This is the no-cold-outreach gate: run_interview refuses to proceed without a matching record. The name and number must match the brief. Re-approving with identical values returns the existing record; different values are refused. Next step: run_interview.

ParametersJSON Schema
NameRequiredDescriptionDefault
phoneYesThe subject's phone number, exactly as on the brief.
confirmYesA human must pass true. This records approval to contact exactly this person at exactly this number.
brief_idYesThe brief_id returned by the brief tool.
statementYesThe approver's own words, stored verbatim.
approved_byYesThe human approving this contact, by name.
subject_nameYesThe subject's full name, exactly as on the brief.
consent_basisYesHow the approver knows the subject consents to being interviewed and recorded, e.g. "agreed by email on Tuesday".

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully carries the burden and delivers: it discloses idempotency behavior (identical re-approval returns the existing record; different values are refused), a matching precondition (name and number must match the brief), and the downstream enforcement role. This is materially more than the schema conveys.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four tight sentences, front-loaded with the action and gate semantics, ending with the next step. No redundancy, though the caveat about identical vs. different values could be slightly compressed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-param mutation tool with no annotations and no output schema, the description covers action, precondition, idempotency, refusal behavior, and the follow-up tool. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every one of the 7 parameters is already documented in the schema. The description reinforces the matching requirement for name/number but adds no syntax or format detail beyond it, so the baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('A human records that InterLogue may contact exactly this person') and immediately frames it as the 'no-cold-outreach gate', which distinguishes it from siblings like discover_contacts or place_call. An agent can identify the tool without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states the dependency: 'run_interview refuses to proceed without a matching record' and closes with 'Next step: run_interview.' It gives both when-to-use (before interviewing) and the constraint that selects it (the gate).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

briefBrief the reporterA

Start here. Brief InterLogue the way an editor briefs a reporter: who the subject is, which client and product the case study is for, the topic, and the angle. The angle decides which questions get asked and what the piece emphasizes; it never changes what the subject is portrayed as having said. Saves the brief and returns a brief_id plus the question plan. Nobody is contacted at this step. Next step: approve_contact.

ParametersJSON Schema
NameRequiredDescriptionDefault
angleYesThe editor's angle, e.g. "a two-person team getting its Mondays back from manual order entry". Shapes which questions are asked and what is emphasized. Never shapes what the subject is portrayed as having said.
genreNoOnly customer_case_study exists in this build.customer_case_study
topicYesThe subject matter as a noun phrase, e.g. "order entry and fulfillment".
subject_nameYesFull name of the person to interview, e.g. the founder or customer.
subject_roleYesThe subject's role, e.g. "founder" or "head of operations".
subject_phoneYesThe subject's phone number. It is stored only in the brief and approval records and never echoed in full.
client_companyYesWho commissioned the piece (the marketing team's company).
client_productYesThe product the case study is about.
content_neededNoWhat the client needs back.
subject_companyYesThe subject's company.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden and does well: it discloses the side effect (saves the brief), the return shape (brief_id plus question plan), and the safety-relevant fact that no contact occurs. It omits auth/permission requirements and rate limits, so not a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with 'Start here.' Every sentence earns its place: input categories, the angle's semantic constraint, the save/return behavior, the no-contact guarantee, and the next step. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 10-parameter, no-output-schema, no-annotation tool, the description compensates well by describing the return value (brief_id, question plan) and the workflow position. It leaves the remaining lifecycle (what approve_contact then triggers) implicit, but that is the sibling's job.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description groups the inputs conceptually (subject, client, product, topic, angle) but adds little beyond what the schema already documents, including the angle semantics which the schema repeats verbatim.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (brief) and resource (InterLogue), enumerates the inputs it captures (subject, client, product, topic, angle), and marks itself as the entry point with 'Start here.' An agent can distinguish it from siblings like approve_contact or draft_piece without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly tells the agent when to use it ('Start here'), what does not happen ('Nobody is contacted at this step'), and routes to the next tool ('Next step: approve_contact'). This is when/when-not/alternatives in miniature.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_citationsFact-check a piece against its transcriptA

Validates that every quoted span resolves to a subject turn at the cited timestamp. With piece_id it re-checks a stored piece. With brief_id and markdown it checks a host-written piece: section order (story, then pull quotes), every quote verbatim and timestamped, no numbers outside quotes, no repeated frames. A clean pass persists the piece as a draft for human review and returns its piece_id. A fail returns every failing span with the closest matching turn so you can fix and resubmit; nothing is persisted on a fail.

ParametersJSON Schema
NameRequiredDescriptionDefault
brief_idNoWith markdown: the brief whose transcript the piece was written from.
markdownNoWith brief_id: the host-written piece. H1 headline, prose story, then '## Pull quotes' with one '> “quote” (MM:SS)' per line. The per-question view is appended for you.
piece_idNoRe-check a stored piece by id. Give either piece_id, or brief_id plus markdown.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: it discloses the validation rules (section order, verbatim timestamped quotes, no numbers outside quotes, no repeated frames), that a clean pass persists a draft for human review and returns a piece_id, and that a fail persists nothing and returns failing spans with the closest matching turn.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core validation statement, then the two modes, then the pass/fail outcomes. Every sentence conveys a distinct behavioral fact with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description must explain return behavior; it does so for both paths (piece_id on pass, failing spans plus nearest turn on fail). Nothing an agent needs to call or interpret this tool is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, and the parameter descriptions already explain the two invocation modes and the required markdown format. The description restates the piece_id vs. brief_id+markdown split without adding syntax or format detail beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: validates that quoted spans resolve to a subject turn at the cited timestamp. This is clearly distinct from sibling generators like draft_piece and generate_piece, and the title reinforces the fact-check framing.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly documents two invocation modes: 'With piece_id it re-checks a stored piece' and 'With brief_id and markdown it checks a host-written piece.' That gives clear context for selecting arguments, though it never names sibling alternatives or says when this check should be skipped.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

discover_contactsDiscover contacts (not in this build)A

Cut-list stub. Automated contact discovery is not implemented and will not find, suggest or look up anyone. Explains what to do instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYesIgnored. Kept so the tool has a stable shape.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations present, the description carries the full burden and does disclose the critical behavior: discovery is unimplemented and will return nothing useful. It is honest about the no-op nature, though it does not say what the call returns or whether the required query matters.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with 'Cut-list stub' so the agent grasps the situation immediately. No filler; every clause conveys necessary information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter stub with no output schema or annotations, the description supplies the one fact that matters: it will not work. The remaining gap is a concrete pointer to the alternative workflow, which would make it fully complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema itself states the query is 'Ignored. Kept so the tool has a stable shape.' The description adds nothing about the parameter beyond what the schema already documents, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states the tool's real purpose: it is a 'cut-list stub' that 'will not find, suggest or look up anyone.' This is a specific and honest statement of scope that distinguishes it from action-oriented siblings like place_call, approve_contact, and run_interview, though the verb+resource framing is inverted (it says what it does NOT do).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Explains what to do instead' implies the tool is used as a redirect mechanism, giving implied usage. However, no alternative tool or action is named, so the agent is left to infer the actual path forward on its own.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

download_recordingDownload recording (not in this build)A

Cut-list stub. No audio is fetched or stored by this build; the timestamped transcript is the record. Any transcript_id gets the same answer.

ParametersJSON Schema
NameRequiredDescriptionDefault
transcript_idYesIgnored. Kept so the tool has a stable shape.

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: it discloses that no audio is fetched or stored, that the timestamped transcript is the record, and that input is ignored. It does not discuss return format or edge cases, but the core stub behavior is transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the essential stub status. Every sentence adds useful information without waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a stub tool with no annotations and no output schema, the description is nearly sufficient: it explains the no-op behavior and that the transcript is the record. It could more explicitly describe the shape of the returned answer, but the agent has enough to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and already says transcript_id is ignored. The description adds that any transcript_id gets the same answer, which is marginally useful, but otherwise the schema does the heavy lifting. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states this is a cut-list stub, not a real download, and explains that no audio is fetched or stored. That distinguishes it from a functional download, though it does not explicitly contrast it with the sibling fetch_transcript tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no when-to-use guidance or alternatives. It only notes that any transcript_id returns the same answer, which is behavioral context rather than routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

draft_pieceGet the reporter's packet to write the pieceA

Returns everything needed to write the published piece from the transcript: the brief and angle, the question plan, a strict writing contract, ranked verbatim quote candidates each with its timestamp, and the full timestamped transcript. You (the host) write the story first, then pull quotes, in markdown, and submit it to check_citations. Every quoted span must be verbatim from a subject turn and followed by its (MM:SS). Nothing is published until the check passes.

ParametersJSON Schema
NameRequiredDescriptionDefault
brief_idYesThe brief_id whose transcript you are writing from. run_interview must have stored a transcript for it.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: it discloses the publication gate ('nothing is published until the check passes') and the hard constraint that every quoted span be verbatim from a subject turn and carry its (MM:SS). It stops short of stating access/permission requirements or whether the packet is cached/regenerated.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four sentences, front-loaded with what is returned, then the authoring rules. Dense but each sentence earns its place; the return-content list is long but necessary given there is no output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so describing the returned packet is essential, and the description does so thoroughly while also covering the citation format and the check_citations gate. An agent has everything needed to invoke it and act on the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and there is only one parameter, so the schema already defines brief_id's meaning and the precondition that run_interview stored a transcript. The description adds no further semantics about brief_id, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific retrieval action and enumerates the exact payload (brief/angle, question plan, writing contract, ranked verbatim quote candidates with timestamps, full timestamped transcript). It also implicitly distinguishes itself from siblings like generate_piece and fetch_transcript by clarifying that the host writes the story, not the tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a clear workflow: write the story first, then pull quotes in markdown, then submit to check_citations, with the rule that nothing is published until the check passes. It names a downstream sibling and its ordering but never states when NOT to use this tool (e.g., versus fetch_transcript) or any prerequisites beyond the transcript existing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fetch_transcriptFetch the call transcript (phone path, step 2 of 2)A

Step 2 of the phone path. Waits for the placed call to end (up to about three minutes per call), then fetches the transcript from ElevenLabs, normalizes it to timestamped turns, runs the consent check (AI disclosure, permission to record, the subject's yes), and stores it against the brief. If the call is still running it answers STILL IN PROGRESS: call it again, as many times as needed, until it answers TRANSCRIPT STORED. A ten-minute interview needs about four calls. Then: draft_piece.

ParametersJSON Schema
NameRequiredDescriptionDefault
brief_idYesThe brief whose call was placed with place_call.
wait_secsNoSeconds to wait for the call to end before answering "still in progress". Default 170. A ten-minute interview needs about four calls at the default. Leave it alone unless you know the host's timeout.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: it discloses the blocking wait (up to ~3 minutes per call), the retry/idempotency pattern, the mutation (transcript stored against the brief), and a consent-validation side effect (AI disclosure, permission to record, subject's yes). These are exactly the behaviors an agent needs to plan around, none of which appear in the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the step position and the core action, then the operational loop, then the handoff. Nearly every sentence earns its place, though the normalize/consent-check detail is slightly more than needed to select and invoke the tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description must explain return values, and it does: the two terminal answers (STILL IN PROGRESS vs TRANSCRIPT STORED) are named verbatim. Combined with the wait semantics and next-step routing, an agent has everything required to call it correctly and repeatedly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema itself richly documents brief_id and wait_secs, so the baseline is 3. The description adds real meaning on top: 'up to about three minutes per call' and 'a ten-minute interview needs about four calls' directly explain the wait_secs default of 170 and its retry economics, which is more than the schema's terse note provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (fetch transcript) plus the full pipeline: waits for the call to end, pulls from ElevenLabs, normalizes to timestamped turns, runs a consent check, stores against the brief. It also positions itself in the workflow ('step 2 of the phone path') and names the predecessor (place_call, via brief_id) and successor (draft_piece), so it is unmistakable against siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-call and when-to-call-again: if the answer is STILL IN PROGRESS, call it again as many times as needed until TRANSCRIPT STORED, with a concrete expectation ('a ten-minute interview needs about four calls'). It also hands off the next step ('Then: draft_piece'), so the agent knows both the loop condition and the exit path.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

generate_pieceFallback writer: generate the piece deterministicallyA

FALLBACK writer, used when no host is writing (for example npm run spine). Inside Claude, prefer draft_piece then check_citations, where the host writes the prose. This tool assembles the customer case study deterministically from the saved transcript: the story first, pull quotes second, per-question answers third. Every quote is a verbatim span of a subject turn and carries its transcript timestamp; the piece is saved only if the citation check passes. Regenerate any time; the transcript is never edited to fit a piece. Next step: check_citations.

ParametersJSON Schema
NameRequiredDescriptionDefault
brief_idYesThe brief_id whose transcript should be written up.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full load and delivers: deterministic assembly, verbatim quote spans with transcript timestamps, save-only-if-citation-check-passes, transcript never edited to fit a piece, and idempotent regeneration. These are exactly the behavioral traits an agent needs before invoking it.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the crucial routing word FALLBACK in caps, then layers usage, mechanics, and next step in four tight sentences. Slightly dense but every sentence carries distinct information; no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers purpose, routing, output ordering, citation gating, and follow-up tool despite having no annotations or output schema. An agent has everything needed to decide whether and how to call it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter (brief_id) and schema description coverage is 100%, so the schema already documents it. The description adds only the implication that the brief's transcript is what gets written up; it adds no syntax or selection nuance beyond the schema. Baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Explicitly names itself as the FALLBACK writer for deterministic assembly of the case study from the saved transcript, and states the output order (story, quotes, per-question answers). This makes it clearly distinguishable from the sibling draft_piece, which is the host-written path.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit when-to-use condition (only when no host is writing, e.g. `npm run spine`) and a when-not/preferred-alternative (inside Claude, use draft_piece then check_citations). It even names the next step, check_citations.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

place_callPlace the interview call (phone path, step 1 of 2)A

Places one real outbound call to the brief's subject through the ElevenLabs agent over Twilio. Refused unless a human approval for this exact person and number is on file. The agent opens by stating it is an AI and asking permission to record. Returns at once with the conversation id; call fetch_transcript to wait for the transcript. Requires ELEVENLABS_API_KEY, ELEVENLABS_AGENT_ID and ELEVENLABS_PHONE_NUMBER_ID in the server's environment.

ParametersJSON Schema
NameRequiredDescriptionDefault
brief_idYesThe brief to interview. approve_contact must have recorded approval for its exact name and number.
confirm_dialYesA human must pass true. This places a real phone call to the approved number.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and delivers: it is a real outbound call, it is refused without approval, the agent self-identifies as AI and seeks recording consent, it returns immediately rather than blocking, and it lists the required environment variables.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense but efficient: each sentence adds distinct information (purpose, gate, call semantics, return, env requirements) with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a side-effecting tool with no output schema and no annotations, the description covers safety gating, return value, follow-up tool, and runtime prerequisites — everything an agent needs before invoking it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so both parameters are already fully documented, including confirm_dial's const:true and the approval linkage on brief_id. The description adds no syntax or format detail beyond the schema, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('places one real outbound call to the brief's subject') plus the delivery mechanism (ElevenLabs over Twilio), and its 'step 1 of 2' framing lets an agent separate it from fetch_transcript and run_interview.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear precondition for use (human approval on file for the exact person and number) and routes the agent onward to fetch_transcript to await the result. It does not, however, contrast this phone path against any purely text path or explain when to prefer the alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

question_templatesQuestion templates by genre (not in this build)A

Cut-list stub. There is one genre, customer case study, and its questions come from the brief tool's angle-driven plan. Any genre passed here gets the same answer.

ParametersJSON Schema
NameRequiredDescriptionDefault
genreYesIgnored. Kept so the tool has a stable shape.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does reasonably well: it discloses that only one genre exists, that the genre argument is meaningless, and that output is identical for any input. It omits nothing critical for a no-op stub, though it doesn't say whether the call succeeds or errors.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the key fact ('Cut-list stub') so the agent learns the tool is non-functional immediately. No filler, though 'cut-list' is internal jargon that carries little meaning to an outside caller.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a stub with one ignored parameter, no output schema and no annotations, the description covers what an agent needs: it is a stub, input is irrelevant, and the real question source is brief. Return-value detail is unnecessary since output is constant.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the schema itself already states the 'genre' param is ignored and exists only for shape stability. The description's 'any genre passed here gets the same answer' reinforces that but adds no new semantic detail beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states plainly that this is a cut-list stub, identifies the single supported genre (customer case study), and says where the real questions come from (the brief tool). An agent knows this tool returns a fixed answer rather than genre-specific templates, though the name 'question_templates' implies a generality the description correctly denies.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It points at the 'brief tool's angle-driven plan' as the real source of questions, which nudges the agent toward brief, but it never explicitly says 'use brief instead of this tool.' Usage is implied rather than prescribed, and there is no statement of when this tool should ever be called (if at all).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_interviewRun the interview (text-only in this build)A

Runs the interview step of the spine on text: either a named fixture transcript or inline turns. Refuses unless a human approval for this brief's exact person and number is on file (the same gate a real dial would need). Checks that the agent disclosed it is an AI and asked permission to record at the top of the call, then saves the transcript. Transcripts are append-only. No phone call is placed in this build. Next step: generate_piece.

ParametersJSON Schema
NameRequiredDescriptionDefault
turnsNoInline interview turns in call order: { speaker: agent|subject, time_in_call_secs, text }. Give either fixture or turns, not both.
fixtureNoName of a fixture in the package's fixtures/ directory without the ".transcript.json" suffix, e.g. "founder-case-study". Give either fixture or turns, not both.
brief_idYesThe brief_id from the brief tool. Must have a matching approve_contact record.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: it discloses the approval gate and its refusal behavior, the AI-disclosure and recording-permission checks performed at the top of the call, that the transcript is saved, that transcripts are append-only, and that no phone call is placed. These are exactly the mutation/authorization semantics an agent needs before invoking.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, then the refusal gate, then side effects, then the next step. Every sentence adds a distinct fact; there is no filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no annotations and no output schema, the description covers preconditions, side effects, persistence semantics, and the follow-up tool. It stops short of describing what the call returns (e.g. confirmation shape or transcript handle), which is the only remaining gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the schema already documents fixture/turns mutual exclusivity and that brief_id must have a matching approve_contact record. The description restates the fixture-or-turns choice and the approval gate without adding new syntax or format detail, so baseline 3 is correct.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ("Runs the interview step of the spine on text") and immediately narrows the input modes to a named fixture transcript or inline turns. It also distinguishes itself from place_call by declaring "No phone call is placed in this build," so an agent can tell it apart from the dialing sibling without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a hard precondition (refuses unless a human approval for this brief's exact person and number is on file) and names the next step (generate_piece), which is strong routing guidance. It does not explicitly say when to prefer this over place_call or fetch_transcript, so it falls just short of full when/when-not/alternatives coverage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

statusWhere is this brief in the spine?A

Reports which of brief, human approval, transcript and generated pieces exist for a brief_id, and names the next tool to call. Spine: brief -> approve_contact -> run_interview -> generate_piece -> check_citations.

ParametersJSON Schema
NameRequiredDescriptionDefault
brief_idYesThe brief_id to report on.

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden, and it does imply a read-only inspection operation by saying it 'reports which ... exist'. However, it never explicitly states it is non-mutating, nor does it describe auth requirements, rate limits, or what the response payload looks like beyond 'names the next tool'.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, both earning their place: the first states the behavior, the second supplies the pipeline context that makes the artifact list interpretable. The core behavior is front-loaded with zero filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter read tool with no output schema and no annotations, the description supplies the key missing context: the pipeline spine and the promise that the next tool is named. That largely compensates for the absence of a return schema, though a hint about the shape of the status report itself is still absent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is a single parameter, brief_id, and schema description coverage is 100%, so the schema already documents it fully. The description adds no format, source, or constraint information beyond what the schema provides, which makes the baseline 3 appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: it reports which artifacts (brief, human approval, transcript, generated pieces) exist for a given brief_id. It also enumerates the pipeline spine, which implicitly positions it against the sibling workflow tools. It stops short of naming a specific sibling it is not, but the purpose is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The spine ordering ('brief -> approve_contact -> run_interview -> generate_piece -> check_citations') gives clear context for when an agent should consult this tool: to determine where in the pipeline a brief currently sits. It also states the tool names the next tool to call, which is actionable guidance. No explicit when-not or exclusion conditions are given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 12 tool updatesv0.1.0
    • First observedapprove_contact
    • First observedbrief
    • First observedcheck_citations
    • First observeddiscover_contacts
    • First observeddownload_recording
    • First observeddraft_piece
    • First observedfetch_transcript
    • First observedgenerate_piece
    • First observedplace_call
    • First observedquestion_templates
    • First observedrun_interview
    • First observedstatus

TDQS

A3.9/5.0

Scored across 12 tools

Disambiguation4/5

Tools mostly map to distinct steps in a linear interview spine, but there is a potential confusion between the simulated text path (run_interview) and the real phone path (place_call + fetch_transcript), and between the fallback writer (generate_piece) and the preferred writer flow (draft_piece + check_citations). Fortunately, the descriptions explicitly clarify these boundaries, which mitigates the overlap.

Naming Consistency4/5

The names are mostly snake_case verb_noun (e.g., approve_contact, run_interview, fetch_transcript, check_citations). A few names are nouns or noun phrases (brief, question_templates, status), which is a minor deviation but still readable and consistent with the domain.

Tool Count3/5

With 12 tools, the count is not unreasonable, but three stubs (question_templates, download_recording, discover_contacts) are explicitly cut-list placeholders that add no real functionality and dilute the set. The remaining tools feel appropriately scoped for the interview workflow.

Completeness4/5

The surface covers the full spine from brief to approval to interview to piece generation and citation checking, with status reporting. However, the stubs represent unimplemented features, and there is no tool to update or delete briefs or transcripts, though the workflow may not require them.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers