person_attach
Tier: write · Tags: person, write
Enrich one existing private person with extra grounding -
exactly one of source / evidence. Use this to add
hand-tailored material to a single persona after the fact (vs.
person_generate, which mints N personas from a brief / sources). See
docs_get("guides/build-specific-person") for the evidence loop.
source=SourceAttachInput(path=..., description=...)runs the Person-scoped 3-step attachment intake (initiate → signed-URL PUT → confirm) - a file you want this persona to react to.evidence=[EvidenceTraceInput(...), ...]POSTs scenario answers the persona’s simulation-time prompt reads as<past_reactions>.
visibility="private"): the backend
rejects shared/published people (moderation gate); the MCP surfaces
that as [validation_error] with a “must be private” message.
person_id: UUID or short alias (e.g. p-d4e); must be a
caller-owned private Person.
source: file payload - exactly one of source / evidence.
evidence: 1..N EvidenceTraceInput rows (mutually exclusive with
source). Each carries text (persona answer), source enum
(situation / voice / binary / micro-story),
scenario_prompt (the question), optional raw_response.
Returns a PersonAttachResponse. With source, success sets
attachment_id; with evidence, evidence_traces lists the
persisted rows. On failure inspect error_kind ∈ {validation_error, not_found, forbidden, server_error, network_error, http_error}.
Parameters
string
required
UUID or short alias (e.g. ‘w-6ec’, ‘p-abc’)
object
object[]
person_delete
Tier: destructive · Tags: delete, person
Permanently delete a person. DESTRUCTIVE.
Public-pool people cannot be deleted by individual workspaces; the
backend rejects those with [auth_failed] (or [not_found] if
the Person does not exist).
person_id: UUID or short alias (e.g. p-d4e) of the person
to delete.
Returns {"deleted": True, "person_id": <id>} on success; on
failure raises ToolError with error_kind ∈ {auth_failed, forbidden, not_found, server_error, network_error, http_error}.
Parameters
string
required
UUID or short alias (e.g. ‘w-6ec’, ‘p-abc’)
person_generate
Tier: long-running · Tags: dispatch, person
Build a person (or cohort) “ish” from a description and/or real
research artifacts, via the agentic generation pipeline (turns the
brief plus uploaded evidence - emails, PDFs, text, images, audio - into
people, optionally with grounded scenarios). See
docs_get("concepts/person") (generate vs manual) and
docs_get("concepts/source") (artifacts as generation inputs).
Blocks by default (wait=True): uploads artifacts, enqueues the
job, polls to terminal, returns resolved people + scenarios. Pass
wait=False for the job_id immediately, then pick up results via
person_get(workspace_id=..., type="ai") - see
docs_get("reference/long-running-jobs"). The three inputs
(description, source_paths, source_upload_ids) freely combine.
Counts toward the plan’s custom-person entity cap (independent of the
per-run credit pool) - see docs_get("reference/credits"); on hit:
[usage_limit_reached].
Single-person role-fitting (pair-mode use case). Pair-mode chat
rehearsals (study_add_iteration with chat_pair=...) need one person
per side: call person_generate(count=1, description="...") per side;
the returned ids plug into ChatPairConfig.group_a / group_b.
workspace_id: UUID or short alias (e.g. w-6ec) of the workspace.
description: free-text audience brief (>=20 chars when supplied).
source_paths: evidence references - prefer a data: URL or an
http(s):// URL (fetched server-side, SSRF-guarded, 10MB cap): those are
portable and work against the hosted server. A local file path is read from
the MCP server’s own filesystem, so it only helps when you run the
server yourself. To feed raw local bytes to the hosted server, upload them
first with source_upload(inline_base64=...) and pass the returned id via
source_upload_ids. Supported MIME: audio/*, image/*, text/*,
application/pdf, application/json, office-document types.
source_upload_ids: reuse sources already uploaded via
source_upload (or a prior partial build) without re-uploading.
reaction_notes: one researcher note per source_paths entry (same
order, same length) describing how the real person reacted to THAT
artifact; "" skips a note for that file.
count: pin audience size to [1, 10]; omit to let the agent propose.
age_range: (min, max) inclusive. country: ISO-3166-alpha-2
codes. gender: list of gender labels.
generate_evidence: also produce grounded EvidenceTrace rows.
None (default) = auto (scenarios only when sources attached);
True / False override.
wait: block until terminal (default True; runs take ~30-60s).
timeout: seconds to wait when wait=True (default 180s).
Returns a PersonGenerateResponse discriminated by ok. With
wait=True, success populates people + person_ids; with
wait=False, job_id + status="queued" only. On failure inspect
error_kind ∈ {validation_error, not_found, usage_limit_reached, generation_failed, timeout, rate_limited, server_error, network_error, http_error}. Partial-failure contract: when upload(s) succeeded but
enqueue failed, source_ids is still populated so agents can retry
against existing sources without re-uploading.
Parameters
string
required
UUID or short alias (e.g. ‘w-6ec’, ‘p-abc’)
string
string[]
string[]
string[]
integer
object[]
string[]
string[]
boolean
boolean
Default:
true.number
Default:
180.0.person_get
Tier: read-only · Tags: person, read
Read people. Polymorphic on person_id: omit to list, pass it to
fetch one Person. See docs_get("concepts/people") for
people-selection semantics.
List mode (no person_id): people in the workspace plus the
public pool. Within a dimension (country / gender /
occupation / each *_in enum) values OR; across dimensions they
AND. Defaults to type="ai" (simulatable); "human" or "all"
widen it. Pagination via limit (max 200) + offset. Returns a
PaginatedList[Person] ({items, total, returned, limit, offset, has_more}); total is the match count, handy for pre-flighting a
pair-mode side’s pool (the *_in enums + a11y booleans share their
vocabulary with RoleCriteria). If nothing matches, fall through to
person_generate to mint matching people. Public-pool rows surface
but can’t be deleted by the caller (person_delete → [auth_failed]).
Single mode (with person_id): that Person with workspace-scoped
custom fields + usage stats. include_evidence=True attaches persisted
EvidenceTrace rows (newest-first) under the Person’s evidence;
rejected in list mode (per-row evidence blows the token budget).
Three text-search dimensions (each case-insensitive substring, AND’d):
search → name; bio → narrative bio; occupation=[...] →
occupation (OR’d within the dimension).
workspace_id: UUID or short alias (e.g. w-6ec) of the workspace.
person_id: UUID or short alias (e.g. p-d4e); omit to list.
country: ISO-3166-alpha-2 codes. gender: gender labels.
occupation: free-text occupation substrings (OR’d).
role_in: canonical role keys (founder, product_leader,
engineer, …) that OR-expand into many occupation substrings -
a best-effort convenience over free-text occupation; merged with any
explicit occupation. Pass an unknown key to see the full list in the
[validation_error].
age_min / age_max: inclusive age bounds. search: name substring.
bio: bio substring. type: ai (default) / human / all.
limit / offset: pagination. include_bio,
include_accessibility_profile: default False (each is large per
row; fetch a single Person for the full payload). include_evidence:
single mode only.
visibility: narrows the list; default unions every scope, ordered
workspace → platform → shared. Canonical values "workspace" (caller’s
own; required ahead of person_evidence_add), "shared"
(community-published), "platform" (admin-curated). Pre-rollout
"private" / "public" are accepted as deprecation aliases for
"workspace" / "platform".
Extended demographic enums (snake_case, must match
spec/profile-enums.v1.json):
education_level_in:less_than_secondary,secondary,some_post_secondary,vocational_or_associate,bachelor,graduate.household_in:single,couple_no_kids,couple_with_kids,single_parent,shared_housing,adult_with_parents,multi_generational.locale_type_in:urban,suburban,small_town,rural.income_level_in:lower,lower_middle,middle,upper_middle,upper,prefer_not_to_say.employment_status_in:employed_full_time,employed_part_time,self_employed,unemployed_seeking,student,homemaker,retired,unable_to_work,other.
accessibility_profile
JSONB): requires_captions, uses_screen_reader,
prefers_reduced_motion, prefers_high_contrast,
has_any_accessibility_need.
Returns PaginatedList[Person] (no id) or Person (with id);
on failure raises ToolError with error_kind ∈ {auth_failed, forbidden, not_found, server_error, network_error, http_error}.
Parameters
string
required
UUID or short alias (e.g. ‘w-6ec’, ‘p-abc’)
string
string[]
string[]
string[]
string[]
integer
integer
string
string
"ai" | "human" | "all"
Default:
"ai".integer
Default:
50.integer
Default:
0.boolean
Default:
false.boolean
Default:
false.boolean
Default:
false.string[]
string[]
string[]
string[]
string[]
boolean
boolean
boolean
boolean
boolean
"workspace" | "shared" | "platform" | "private" | "public"
source_upload
Tier: write · Tags: person, write
Upload one piece of real evidence (email, PDF, text/doc, image, audio)
so a later person_generate can ground a participant “ish” in how a
real person reacted. Returns a source_upload_id to hand to
person_generate(source_upload_ids=[...]). See
docs_get("concepts/source").
Pass the bytes with inline_base64 (or a data: URL) - that is the
portable path and the only one that works against the hosted MCP server,
which cannot see your filesystem. source_path reads a LOCAL file from
the MCP server’s own filesystem, so it only helps when you run the
server yourself; an http(s):// URL is fetched server-side.
workspace_id: UUID or short alias (e.g. w-6ec) of the workspace.
source_path: read the evidence from the MCP server’s filesystem (a
local path only works when the server runs on your machine), an
http(s):// URL (fetched server-side, SSRF-guarded, 10MB cap), or a
data: URL. Supported MIME: audio/*, image/*, text/*,
application/pdf, application/json, office-document types. Omit when
passing inline_base64.
reaction: researcher note on how the real person reacted to THIS
artifact (e.g. “called this proposal lazy and low-effort”); rides along
to the agent. Backend caps it at 500 chars.
inline_base64: raw base64-encoded file bytes (no data: prefix) - the
portable input for hosted MCP clients that can pass the bytes but not a
server-visible path. file_name is REQUIRED with this (it carries no name
or MIME). Mutually exclusive with a non-data source_path.
file_name: name to record for the upload; required with raw
inline_base64, optional otherwise (overrides the path/URL basename).
content_type: MIME override; inferred from file_name / the remote
Content-Type when omitted.
Returns a SourceUploadResponse discriminated by ok. On
success source_upload_id is the new source’s ID. On failure inspect
error_kind ∈ {validation_error, not_found, server_error, network_error, http_error}.
Parameters
string
required
UUID or short alias (e.g. ‘w-6ec’, ‘p-abc’)
string
string
string
string
string