Run a full product-research pass on an idea — the recommended default for validating a new idea end to end. Returns a markdown report, FOLLOWED IN THE SAME TEXT by a machine-checked TRUST DIGEST — read the digest rather than trusting the prose. It states every claim's GROUNDED / SPECULATION / NO_RECEIPT state with its receipt id, the separate market/competitor spine, which personas are ⚠ QA-FLAGGED, and the anti-sycophancy readout. The digest also reports hypothesis robustness: when a verdict FLIPPED under rephrasing it names the downgraded verdict to act on. Each re-tested row quotes the hypothesis statement and any scope caveat. A scope caveat means persona support came from outside that persona's credibility domain: treat that support as directional, never grounded. A separate "Scope caveats on hypotheses not re-tested" block carries every such qualification on a single-shot verdict; those are not robustness results. When a section is missing the digest says so — absent is not clean. The digest also states the SOURCE TYPE on every receipt — `user_voice` (a real person's first-hand account), `report_evidence` (authoritative/third-person reporting), `marketing_seo` (vendor marketing or SEO content), or `unclassified`. Every "RRCP-" market/competitor receipt carries a `source type:` line; a "RCP-" persona receipt is a first-hand `user_voice` post unless its row says otherwise, and any that is not carries the same line marked ⚠. `marketing_seo` is shown for awareness but is EXCLUDED from grounding AND from automatic community synthesis — it is vendor marketing or SEO content, never cite it as user evidence. `unclassified` is EXCLUDED from both as well, and means the classification is genuinely unknown, NOT that the source was checked and found benign. Before the proof separator, the result may include carefully labelled MODEL-AUTHORED report framing: `personasSynthesis` plus only the actionable parts of `researchBrief` (target market, value proposition, assumptions, competitive landscape, and key risks). This framing is NOT evidence or findings. Structured `report_data` also carries typed `methodology` without duplicating its existing markdown section, and a safe `interviewHighlights[]` projection with only `personaName`, `personaRole`, `overallImpression`, and `quotesByHypothesis` — internal `researchTaskId` is excluded. The trust digest includes a compact, code-derived competitor source-quality aggregate and names only rows flagged with the exact `marketing_seo` mark; it does not repeat competitor positioning or notes below the proof separator. The full structured report_data (framing, methodology, safe interview highlights, hypotheses, competitors[], key findings) is mirrored to host-side `_meta.report_data` for programmatic use by your MCP client; everything YOU need to reason is already in the result text above it. Raw typed `report_data` states, source ids, and attestation markers are stored audit data, not citation eligibility. Only the machine-checked TRUST DIGEST's rendered state and receipt arrow authorize Cited: the digest must resolve a canonical, spine-owned pointer to a safe reachable HTTP(S) destination. Dangling, malformed, cross-persona, unsafe, credentialed, or incomplete pointers degrade without an arrow and MUST NOT be cited. report_data carries this same typed TRUST layer: (1) `claims[]` — each has a stored GROUNDED / SPECULATION / NO_RECEIPT state and may carry a `sourceId` of the form "RCP-p{i}-s{j}" into `personas[i].sources[j]`; use the digest, not this raw pointer, to decide whether the claim earned Cited. One discussion can carry several bounded excerpts. A claim addressing one shows a second id after "·" (form "rr1:<16 hex>"), and the receipt pool hangs that excerpt off the source row on its own "↳" line: read THAT line, not the row's first excerpt, as what the claim was checked against. These are excerpts from a discussion, never a speaker's exact words. A claim whose second id does not resolve under its own source loses the arrow entirely and MUST NOT be cited. NO_RECEIPT can mean a bad claim OR merely sparse evidence — cross-check `personas[].insufficientEvidence` / `sourcesFound` before discounting it. (2) `hypothesisResults[].robustness` — how many reworded re-asks a verdict survived (`survived`/`total`, e.g. 3/3); when `flipped` is true, trust `robustness.downgradedStatus` as the real verdict, NOT the top-level `status`. (3) `personas[]` — besides `sources[]` receipts, check `qaFlagged` (persona failed a quality check) before relying on its claims. Two DIFFERENT grounding models ride here: forum `sources[]` are receipt-eligible clickable posts, whereas `identityProvenance` (when present) is a PII-free aggregate calibration line ("calibrated against N real ICP profiles") — NEVER a receipt, so do not treat it as a source URL; `identityPriors` (seniority + career path) is typed enrichment, not a receipt either. (4) `sycophancySignals` — broken-persona flags (`lowDiscrimination`), disagreement splits, and explicit `totalRejections`. (5) `reportClaims[]` — the SEPARATE market/competitor spine (never crosses the persona one): each stored GROUNDED / SPECULATION / NO_RECEIPT, and may carry a `sourceId` of the form "RRCP-s{n}" into `reportEvidence[n]` (its own pool). On THIS spine a NO_RECEIPT claim has one of two provenance readings: only when its complete `attestation` marker ({sourceId, quote}) resolves in the digest to a safe receipt with an arrow is it "Cited" — Claude read a supporting page and an independent check vouched it supports the figure, though no exact quote could be pinned (stronger than recall, but NOT a verified receipt; its `attestation.sourceId` indexes `reportEvidence[n]` the same way, but a marker's presence NEVER implies grounding — key on the digest's rendered state and arrow, not raw state/sourceId); otherwise it is "unsourced": an evidence-shaped figure Claude wrote from its own training knowledge that could not be verified against a source — often directionally right (a recalled analyst estimate), but treat it as unconfirmed, NOT as a checked fact. Neither reading is ever counted as grounded. (6) The typed `openQuestions[]` field is mirrored for your MCP client at host-side `_meta.report_data.openQuestions`; because host `_meta` is not reliably model-visible, YOU should use the model-visible result text's `## Open Questions` section. Its strict `status` is `never_asked`, `nobody_answered`, or `voices_disagreed`. When the run wrote one, its own verdict rationale is rendered in the model-visible result text under "## Verdict rationale" — READ IT THERE. The typed field is mirrored for your MCP client at host-side `_meta.report_data.verdictSummary`, which is not reliably model-visible: 1-2 sentences the agent wrote at synthesis time saying WHY the overall verdict came out this way. It is RETRIEVED, not derived — never recompute or paraphrase it from the verdict counts or the confidence number. It is often ABSENT, which is normal and not an error: the run may predate the field, have written none, or have had it withdrawn because a robustness re-ask downgraded a verdict it argued for. When it is absent, say no rationale was recorded rather than inferring one. Typical wall time 15-25 minutes; progress is streamed via notifications/progress. This hero tool runs the whole curated pipeline in one call. PREFER it over hand-assembling a full validation from the granular primitives (create_persona + interview_persona + get_report) — those are for targeted, cheaper spot-checks, not a complete report; sequencing them yourself gives lower-quality coverage. See docs/recipes/ for the supported compositions (competitor spot-check, pivot viability, new-market persona validation). ALWAYS attach the run to a project so the report is visible in the Clien.ai web app: pass `project_name` to create a new project (derive a short 2-4 word name from the idea), or `project_id` to reuse an existing one — a run with neither is refused. First call opens a browser for one-time OAuth login; subsequent calls reuse the stored refresh token. IMPORTANT: if this call fails mid-flight with "MCP error -32000: Connection closed", do NOT call clien_research again — that spawns a new run and debits credits again for the same idea. Instead call `clien_research_status` with NO arguments — it finds your recent run(s) and lists them so you can pick the one you were researching. The dropped call's error text usually carries the job_id too, and you can pass it directly if you have it. (The id is also in the `[clien-mcp] research started job_id=…` stderr line and in host-side `_meta.job_id`, but both reach the operator's MCP client rather than you.)

Leave UNSET on the first attempt. Only set true to CONFIRM a run after a prior call returned a spend-guard prompt (the user has a daily spend limit and this run would cross it). This is a soft safety check, not a hard limit — setting true proceeds and debits credits normally. Do NOT set it pre-emptively; when the guard trips, relay the message to the user and only re-run with confirm_spend: true if they agree to proceed.

"deep" (default) runs a 15-25 minute full research pass. "quick" caps cost and runs a tighter pass.

The product idea, feature hypothesis, or research question to validate. Can be a one-liner or several paragraphs — more context yields a better report.

Clien.ai project UUID to attach this run to. Omit it to create a brand-new project instead — but then you MUST pass `project_name`. Reuse an existing project_id only for follow-up research the user explicitly asks to add to a prior run on the same idea.

Name for a new Clien.ai project to attach this run to. REQUIRED whenever `project_id` is not set — clien_research refuses a run that has neither, so the resulting report is always discoverable in the Clien.ai web UI. Derive a short (2-4 word) human-readable name from the idea — typically the product name. Guidance on when to create a new project vs. reuse an existing one: create a NEW project (supply a fresh `project_name`) for each distinct research idea or product concept; REUSE an existing `project_id` only when the user explicitly asks to add follow-up research to a prior run on the same idea. Ignored when `project_id` is also provided.

Leave UNSET on the first attempt. clien_research runs a soft task guard that refuses inputs which look off-script (e.g. an A/B copy/headline test rather than a product idea to validate). Only set true to OVERRIDE that refusal and run the full validation pipeline anyway — after relaying the guard's message to the user and confirming this really is a product idea they want validated. Do NOT set it pre-emptively.

Fetch the current state of an existing `clien_research` job. Use this to recover a run that disconnected with -32000 mid-flight (the job keeps running on the backend; this tool re-attaches a read view) and to poll for completion. If the job is complete, returns the full markdown report — followed in the same text by the same machine-checked TRUST DIGEST `clien_research` renders (claim states + receipt ids, QA-flagged personas, and the anti-sycophancy readout). One discussion can carry several bounded excerpts. A claim addressing one shows a second id after "·" (form "rr1:<16 hex>"), and the receipt pool hangs that excerpt off the source row on its own "↳" line: read THAT line, not the row's first excerpt, as what the claim was checked against. These are excerpts from a discussion, never a speaker's exact words. A claim whose second id does not resolve under its own source loses the arrow entirely and MUST NOT be cited. The digest also reports hypothesis robustness: when a verdict FLIPPED under rephrasing it names the downgraded verdict to act on. Each re-tested row quotes the hypothesis statement and any scope caveat. A scope caveat means persona support came from outside that persona's credibility domain: treat that support as directional, never grounded. A separate "Scope caveats on hypotheses not re-tested" block carries every such qualification on a single-shot verdict; those are not robustness results. The digest also states the SOURCE TYPE on every receipt — `user_voice` (a real person's first-hand account), `report_evidence` (authoritative/third-person reporting), `marketing_seo` (vendor marketing or SEO content), or `unclassified`. Every "RRCP-" market/competitor receipt carries a `source type:` line; a "RCP-" persona receipt is a first-hand `user_voice` post unless its row says otherwise, and any that is not carries the same line marked ⚠. `marketing_seo` is shown for awareness but is EXCLUDED from grounding AND from automatic community synthesis — it is vendor marketing or SEO content, never cite it as user evidence. `unclassified` is EXCLUDED from both as well, and means the classification is genuinely unknown, NOT that the source was checked and found benign. Before the proof separator, the result may include carefully labelled MODEL-AUTHORED report framing: `personasSynthesis` plus only the actionable parts of `researchBrief` (target market, value proposition, assumptions, competitive landscape, and key risks). This framing is NOT evidence or findings. Structured `report_data` also carries typed `methodology` without duplicating its existing markdown section, and a safe `interviewHighlights[]` projection with only `personaName`, `personaRole`, `overallImpression`, and `quotesByHypothesis` — internal `researchTaskId` is excluded. The trust digest includes a compact, code-derived competitor source-quality aggregate and names only rows flagged with the exact `marketing_seo` mark; it does not repeat competitor positioning or notes below the proof separator. The structured report_data behind that digest is mirrored to host-side `_meta`, the same shape `clien_research` would have returned, but it is the result text you read. A recovered run therefore loses none of the trust signal a completed run would have shown. The typed `openQuestions[]` field is mirrored for your MCP client at host-side `_meta.report_data.openQuestions`; because host `_meta` is not reliably model-visible, YOU should use the model-visible result text's `## Open Questions` section. Its strict `status` is `never_asked`, `nobody_answered`, or `voices_disagreed`. When the run wrote one, its own verdict rationale is rendered in the model-visible result text under "## Verdict rationale" — READ IT THERE. The typed field is mirrored for your MCP client at host-side `_meta.report_data.verdictSummary`, which is not reliably model-visible: 1-2 sentences the agent wrote at synthesis time saying WHY the overall verdict came out this way. It is RETRIEVED, not derived — never recompute or paraphrase it from the verdict counts or the confidence number. It is often ABSENT, which is normal and not an error: the run may predate the field, have written none, or have had it withdrawn because a robustness re-ask downgraded a verdict it argued for. When it is absent, say no rationale was recorded rather than inferring one. If the job is still running, returns a brief status summary. If the job failed or was cancelled, returns the failure reason. RECOVERY WITHOUT A JOB_ID: if the -32000 drop left you with no job_id, call this tool with NO arguments — it discovers your recent run(s). If exactly one is in flight it resumes it automatically; if several come back, it returns a list of runs each with a job_id and an idea snippet — re-call with the job_id whose idea matches the run you were executing (never guess, so run A never receives run B's report). Read-only: no credit cost, no side effects.

UUID of the research job to query. OPTIONAL — and omitting it is the FIRST thing to try: called with no `job_id`, this tool finds your recent run(s) and lists them with their ideas, so you can re-call with the one that matches what you were researching. Reach for that whenever you do not already have the id, because a completed `clien_research` call does not put it anywhere you can read. The places it IS readable: the error message text when a run drops mid-flight (e.g. "MCP error -32000"), and a `list_reports` entry for a run that already finished. It is also printed to the MCP server's stderr log as `[clien-mcp] research started job_id=<uuid>` and mirrored to host-side `_meta.job_id` — both reach the human operator and their MCP client, not you. Use this tool to RECOVER an in-flight job instead of calling `clien_research` again — calling research again would spawn a new run and debit another 50 credits for the same outcome.

Create a persona (a target user/customer profile) in a Clien.ai project from fields you already know. Prints the created persona and its `id` in the result text (the record is mirrored to host-side `_meta.persona`). Requires a `project_id` — call `list_projects` first to find one, or `create_project` to make one. Provide `name` and `role` at minimum; add `company`, `description` (background/goals/pain points), `company_size`, `industry`, and `location` when you have them. Set `ephemeral: true` for a scratch persona you do NOT want counted in the project's aggregate insights (e.g. a quick one-off). Compose with `interview_persona` to validate a NEW MARKET cheaply: create a persona representing that market, then interview it (see docs/recipes/new-market-persona-validation.md). For a FULL validation report on the new market rather than a targeted probe, prefer `clien_research`. This is a free, no-credit create for explicit fields you already know — if you want the AI to generate the background/company/industry from just a name + role, use `generate_persona` instead (that path debits 1 credit).

Optional company or organisation the persona works at.

DEPRECATED alias for `company_size` — pass `company_size` instead. Still accepted for backward compatibility. Passing both this and `company_size` with DIFFERENT values is rejected.

Optional company size (e.g. "11-50", "Enterprise").

Optional background/bio for the persona: goals, pain points, context — whatever helps an interview feel grounded. Stored as the persona's background.

Set true for a scratch/throwaway persona that should NOT count toward the project's aggregate insights (sets include_in_insights=false). Leave false (the default) for a real persona you want reflected in project-level analysis.

Optional industry (e.g. "Fintech", "Healthcare").

Optional location (e.g. "Berlin, Germany").

The persona's name (e.g. "Priya, the pragmatic PM"). Short and human-readable.

DEPRECATED alias for `project_id` — pass `project_id` instead. Still accepted for backward compatibility. Passing both this and `project_id` with DIFFERENT values is rejected.

REQUIRED — pass `project_id` (or its deprecated alias `projectId`); the call is rejected if neither is present. It is absent from this schema's `required` list only so an alias-only call stays valid. UUID of the project this persona belongs to. Get it from `list_projects`, or from `create_project`, which prints the new id in its result text. The persona is rejected with a 404 if you do not own the project.

The persona's job title or role (e.g. "Senior Product Manager"). Required.

Create a new Clien.ai project to group research runs, personas, and reports. Prints the created project and its `id` in the result text (the record is mirrored to host-side `_meta.project`); pass that id as `project_id` on subsequent `clien_research` calls. Prefer calling `list_projects` first to avoid duplicates. Note: `clien_research` can also auto-create a project via its `project_name` argument — use this tool when you want to create the project up front (e.g. with a description) or without starting a research run.

Optional longer description of what the project is about (max 1500 chars). Omit if the name is self-explanatory.

Human-readable name for the new project. Keep it short (2-4 words) — typically the product or idea name. Use `list_projects` first to avoid creating a duplicate of an existing project.

AI-enrich an EXISTING persona: fill in the thin scalar fields it is missing (background/description, company, industry, company size, location) using the model. Supply `persona_id`; by default the model fills only fields that are currently BLANK and leaves populated content unchanged, including a human edit made while the model is running. Passing `refresh` is a deliberate overwrite: the named fields are replaced with newly generated values (e.g. ["description", "industry"]). Add `additional_context` (a free-form brief) to steer the enrichment toward the product/market you are validating. Returns the UPDATED PROFILE as readable result text (so you can read the fields the model just AI-wrote) plus the list of AI-written field names; both are mirrored to host-side `_meta.persona` / `_meta.enriched`. This DEBITS 1 credit per enrichment (use `create_persona` to set fields explicitly for free, or `generate_persona` to AI-create a brand-new persona). If nothing is blank and you pass no `refresh`, it is a no-op and NOTHING is charged. On insufficient credits the tool returns a clear error with your balance and a top-up link. Server-confirmed no-value outcomes are refunded, but a timeout or ambiguous server response can hide a committed write or an unconfirmed refund: inspect the persona and call `get_credit_balance` before retrying, especially after `refresh`. Source (the creation channel) and insights inclusion remain unchanged. A successful non-noop AI write transitions `manual` authorship to `ai_enriched`; `unknown`, `ai_generated`, and `ai_enriched` authorship remain unchanged. This MCP tool stays available for every authorship state; the web profile rewrite has a separate eligibility rule.

DEPRECATED alias for `additional_context` — pass `additional_context` instead. Still accepted for backward compatibility. Passing both this and `additional_context` with DIFFERENT values is rejected.

Optional free-form brief to steer the enrichment — the product/market being validated, constraints, or anything that should shape the filled-in background and details.

DEPRECATED alias for `persona_id` — pass `persona_id` instead. Still accepted for backward compatibility. Passing both this and `persona_id` with DIFFERENT values is rejected.

REQUIRED — pass `persona_id` (or its deprecated alias `personaId`); the call is rejected if neither is present. It is absent from this schema's `required` list only so an alias-only call stays valid. UUID of the persona to enrich. Get it from a `list_personas` entry, or from `create_persona` / `generate_persona`, which print the new persona's id in their result text. Rejected with a 404 if you do not own it.

Optional list of already-populated fields to deliberately OVERWRITE and REGENERATE. By default enrich only fills fields that are currently blank and leaves existing content unchanged; pass e.g. ["description", "industry"] to replace those fields with newly generated values. These are persona ENTITY field names, not param names, so `companySize` keeps its camelCase spelling here. Valid values: description, company, industry, companySize, location.

description company industry companySize location

AI-generate a persona from a short brief and save it to a Clien.ai project. Supply at minimum `project_id`, `name`, and `role`; the model fills a believable background, company, industry, company size, and location, plus a decision endowment (what they use today, what they pay for it, switching cost, and who pays vs. who uses) and a credibility domain (what the persona is credible on, and not beyond) folded into the background so interviews reason from a real status quo. Add `company`, `industry`, or `company_size` to pin those yourself, and `additional_context` (a free-form brief) to steer the persona toward the product/market you are validating. Set `ephemeral: true` for a scratch persona excluded from the project's aggregate insights. Returns the GENERATED PROFILE as readable text — name, role, company, company size, industry, location, and the background paragraph the model wrote — so you can read what you just paid for without a follow-up `get_persona`. That result text is the copy you read; the record is mirrored to host-side `_meta.persona`. This DEBITS 1 credit per generated persona (the explicit, no-AI `create_persona` is free — use that when you already know the fields). On insufficient credits the tool returns a clear error with your balance and a top-up link, and nothing is charged. A failed generation is never charged, so a surfaced error is safe to retry.

Optional free-form brief to steer generation — goals, constraints, the product being validated, or anything that should shape the persona's background and pain points.

Optional company/organisation. When omitted the AI invents a realistic one from the role.

DEPRECATED alias for `company_size` — pass `company_size` instead. Still accepted for backward compatibility. Passing both this and `company_size` with DIFFERENT values is rejected.

Optional company size (e.g. "11-50"). When omitted the AI infers one.

Set true for a scratch/throwaway persona that should NOT count toward the project's aggregate insights (sets include_in_insights=false).

DEPRECATED alias for `ground_in_evidence` — pass `ground_in_evidence` instead. Still accepted for backward compatibility. Passing both this and `ground_in_evidence` with DIFFERENT values is rejected.

When true (the default), the persona is grounded in REAL user-voice evidence retrieved from community forums + Stack Exchange for this role/industry, and returned with its source receipts. Set false to skip retrieval for a faster, invented-from-brief persona. Either way this debits one generate_persona credit; grounding adds no extra credit cost.

Optional industry (e.g. "Fintech"). When omitted the AI infers one.

The persona's name (e.g. "Priya, the pragmatic PM"). Required.

DEPRECATED alias for `project_id` — pass `project_id` instead. Still accepted for backward compatibility. Passing both this and `project_id` with DIFFERENT values is rejected.

REQUIRED — pass `project_id` (or its deprecated alias `projectId`); the call is rejected if neither is present. It is absent from this schema's `required` list only so an alias-only call stays valid. UUID of the project this persona belongs to. Get it from `list_projects` (or `create_project`). Rejected with a 404 if you do not own the project.

The persona's job title or role (e.g. "Senior Product Manager"). Required.

Read the account's CURRENT CREDIT BALANCE and what every metered action costs — the affordability check to run BEFORE committing to paid work. Returns the ledger balance, the spendable balance, and a per-action price list with how many of each the account could afford right now, as readable text; the same record is returned as `structuredContent.credits` (mirrored in `_meta`). Takes no arguments — it reads the account you are authenticated as. CALL THIS BEFORE PLANNING MULTIPLE PAID ACTIONS (`clien_research`, `interview_persona`, `enrich_persona`, `generate_persona`, `scan_competitors`, `search_forums`). Without it the only way to learn the ceiling is to hit it — mid-plan, after some spend has already happened and the work is half-done. SPENDABLE IS THE NUMBER THAT GOVERNS, and it can be LOWER than the ledger balance: an anti-hoarding cap is applied when the balance is read. Budget with the spendable figure. ADVISORY, NEVER A RESERVATION: the number is a reading, not a hold. It can change between this call and any spend, and the server's atomic debit remains the only authority on whether an action happens. A tool that refuses for insufficient credits has not been overridden by this reading — never report an action as done because the balance said you could afford it. READ-ONLY AND CANNOT SPEND: no top-up, no plan change, no checkout, no debit — and no other MCP tool adds credits either. If the balance is short, tell the account owner; buying credits is something they do themselves in the Clien.ai web app. PRICES ARE READ LIVE from the server on every call. Use the figures returned rather than any price you remember — they change. A FAILED READ IS NOT A ZERO BALANCE: this tool raises an error rather than report a balance it could not read, so treat an error as "unknown", never as "out of credits". Read-only: no credit cost, no side effects.

Fetch a single interview by its `interview_id` (from a `list_interviews` entry or an interview's id printed by `interview_persona action:start`). Returns the full message transcript as readable text; the interview entity (status, personaId, messages, completedAt) is also returned as `structuredContent.interview` (mirrored in `_meta.interview`). Use it to re-read a completed interview without re-running it. This is the read-only twin of `interview_persona action:transcript`, reachable from just an id. Read-only: no credit cost, no side effects.

UUID of the interview to fetch. Get it from a `list_interviews` entry, or from the id `interview_persona` action=start prints in its result text. Rejected with a 404 if you do not own it. Returns the full message transcript.

Read a Clien.ai project's MARKET SNAPSHOT — the third cross-run research dossier, alongside `list_competitors` and `list_community_signals`. Returns market size, growth trend, key trends and positioning gaps as readable text, plus the id of the run that produced them and when it was last updated; the full record is also returned as `structuredContent.market` (mirrored in `_meta`). Requires a `project_id` — call `list_projects` to find one. ONE RUN, ONE SNAPSHOT: unlike the two collections, market is a SINGLETON — one row per project, replaced whole. Every field returned was written together by the single research run named in `sourceRunId`, never assembled from several runs, so a figure you quote can always be attributed to a specific run. Pass that id to `get_report` for the run behind the numbers. NO SNAPSHOT IS NOT AN EMPTY MARKET: a project can legitimately have none, because a completed run that did no web research writes nothing here. The tool says so explicitly and you must not convert it into a claim — "no market data on record" is the only statement it supports, never "the market is small", "unmeasured" or zero. A run that DID research the web and recorded nothing is reported as its own, differently-worded case. TRUST: the figures here carry NO trust state. A market figure's grounding lives in its source run's claim spine, not on the snapshot, so treat everything returned as recorded rather than verified — cite it only after reading the source run with `get_report`, whose market claims carry GROUNDED / SPECULATION / NO_RECEIPT states and their receipts. This is a free read of persisted state — it never researches anything. Read-only: no credit cost, no side effects.

UUID of the project whose market snapshot to read. Get it from `list_projects` (or `create_project`). Rejected with a 404 if you do not own the project. Returns the project's single stored market snapshot — market size, growth trend, key trends and positioning gaps — which is ONE COHERENT RUN'S OUTPUT: every field was written together by the research run named in the `sourceRunId` provenance field, never assembled from several runs. Pass that id to `get_report` to see the run behind the figures. A project can legitimately have NO snapshot; that is reported as "no run has produced market data", never as a zero or an empty market.

Fetch a single persona by its `persona_id` (from a `list_personas` entry, or the id printed by `create_persona` / `generate_persona`). Returns the FULL persona profile as readable text — name, role, company, company size, industry, location, the background/description paragraph, provenance (`source`), lock state, and `seniority` / `careerPath` when the persona has them — so you can read the persona you are about to interview or correct without any further call. The same record is also returned as `structuredContent.persona` (and mirrored in `_meta.persona`) for programmatic use. Use it to inspect a persona before correcting it with `update_persona` or interviewing it with `interview_persona`. TRUST: this is the persona ENTITY and none of it is evidence. `seniority` / `careerPath` are user-editable in the web app and writable here through `update_persona_identity_priors`, and nothing records whether a given value came from a research run, from an agent, or from a person typing it — so they are not a research signal. Even run-written ones are aggregate-calibrated, never span-receipted, so they are not evidence you can follow to a source. `get_report` is where the run-written copy lives WHEN A RUN PRODUCED ONE (nested under `report_data.personas[].identityPriors`, unreachable by editing; absent on a persona that never had a run), along with forum receipts (`sources[]`) and `identityProvenance`. Treat every other field here as unverified profile data until you have checked it there. Read-only: no credit cost, no side effects.

UUID of the persona to fetch. Get it from a `list_personas` entry, or from the id printed by `create_persona` / `generate_persona`. Rejected with a 404 if you do not own it. Returns the persona ENTITY (name, role, company, industry, etc.) for discovery/correction, including `seniority` / `careerPath` when the persona has them. Those two are user-editable in the web app and writable through `update_persona_identity_priors`, and this response does NOT record whether a given value came from a research run, from an agent, or from a person typing it — so do not read them as a research signal. The run-written copy, where a run produced one, is at `report_data.personas[].identityPriors`; forum sources and `identityProvenance` live there too. Read all three via `get_report`.

Orient on a Clien.ai project in ONE call: the project's metadata plus the counts, ids, and one-line summaries of everything in it — personas, interviews, competitors, community signals, and research reports. START HERE when you pick up an existing project and need to know what it already holds; it replaces the five separate `list_*` calls that answer the same question. Reading it BEFORE `clien_research`, `scan_competitors`, or `search_forums` is the cheapest way to avoid paying to rediscover work the project already has. Pass `include` (any of "personas", "interviews", "competitors", "community", "reports") to inline those collections' full records instead of summaries, and `limit` to cap how many records per collection come back. Inlined interviews carry `messageCount` but NOT transcripts — use `get_interview` for one. DEGRADED RESULTS ARE NORMAL AND MUST BE READ CAREFULLY: each collection is fetched independently, so one failing read does not lose the others — a failed one is named as unavailable in the result text (and carried as `{ error: "unavailable", detail }` under its key in host-side `_meta.collections`). The project metadata degrades the SAME way and is flagged in the text with its own warning line — so the project name can be the one part that failed while every collection loaded. An `unavailable` entry is NOT an empty one: never conclude a project has no competitors (and never start a paid scan) on the strength of a collection that failed to load. A collection also comes back `unavailable` when the server answers without a usable count, precisely so a broken response can never read as "this project has none". Re-read just that collection with its `list_*` tool. COUNTS: `count` is the project-wide total and `countExact` is true for personas, interviews, competitors, and community signals. For REPORTS the endpoint returns no total, so a full page yields `countExact: false` and `count` is a LOWER BOUND — there may be more. ORDERING differs per collection and is not interchangeable: personas by newest created, interviews by newest started, reports by newest created, competitors by most recently SEEN (a competitor re-sighted by a later run moves back to the top), and community signals by newest DISCOVERED (stable — a thread seen again does not move). Read-only: no credit cost, no side effects.

Optional list of child collections to INLINE in full — any of "personas", "interviews", "competitors", "community", "reports". Omit (the default) to get counts, IDs, and one-line summaries only, which is usually enough to decide what to read next. Name a collection here when you intend to reason over its records and want to skip the follow-up call. NOTE: inlined interviews carry `messageCount` but NOT their message transcripts — a page of full transcripts would swamp the response; use `get_interview` for one transcript.

personas interviews competitors community reports

Maximum records to sample PER collection (1-50, default 10). Caps the response size — this tool reads five collections at once. The COUNTS are still the project-wide totals (except reports, see `countExact`); this only bounds how many ids/summaries/inlined records come back. To page beyond it, use the per-collection list tool.

UUID of the project to orient on. Get it from `list_projects` (or `create_project`). Rejected with a 404 if the project does not exist or belongs to a different account.

Retrieve the full report for a past `clien_research` job by its `job_id` (from a `list_reports` entry, which prints every run's id, or from the error text of a run that dropped mid-flight). Returns the markdown report as text, FOLLOWED BY A MACHINE-CHECKED TRUST DIGEST rendered into that same text — read the digest rather than trusting the prose. The digest carries: Raw typed `report_data` states, source ids, and attestation markers are stored audit data, not citation eligibility. Only the machine-checked TRUST DIGEST's rendered state and receipt arrow authorize Cited: the digest must resolve a canonical, spine-owned pointer to a safe reachable HTTP(S) destination. Dangling, malformed, cross-persona, unsafe, credentialed, or incomplete pointers degrade without an arrow and MUST NOT be cited. (1) the persona claim spine — every claim's rendered GROUNDED / SPECULATION / NO_RECEIPT state; only an eligible Cited row has a "RCP-p{i}-s{j}" receipt arrow into the pool below it. One discussion can carry several bounded excerpts. A claim addressing one shows a second id after "·" (form "rr1:<16 hex>"), and the receipt pool hangs that excerpt off the source row on its own "↳" line: read THAT line, not the row's first excerpt, as what the claim was checked against. These are excerpts from a discussion, never a speaker's exact words. A claim whose second id does not resolve under its own source loses the arrow entirely and MUST NOT be cited. NO_RECEIPT can mean a bad claim OR merely sparse evidence, so check that persona's `insufficientEvidence` / `sourcesFound` line before discounting it. (2) the SEPARATE market/competitor spine — same three rendered states; eligible Cited rows carry "RRCP-s{n}" receipt arrows into their own evidence pool; a NO_RECEIPT claim marked "Cited" means a supporting page was read and independently vouched but no exact span pinned (NOT a receipt), and an unmarked NO_RECEIPT is recalled model knowledge, unverified. Neither counts as grounded — key on the digest's rendered state and arrow, never raw state or whether a source id is present. (3) the SOURCE TYPE on every receipt — `user_voice` (a real person's first-hand account), `report_evidence` (authoritative/third-person reporting), `marketing_seo` (vendor marketing or SEO content), or `unclassified`. Every "RRCP-" market/competitor receipt carries a `source type:` line; a "RCP-" persona receipt is a first-hand `user_voice` post unless its row says otherwise, and any that is not carries the same line marked ⚠. `marketing_seo` is shown for awareness but is EXCLUDED from grounding AND from automatic community synthesis — it is vendor marketing or SEO content, never cite it as user evidence. `unclassified` is EXCLUDED from both as well, and means the classification is genuinely unknown, NOT that the source was checked and found benign. Before the proof separator, the result may include carefully labelled MODEL-AUTHORED report framing: `personasSynthesis` plus only the actionable parts of `researchBrief` (target market, value proposition, assumptions, competitive landscape, and key risks). This framing is NOT evidence or findings. Structured `report_data` also carries typed `methodology` without duplicating its existing markdown section, and a safe `interviewHighlights[]` projection with only `personaName`, `personaRole`, `overallImpression`, and `quotesByHypothesis` — internal `researchTaskId` is excluded. The trust digest includes a compact, code-derived competitor source-quality aggregate and names only rows flagged with the exact `marketing_seo` mark; it does not repeat competitor positioning or notes below the proof separator. (4) per-persona QA — a ⚠ QA-FLAGGED persona failed a quality check (or could not be checked at all); do not rely on its claims. Its `identityPriors` (seniority rung, career path) are typed enrichment and `identityProvenance` is a PII-free aggregate calibration line — NEVER a receipt, do not cite it as a source. (5) the anti-sycophancy readout — explicit rejection count, `lowDiscrimination` broken-persona flags, and per-hypothesis disagreement splits. (6) The digest also reports hypothesis robustness: when a verdict FLIPPED under rephrasing it names the downgraded verdict to act on. Each re-tested row quotes the hypothesis statement and any scope caveat. A scope caveat means persona support came from outside that persona's credibility domain: treat that support as directional, never grounded. A separate "Scope caveats on hypotheses not re-tested" block carries every such qualification on a single-shot verdict; those are not robustness results. The typed `openQuestions[]` field is returned at `structuredContent.report_data.openQuestions`, where it lists what the run did not settle. Its strict `status` is `never_asked`, `nobody_answered`, or `voices_disagreed`. When the run wrote one, its own verdict rationale is rendered in the result text under "## Verdict rationale", and typed at `structuredContent.report_data.verdictSummary`: 1-2 sentences the agent wrote at synthesis time saying WHY the overall verdict came out this way. It is RETRIEVED, not derived — never recompute or paraphrase it from the verdict counts or the confidence number. It is often ABSENT, which is normal and not an error: the run may predate the field, have written none, or have had it withdrawn because a robustness re-ask downgraded a verdict it argued for. When it is absent, say no rationale was recorded rather than inferring one. When a section is missing the digest SAYS SO ("NOT PRESENT on this run") — absent is not clean, so treat the corresponding prose as unverified. The full structured `report_data` (hypotheses, competitors[], key findings, and every field summarised above) is also returned as `structuredContent.report_data`, mirrored in `_meta.report_data`. Use this to RETRIEVE past research instead of re-running `clien_research`, which would debit credits again for the same idea. Backs the competitor spot-check (read `report_data.competitors[]`) and pivot-viability (compare a pivot's report against the original) recipes in docs/recipes/. If the job is still running or you are unsure of its state, use `clien_research_status`. Read-only: no credit cost, no side effects.

UUID of the research job whose report you want to retrieve. Get it from a `list_reports` entry, which renders every run's id in its result text; a dropped run also carries its id in the error message. (It is mirrored to host-side `_meta.job_id` as well, but that reaches your MCP client, not you.) Use this to RETRIEVE a past report instead of calling `clien_research` again — re-running would spawn a new job and debit another 50 credits for the same idea. Read-only: no credit cost.

Run a real, stateful multi-turn interview with a persona and get its full replies. IMPORTANT — these personas are SYNTHETIC: AI-generated composites, not real people. Their replies are simulated research signal, never testimony from a human, and the persona will stay in character if you ask whether it is an AI (it will answer plainly if you press). Say so whenever you relay these answers to a person. Drive it as a loop: `action:start` once (with project_id + persona_id) opens the interview and seeds the persona's greeting, printing the interview id in its result text. Then `action:turn` (interview_id + content) repeatedly — each call posts one question and returns THAT persona's full reply as the result text; read it, then ask the next question. `action:transcript` (interview_id) re-reads the whole conversation. `action:complete` closes the interview when you've learned enough (5-12 turns is typical); `action:reopen` resumes a completed one. Interviews and their auto-summary/message-count behave exactly like the web app. Set `ephemeral:true` on `start` for a scratch interview excluded from the project's aggregate insights. ANCHOR IT: when the questions come from `list_interview_scripts`, pass that script's `hypothesisId` as `hypothesis_id` and the call's `sourceRun.id` as `hypothesis_run_id` on `start` (both or neither). The interview stores which hypothesis it tested and returns it on `get_interview` / `list_interviews`, so the answers can be tied back without you carrying the id through the conversation; `start` tells you if the server did not record it. Compose with `create_persona` to validate a new market or pressure-test a pivot (see docs/recipes/); for a FULL validation report, prefer `clien_research` over stitching interviews together yourself. Each `turn` generates a real AI reply. Billing is a FLAT 3-credit charge for the WHOLE interview, however many turns it runs: the first charging turn debits it, and every later turn — or a retry of the same one — replays that charge to a no-op, so it is free. Credits are the ONLY meter: there is no separate token allowance, so a turn never fails for usage reasons while you hold credits.

What to do this call. Drive a full interview as a loop: `start` once to open an interview (seeds the persona's greeting), then `turn` repeatedly — send a question, read the persona's full reply, decide the next question. `transcript` re-reads the whole conversation. `complete` closes the interview when you've learned enough (5-12 turns is typical); `reopen` resumes a completed one.

action=turn: the next question to ask the persona. The persona's full reply comes back in the tool result text.

action=start: set true for a scratch/throwaway interview that should NOT count toward the project's aggregate insights (sets include_in_insights=false). Leave false (the default) for a real interview you want reflected in project-level analysis.

action=start: the `hypothesisId` of the `list_interview_scripts` script you are about to ask, RECORDED ON THE INTERVIEW. Send it with `hypothesis_run_id` (that call's `sourceRun.id`) or not at all — an id alone is ambiguous, because the same "H3" recurs across runs of one project meaning different things. Optional: omit both for an interview that tests no particular hypothesis. Once stored it comes back on `get_interview` and `list_interviews`, so the answers stay tied to the hypothesis without you carrying the id through the conversation.

action=start: the research run that defined `hypothesis_id` — `sourceRun.id` from the same `list_interview_scripts` call. Required whenever `hypothesis_id` is sent, and refused without it. Recorded as provenance, NOT checked against the run: a run can be deleted and the interview outlives it.

DEPRECATED alias for `interview_id` — pass `interview_id` instead. Still accepted for backward compatibility. Passing both this and `interview_id` with DIFFERENT values is rejected.

action=turn/transcript/complete/reopen (REQUIRED there): UUID of the interview to act on. Printed by `start` in its result text ("Started interview <id>"), or discoverable via `list_interviews`.

DEPRECATED alias for `persona_id` — pass `persona_id` instead. Still accepted for backward compatibility. Passing both this and `persona_id` with DIFFERENT values is rejected.

action=start (REQUIRED there): UUID of the persona to interview (must belong to `project_id`). Get it from `list_personas`, or from the id printed by `create_persona` / `generate_persona`.

DEPRECATED alias for `project_id` — pass `project_id` instead. Still accepted for backward compatibility. Passing both this and `project_id` with DIFFERENT values is rejected.

action=start (REQUIRED there): UUID of the project the interview belongs to. Get it from `list_projects` or `create_project`. You are 404'd if you do not own it.

List the community signals (forum / Hacker News / Stack Exchange threads) recorded for a Clien.ai project (newest-discovered first, paginated). Returns each thread's title, platform, sentiment summary, url, one representative quote (with `(+N more cached)` when the thread has others, so one quote is not mistaken for all there was), and engagement as readable text (shown only when a real, non-zero count was measured — an absent engagement line means either UNMEASURED or genuinely zero on both sides, which the render cannot distinguish); the full signal array and pagination are also returned as `structuredContent.communitySignals` / `.pagination` (mirrored in `_meta`). Requires a `project_id` — call `list_projects` to find one. This reads the project's DEDUPED, ACCUMULATED thread set — merged across every research run and the web app — so unlike `get_report` (one run's view) or `search_forums` (a fresh, credit-debiting scan), it answers "what user voice has this project already collected?" for free. Check here BEFORE running `search_forums` to avoid paying to rediscover threads you already have. Each signal's `relevantQuotes[]` are the user-voice excerpts cached at collection — the same field `search_forums` returns — so they stay readable even if the thread later disappears. ORDERING differs from `list_competitors` on purpose: this feed is ordered by when the project FIRST saw a thread and that order is STABLE — a thread a later run sees again does not move back to page one. So page one is the newest DISCOVERIES, not the newest activity; do not read a thread's position as a recency signal. SOURCE TYPE: every returned community row carries a `source type:` line — `user_voice` (a real person's first-hand account), `report_evidence` (authoritative/third-person reporting), `marketing_seo` (vendor marketing or SEO content), or `unclassified`. `marketing_seo` is shown for awareness but is EXCLUDED from grounding AND from automatic community synthesis — it is vendor marketing or SEO content, never cite it as user evidence. `unclassified` is EXCLUDED from both as well, and means the classification is genuinely unknown, NOT that the source was checked and found benign. Read-only: no credit cost, no side effects.

Maximum number of community signals to return (1-100, default 20). Newest-discovered first. This feed is ordered by when the project FIRST saw a thread, and that order is stable — a thread seen again by a later run does not jump back to the top (unlike `list_competitors`, which is ordered by latest sighting).

Number of community signals to skip before returning results (default 0). An absolute row offset, honoured exactly — combine with `limit` to page through a large feed; the total count is stated in the result text ("Found N community signals").

UUID of the project whose community signals to list. Get it from `list_projects` (or `create_project`). Rejected with a 404 if you do not own the project. Lists the project's whole accumulated thread set — including threads found by web-app runs and by earlier `search_forums` / `clien_research` calls, deduped by url across runs.

List the competitors recorded for a Clien.ai project (most-recently-seen first, paginated). Returns each competitor's name, pricing, description, url, company facts and strengths/weaknesses as readable text; the full competitor array and pagination are also returned as `structuredContent.competitors` / `.pagination` (mirrored in `_meta`). Requires a `project_id` — call `list_projects` to find one. This reads the project's DEDUPED, ACCUMULATED competitor set — merged across every research run and the web app — so unlike `get_report` (one run's view) or `scan_competitors` (a fresh, credit-debiting scan), it answers "what does this project already know?" without spending anything. Check here BEFORE running `scan_competitors` to avoid paying to rediscover competitors you already have. TRUST: each of the four company facts (`funding`, `employeeCount`, `founded`, `hqLocation`) is followed IN THE TEXT by its own trust state in brackets — `[GROUNDED]`, `[SPECULATION]`, `[NO_RECEIPT]`, or `[no grounding]` / `[state?]` when no recognised state was recorded. Read the bracket, not the number: only `[GROUNDED]` means a source was checked, and the last two are NOT "checked and refuted". Cite only `[GROUNDED]` figures; state the rest as unverified. The same states are available structurally on the sibling `<fact>Grounding` field ({ state, sourceUrl?, sourceRetrievedAt? }), persisted in lockstep with the value. Strengths and weaknesses carry NO grounding of any kind — they are the research agent's reading, never receipted. Read-only: no credit cost, no side effects.

Maximum number of competitors to return (1-100, default 20). Most-recently-seen competitors come first.

Number of competitors to skip before returning results (default 0). An absolute row offset, honoured exactly — combine with `limit` to page through a large set; the total count is stated in the result text ("Found N competitors").

UUID of the project whose competitor set to list. Get it from `list_projects` (or `create_project`). Rejected with a 404 if you do not own the project. Lists the project's whole accumulated competitor set — including competitors found by web-app runs and by earlier `scan_competitors` / `clien_research` calls, deduped across runs.

Read the INTERVIEW SCRIPTS a Clien.ai research run wrote for a project — the questions that run decided are worth asking real people, one script per hypothesis, ranked least-settled first. Returns each script's hypothesis id, statement, verdict, confidence, who to recruit and its questions as readable text; the full set and the run it came from are also returned as `structuredContent.interviewScripts` / `.sourceRun` (mirrored in `_meta`). Requires a `project_id` — call `list_projects` to find one. CALL THIS BEFORE `interview_persona`. These questions are anchored to the run's open hypotheses, so the answers feed back into its claim spine; questions you invent, or re-derive from `get_report`'s hypothesis list, are not, and re-deriving them is recomputing something the run already produced and stored. STORED, NOT SUGGESTED: this is the persisted output of ONE SPECIFIC RUN, named in the result and written when that run executed. Nothing is generated to answer this call, now or ever — it is a free read of a report that is already immutable, so the verdict beside each script is that run's and may be older than today. NO SCRIPTS IS NOT "NOTHING WORTH ASKING": a project can legitimately have none, because scoped runs (`scan_competitors`, `search_forums`) never write them and a failed run writes nothing. The tool says so explicitly and you must not convert it into a claim that the hypotheses are settled. LINKAGE: pass a script's `hypothesisId` to `interview_persona action:start` as `hypothesis_id`, together with this call's `sourceRun.id` as `hypothesis_run_id`. The interview then RECORDS which hypothesis it tested and hands it back on `get_interview` / `list_interviews`, so the tie survives without you carrying the id. Both or neither — an id is only meaningful against the run that defined it. TRUST: the verdicts and confidences here are the source run's reading of its own hypotheses, not graded claims — no GROUNDED / SPECULATION / NO_RECEIPT states attach to them; read the source run with `get_report` for those. Read-only: no credit cost, no side effects.

UUID of the project whose interview scripts to read. Get it from `list_projects` (or `create_project`). Rejected with a 404 if you do not own the project. Returns the STORED OUTPUT OF ONE SPECIFIC RESEARCH RUN — the scripts that run wrote when it ran, one per hypothesis, ranked least-settled first — not a live suggestion and not something generated when you call this. The run is named in the result; pass its id to `get_report` for the hypotheses behind the questions. A project can legitimately have NO scripts; that is reported as "no run has written any", never as "there is nothing worth asking".

List the interviews in a Clien.ai project (newest first, paginated). Returns each interview's status, persona id, message count, and id as readable text; the raw interview array and pagination are also returned as `structuredContent.interviews` / `.pagination` (mirrored in `_meta`). Entries carry `messageCount`, NOT their message transcripts — a page of full transcripts is a lot of context for a "which interviews exist?" question; read one with `get_interview`. Requires a `project_id` — call `list_projects` to find one. Use it to RECOVER a past interview id (including interviews started in the web app) so you can re-read its transcript with `get_interview` — previously an interview id was only obtainable from `interview_persona action:start` in the same session. Read-only: no credit cost, no side effects.

Maximum number of interviews to return (1-100, default 20). Newest interviews come first.

Number of interviews to skip before returning results (default 0). Combine with `limit` to page through a large interview list; the total count is stated in the result text ("Found N interviews"), which also tells you how many remain and the offset to page with.

UUID of the project whose interviews to list. Get it from `list_projects` (or `create_project`). Rejected with a 404 if you do not own the project. Lists interviews started from the web app too, so you can discover an interview id to re-read with `get_interview`.

List the personas in a Clien.ai project (newest first, paginated). Returns each persona's name, role, and id as readable text; the raw persona array and pagination are also returned as `structuredContent.personas` / `.pagination` (mirrored in `_meta`). This list is deliberately one line per persona — call `get_persona` for a full profile. Requires a `project_id` — call `list_projects` to find one. This is the KEYSTONE discovery read: it surfaces personas created in the web app too, so you can get a persona `id` to pass to `get_persona`, `update_persona`, `enrich_persona`, or `interview_persona` — previously an agent could only reach personas it created in the same session. Each entry carries `seniority` / `careerPath` when the persona has them — user-editable in the web app and writable here through `update_persona_identity_priors`, and nothing records whether a given value came from a research run, from an agent, or from a person typing it — so they are not a research signal. The run-written priors, forum sources and `identityProvenance` all live in `report_data` (read them via `get_report`). Read-only: no credit cost, no side effects.

Maximum number of personas to return (1-100, default 20). Newest personas come first.

Number of personas to skip before returning results (default 0). Combine with `limit` to page through a large persona list; the total count is stated in the result text ("Found N personas"), which also tells you how many remain and the offset to page with.

UUID of the project whose personas to list. Get it from `list_projects` (or `create_project`). Rejected with a 404 if you do not own the project. Lists personas created via the web app too, so you can discover a persona id to pass to `get_persona`, `update_persona`, `enrich_persona`, or `interview_persona`.

List the caller's Clien.ai projects (newest first, paginated). Returns each project's name and id as readable text; the raw project array and pagination are also returned as `structuredContent.projects` / `.pagination` (mirrored in `_meta`). Use this to find an existing `project_id` to attach a `clien_research` run to, or to check whether a project already exists before calling `create_project`. Read-only: no credit cost, no side effects.

Maximum number of projects to return (1-100, default 20). Newest projects come first.

Number of projects to skip before returning results (default 0). Combine with `limit` to page through a large project list; the total count is stated in the result text ("Found N projects"), which also tells you how many remain and the offset to page with.

List the caller's past `clien_research` runs (newest first, paginated by `limit`). Returns each report's prompt, status, and `job_id` as readable text; the raw job array is also returned as `structuredContent.jobs` (mirrored in `_meta.jobs`). Optionally scope to one project with `project_id`. Use this to find a past report to retrieve with `get_report` instead of re-running `clien_research` — re-running spawns a new job and debits credits again for the same idea. Pair with `get_report` for a free competitor spot-check (read `report_data.competitors[]` from a recent run; see docs/recipes/competitor-spot-check.md). Read-only: no credit cost, no side effects.

Maximum number of research reports to return (1-100, default 20). Newest reports come first.

Optional project UUID to scope the list to a single project. Omit to list reports across all of the caller's projects. Use `list_projects` to find a project id.

Scan the competitive landscape for a product idea or market — a targeted, cheaper alternative to the full clien_research report when you only need the COMPETITOR dimension. Runs one web researcher (not the whole H1-H8 pipeline): typical wall time 2-10 minutes, progress streamed via notifications/progress. Renders every competitor into the result text — name, url, description, pricing, strengths[], weaknesses[], and the four company facts (`funding`, `employeeCount`, `founded`, `hqLocation`). The same list, plus `relevantHypotheses[]`, is mirrored to host-side `_meta.competitors` for your MCP client. TRUST: those four company facts are UN-RECEIPTED here — this tool stores the value the researcher wrote, not the URL it came from, and attaches no grounding object to any of them. Treat all four as unverified, and do not cite them as source-checked. The surface that DOES carry per-fact provenance is `list_competitors`, where each of the same four facts has a sibling `<fact>Grounding` field ({ state: GROUNDED | SPECULATION | NO_RECEIPT, sourceUrl?, sourceRetrievedAt? }) — key on `state` there, and treat anything that is not GROUNDED as unverified. WHAT COUNTS AS A COMPETITOR: direct and adjacent products/services a target user would realistically evaluate or already use to solve the same problem — including incumbents, startups, and notable open-source or DIY alternatives; not tangential tools. Depth is a focused landscape scan (roughly 3-10 competitors), not an exhaustive market map. CHECK THE FREE READ FIRST: `list_competitors` returns the competitors a project has already accumulated across every past run and the web app, at no credit cost. Read it (or `get_project`) before spending here, so you do not pay to rediscover what the project already knows. Use this tool when you need a FRESH scan or the project has no competitors yet. ATTACH TO A PROJECT so results are saved to the web app's Research → Competitors tab: pass `project_id` for an existing project, or `project_name` to auto-create one. Without either, the scan still returns competitors here but does NOT persist them. Composes well: run this for a quick competitor spot-check, or before/after a pivot to compare landscapes; for a COMPLETE validation (personas, interviews, synthesis) prefer clien_research. This debits credits (a scoped web scan). IMPORTANT: if the call drops mid-flight with "MCP error -32000", the job keeps running on the backend — do NOT blindly re-call (that starts a new run and debits again); the job_id is logged to the MCP server stderr as `[clien-mcp] scan_competitors started job_id=…`.

Optional short product/brand name for research context (2-4 words). Sharpens the researcher's framing; defaults to a slug of `topic` when omitted.

Clien.ai project UUID to attach this scan to. REQUIRED for the results to be saved to the project's Research tab (competitors/community collections are project-scoped). Call `list_projects` to find one. When omitted, supply `project_name` to auto-create a project, or the scan runs standalone (results returned here but NOT persisted).

Name for a NEW Clien.ai project to auto-create and attach this scan to. Supply this (a short 2-4 word product name) whenever you do NOT already have a `project_id`, so the findings are discoverable in the web app's Research tab. The project is created server-side ONLY when the run is accepted — insufficient credits or an active-run conflict will not create it, and retries never mint duplicates. Ignored when `project_id` is provided.

The product, idea, or market to scan the competitive landscape for. Describe it in a sentence or two (min 20 chars) — e.g. "an AI meeting-notes tool for remote engineering teams that auto-files action items into Linear". More context yields sharper competitor discovery.

Research a MARKET — how big it is, whether it is growing, what is moving it, and what it does not serve. A targeted, cheaper alternative to the full clien_research report when you only need the MARKET dimension. Runs one market researcher over news and financial-report sources (not the whole H1-H8 pipeline): typical wall time 2-10 minutes, progress streamed via notifications/progress. Returns the market size, the growth trend, every atomic figure the run recorded with the scope the source named, the key trends, and the positioning gaps — the same five things it publishes to the web app's Research → Market tab. All of it is rendered into the result text you can read; the same block is also mirrored to host-side `_meta.market` for your MCP client. IT DOES NOT DISCOVER COMPETITORS, and it leaves the competitor and community dossiers completely untouched — use `scan_competitors` for the landscape and `search_forums` for user voice. TRUST: the figures are UNGRADED on this surface — no per-figure source state is attached, and the absence of a marker is not a clean bill of health. A figure carrying no scope label is a market SIZE whose slice the source never named; it is NOT a defaulted "total addressable market". A run that recorded nothing says so explicitly, and that means the RUN found no figures — never that the market is small, absent, or zero. CHECK THE FREE READ FIRST: `get_market` returns the market snapshot the project already holds, at no credit cost, with the id of the run that produced it. Read it (or `get_project`) before spending here. Use this tool when you need a FRESH read or the project has no market data yet. ATTACH TO A PROJECT so results are saved: pass `project_id` for an existing project, or `project_name` to auto-create one. Without either, the research still returns here but does NOT persist. ⚠ IT REPLACES THE WHOLE MARKET SNAPSHOT. A project has ONE market record, written by one run, so a successful scan replaces every field — including emptying a list this run did not establish. That is what keeps the record and its source run honest about each other; it is not a merge. This debits credits (a scoped market run). IMPORTANT: if the call drops mid-flight with "MCP error -32000", the job keeps running on the backend — do NOT blindly re-call (that starts a new run and debits again); the job_id is logged to the MCP server stderr as `[clien-mcp] scan_market started job_id=…`.

The market to size and characterise, described in a sentence or two (min 20 chars) — e.g. "AI meeting-notes tooling sold to remote engineering teams". Name the CATEGORY and the BUYER: this run searches news and financial-report sources for sizing, growth and demand, and a topic phrased as a single product name gives it nothing to size. It does NOT discover competitors — use `scan_competitors` for the landscape.

Search real community discussions (Hacker News, Stack Exchange / Stack Overflow, Indie Hackers, dev.to, Lobsters, Product Hunt) for PRODUCT-VALIDATION signal about an idea or user problem — a targeted, cheaper alternative to the full clien_research report when you only need the COMMUNITY dimension. Runs one forum researcher (not the whole H1-H8 pipeline): typical wall time 2-10 minutes, progress streamed via notifications/progress. Renders every thread into the result text — title, platform, url, sentimentSummary, its first cached quote, its `source type:` line, and engagement (upvotes · comments) ONLY when the thread carries a real, non-zero count — an absent engagement line means the counters were either never measured or genuinely zero on both sides — the render cannot tell those apart, so do not read a missing line as low traction. When a thread cached more than one quote the row says so — `(+N more cached)` after the quote — so you can tell a heavily-discussed thread from a barely-quoted one; the quotes themselves are in `structuredContent` (also mirrored to host-side `_meta.threads`). WHAT IT LOOKS FOR: evidence about the PROBLEM and demand — people describing the pain point, asking for a solution, or complaining about existing tools — not generic keyword hits. This is NOT a generic web search; frame the topic as a user problem/audience for the best threads. CHECK THE FREE READ FIRST: `list_community_signals` returns the threads a project has already accumulated across every past run and the web app, at no credit cost — including each thread's cached `relevantQuotes[]` excerpts, the same field this tool returns. Read it (or `get_project`) before spending here, so you do not pay to rediscover user voice the project already holds. Use this tool when you need FRESH threads or the project has none yet. SOURCE TYPE: every returned community row carries a `source type:` line — `user_voice` (a real person's first-hand account), `report_evidence` (authoritative/third-person reporting), `marketing_seo` (vendor marketing or SEO content), or `unclassified`. `marketing_seo` is shown for awareness but is EXCLUDED from grounding AND from automatic community synthesis — it is vendor marketing or SEO content, never cite it as user evidence. `unclassified` is EXCLUDED from both as well, and means the classification is genuinely unknown, NOT that the source was checked and found benign. The type is stamped from the host by code, never written by a model, and only hosts the forum allowlist recognises get one — so `unclassified` is COMMON. ATTACH TO A PROJECT so results are saved to the web app's Research → Community tab: pass `project_id` for an existing project, or `project_name` to auto-create one. Without either, the threads are returned here but NOT persisted. Composes well with scan_competitors (demand + landscape) for a quick read on an idea — but run the two SEQUENTIALLY when they target the same project: the backend allows one active research run per project, so a parallel second call fails with 409. For a COMPLETE validation (personas, interviews, synthesis) prefer clien_research. This debits credits (a scoped forum scan). IMPORTANT: if the call drops mid-flight with "MCP error -32000", the job keeps running on the backend — do NOT blindly re-call (that starts a new run and debits again); the job_id is logged to the MCP server stderr as `[clien-mcp] search_forums started job_id=…`.

The user problem, product idea, or audience to search community discussions for — framed as a PROBLEM, not a keyword (min 20 chars). e.g. "how remote engineering teams currently capture and track action items from meetings, and what frustrates them". This mines PRODUCT-VALIDATION signal on Hacker News, Stack Exchange / Stack Overflow, Indie Hackers, dev.to, Lobsters, Product Hunt (pain points, demand signals, gripes about existing tools) — it is NOT a generic web search. The more the topic names the audience and their pain, the better the threads.

Correct explicit scalar fields of an EXISTING persona (fix a wrong role, company, industry, background, etc.). Supply `persona_id` and at least one of `name`, `role`, `company`, `description`, `company_size`, `industry`, `location`; only the fields you pass are changed. The result text names the persona, its id, and the fields it just set — named as they appear on the persona ENTITY (so `company_size` reports back as `companySize`). The persona record and that changed-field list are mirrored to host-side `_meta.persona` / `_meta.updated`. This is a FREE, unmetered explicit edit — it does NOT use the AI or debit a credit (use `enrich_persona` to AI-fill blank fields instead, or `generate_persona` to AI-create a new one). Completes the read → correct → interview loop from the agent: discover a persona with `list_personas`, fix it here, then `interview_persona`. Rejected with a 404 if you do not own the persona (call `list_personas` to confirm the id); a persona locked by subscription limits is refused separately with an upgrade prompt. Identity priors (`seniority` / `careerPath`) are not among this tool's fields — `update_persona_identity_priors` is the tool that writes those two. That is a routing split, not a restriction on the values: the user CAN edit both in the web app and you CAN write both through that tool, so never report them to anyone as immutable or as research-derived.

New company or organisation.

DEPRECATED alias for `company_size` — pass `company_size` instead. Still accepted for backward compatibility. Passing both this and `company_size` with DIFFERENT values is rejected.

New company size (e.g. "11-50", "Enterprise").

New background/bio (goals, pain points, context).

New industry (e.g. "Fintech", "Healthcare").

New location (e.g. "Berlin, Germany").

New name for the persona.

UUID of the persona to update. Get it from a `list_personas` entry, or from the id printed by `create_persona` / `generate_persona`. Rejected with a 404 if you do not own it.

New job title / role (e.g. fix a wrong role).

Set a persona's identity priors — `seniority` (the RUNG: a level of responsibility like "senior IC" or "team lead", not a job title) and `careerPath` (the trajectory, e.g. "support → product ops → PM"). Supply `persona_id` and at least one of `seniority`, `career_path`; only the field you pass changes, and an empty string clears it. These two live on their own tool because they are written only by named writers, never by a general persona patch — `update_persona` handles the ordinary scalars. This is a FREE, unmetered explicit edit: it does NOT use the AI or debit a credit (use `enrich_persona` to have a model fill blank fields instead). Rejected with a 404 if you do not own the persona (call `list_personas` to confirm the id); a persona locked by subscription limits is refused separately with an upgrade prompt. TRUST: these fields are user-editable in the web app and writable here, and NOTHING records whether a stored value came from a research run, from an agent, or from a person typing it — so writing one does not make it grounding, and reading one back later is not a research signal. What a run produced stays at `report_data.personas[].identityPriors` (read it with `get_report`), which this write does not touch — so overwriting here never destroys the run's own record.

New career path / trajectory, e.g. "support → product ops → PM". Pass an empty string to clear it. This field is user-editable in the web app as well as writable here, and nothing records which origin a stored value has, so writing it does not make it grounding.

UUID of the persona whose identity priors to set. Get it from a `list_personas` entry, or from the id printed by `create_persona` / `generate_persona`. Rejected with a 404 if you do not own it.

New seniority RUNG — a level of responsibility ("senior IC", "team lead"), not a job title. Pass an empty string to clear it. This field is user-editable in the web app as well as writable here, and nothing records which origin a stored value has, so writing it does not make it grounding.