study_add_iteration
Tier: long-running · Tags: dispatch, study
Add a NEW iteration - a content version (the URL / media / endpoint
participants experience) - to a study. Pick modality and supply only that
modality’s fields. A study has 1..N iterations; study_run defaults to the
latest. This creates a version; it does NOT re-run the study
(study_run), edit an existing iteration in place
(study_update_iteration), or change study-level metadata
(study_revise). Concept: docs_get("concepts/iteration").
interactive:url,platform(browser / android / figma / code),screen_format(mobile_portrait / desktop). Optionallocale,flow_name.platform="figma"also needsfile_key+start_node_id. Theurlis reached by ish’s cloud testers, so it must load WITHOUT your session: use a published / share-preview link, not a login-gated editor preview (Lovable / Replit / Bolt / v0 previews are session-gated) - localhost needsish connect. You set this once per study; later runs reuse the iteration. Credentialed pages: register a login once withsite_access_set. Builder clients get a tailorednoteshint on the response.video/audio/document:content_url(local path or hosted URL). Optionalsegmentation,content_config,copy_content(video/audio),title,mime_type.text:content_text(inline, or@pathfor a local file). Optionalcontent_html,sender_name/sender_email,featured_image_url,segmentation,content_config,title.image:image_urls(non-empty; local paths and/or hosted URLs). Optionalcopy_content,segmentation,content_config,title.chat, two mutually-exclusive sub-modes:external_chatbot- passchatbot_endpoint_id(saved) OR an inlineendpointdict.participant_pair(AI ↔ AI) - passchat_pair=ChatPairConfig(...). Drive each side fromrole_criteria_a/role_criteria_b(backend resolves pools at create time) or from explicitgroup_a/group_b(equal counts zip 1:1, or one side of 1 broadcasts). Scenarios onscenario_a/scenario_b. RoleCriteria enum/accessibility fields:docs_get("guides/chat-pair").chat_pairwithendpoint/chatbot_endpoint_idis a validation error. Optionalmax_turns,early_terminationon both sub-modes.
content_url / image_urls accept local paths (uploaded
and resolved to hosted URLs); content_text accepts @path.
study_id: UUID or alias (e.g. s-b2c) of the study.
Returns an IterationCreateResponse envelope discriminated by ok;
branch on it and read error_kind / suggestions on failure. Media
pre-flight and argument errors come back as ok=False (not exceptions) -
same shape as chatbot_test.
Parameters
UUID or short alias (e.g. ‘w-6ec’, ‘tp-abc’)
study_analyze
Tier: long-running · Tags: dispatch, study
Trigger an AI analysis run for a study and optionally wait for it.
Synthesizes a narrative summary plus a categorised KeyInsight list
(friction / confusion / blocker / observation / positive). Read prior runs
via study_get(view="insights").
Prerequisites (server-enforced): modality in {interactive, video, audio,
text, image, document} (chat ineligible) and a minimum-completions floor. If
it errors on the floor, wait for more completions or fall back to
study_get(view='summary', group_by='segment'|'frame').
Credit cost: first analysis per study is free; each subsequent run costs
10 credits from the workspace’s plan pool. Empty pool →
[insufficient_credits]. Model: docs_get("reference/credits").
study_id: UUID or alias (e.g. s-b2c) of the study.
wait / timeout: blocking contract - docs_get("reference/long-running-jobs").
wait=True polls to completed/failed (raises ToolError on
failed); default returns the pending envelope with a poll hint.
timeout defaults to 300s.
Returns a StudyResult - pending when wait=False, else the
terminal completed envelope (summary + key_insights populated).
Parameters
UUID or short alias (e.g. ‘w-6ec’, ‘tp-abc’)
Default:
false.Default:
300.0.study_benchmark
Tier: long-running · Tags: dispatch, study
Clone a source study (name, description, assignments, interview
questions) to one or more competitor brand workspaces for cross-read.
Clones are draft - this DOES NOT run them; study_run each yourself,
then study_get(study_ids=[source, *clones]). Iterations, participants,
and frames are not copied. Brands (brand_create) and the source must
share a parent workspace.
Each clone is born with an empty placeholder iteration A, surfaced as
placeholder_iteration_ids[<cloned_study_alias>]. Fill it with
study_update_iteration (PATCH the placeholder), NOT study_add_iteration
(which would append a second iteration B and leave A empty). Skipped
clones appear in skipped with a reason - handle before assuming a clean
cohort.
source_study_id: UUID or alias (e.g. s-b2c) of the source study.
brand_ids: list of brand workspace UUIDs / aliases (w-...).
Returns {"cloned": [<Study>, ...], "placeholder_iteration_ids": {<alias>: <iteration_id>}, "skipped": [{"brand_id", "reason", "existing_study_id?"}]}. Reasons: "no_access" or "already_cloned"
(existing_study_id points at the prior clone).
Parameters
UUID or short alias (e.g. ‘w-6ec’, ‘tp-abc’)
study_create
Tier: write · Tags: study, write
Create a study in a workspace. modality picks the artifact kind.
Returns a StudyCreateResponse - study (id / alias / workspace_id /
status all ride on it) plus notes naming the next steps: add content with
study_add_iteration, then dispatch with study_run. To clone for
benchmarking, see study_benchmark. Concept: docs_get("concepts/study").
assignments (the tasks participants attempt) accepts:
- strings or
Assignmentdicts ({name, instructions, test_context?}). Bare strings ≤255 chars become{name, instructions}; longer strings auto-split at the first sentence boundary (name capped at 255, full string → instructions). Use for single-task non-chat andexternal_chatbotchat. Assignmentobjects - required forparticipant_pairchat: two side-tagged rows (side="a"/"b") withname(role),instructions(scenario), optionaltest_context(goal).
Assignment may carry a steps checklist (steps=[AssignmentStep(...)])
- atomic actions an LLM verifier grades per participant, rolled up into
Assignment.step_completiononstudy_get(view='full'). Steps are interactive / external_chatbot-chat only. Seedocs_get("concepts/assignment").
chat_mode (required when modality="chat"): external_chatbot (talk
to a bot endpoint) or participant_pair (AI ↔ AI). For participant_pair
defer iteration creation to study_add_iteration.
Each questions entry becomes a free-text post-sim interview question; for
richer questionnaire shapes refine via study_revise.
See docs_get("concepts/questionnaire").
workspace_id: UUID or alias (e.g. w-6ec) of the workspace.
name: human-readable study name.
modality: interactive | text | video | audio | image | document | chat.
content_type: refines media modalities only (e.g. modality=“video”,
content_type=“ad”); raises a preflight error for interactive / chat.
chat_mode: external_chatbot | participant_pair; required iff modality=“chat”.
assignments: see above.
questions: free-text interview questions.
Parameters
UUID or short alias (e.g. ‘w-6ec’, ‘tp-abc’)
study_delete
Tier: destructive · Tags: delete, study
Permanently delete a study and all its iterations + simulations.
DESTRUCTIVE.
study_id: UUID or alias (e.g. s-b2c) of the study to delete.
Returns {"deleted": True, "study_id": <id>} on success.
Parameters
UUID or short alias (e.g. ‘w-6ec’, ‘tp-abc’)
study_get
Tier: read-only · Tags: read, study
Read studies - browse a workspace’s studies or read one study’s
results. Pass exactly one of workspace_id (browse/list) / study_id
(one study) / study_ids (benchmark cross-read).
Read modes:
workspace_id→ browse: paginated list of every study in that workspace, each row carrying id, alias, name, modality,status/runtime_status, and participant counts - this is how you discover study IDs and inspect what exists (the browse layer for studies, mirroringworkspace_getfor workspaces).view/participant_id/leanignored.study_id→ single-study results, shaped byview:summary(default; counts + sentiment + per-participant rows),full(typedStudy; iterations + flat participant graph, each participant carriesiteration_id),per_participant(one participant’s run; needsparticipant_id),transcripts(chat-only; all transcripts, or one whenparticipant_idset),insights(AI summary +KeyInsightlist fromstudy_analyzeruns;{latest, history}newest-first).study_ids→ benchmark cross-read; list of per-study results in order, each shaped byview(pass source +study_benchmarkclones).
filters=StudyResultsFilter(...) narrows to
matching interactions; group_by reprojects into per-group rollups.
Axes by modality - interactive→frame/step; video/audio/text/document→
segment; chat→turn (side on participant_pair, step on graded
external_chatbot); image→none; iteration/assignment/sentiment
apply to all. Off-modality filters warn via modality_warnings and are
ignored; off-modality group_by hard-errors. Filtered responses carry
totals_unfiltered for coverage checks. See docs_get("guides/slicing-results").
Text-field provenance: summary’s participants[].summary_highlight is
AI-synthesized (not a quote); per_participant’s interactions[].comment
and participant_summary.comment are verbatim persona text. Drill into
per_participant for source quotes.
Navigation / decision trace: per_participant’s interactions[] IS the
step-by-step clickstream - ordered by timestamp, each step carries url
(page URL), location (page/screen template), actions[] (taps / typing
/ scrolls), and screenshot_id (the frame seen at that step). For
interactive studies that is the visited-pages / decision-path record; graded
step outcomes roll up via group_by='step'. Screenshots and transcripts
are also exposed as ish:// resources, with inline screenshots_resource
/ transcripts_resource pointers on the summary view so clients that
can’t read resources still reach them.
study_id: UUID or alias (e.g. s-b2c). Exclusive with the other two.
study_ids: list of UUIDs/aliases for benchmark cross-read. Exclusive.
workspace_id: UUID or alias (e.g. w-6ec). Exclusive.
view: summary (default) | full | per_participant |
transcripts | insights. Ignored in list mode.
participant_id: required for per_participant; optional scope for
transcripts; ignored otherwise.
lean: view="full" only - null iterations AND skip the participants
fetch for a metadata-only payload (also the fix if full times out on a
draft study).
filters: StudyResultsFilter (see that model). Only with study_id +
view in {summary, full}.
group_by: iteration | frame | segment | turn |
assignment | step. Reprojects onto the axis; returns a
SliceResponse. Only with study_id + default view="summary".
Returns PaginatedList[Study] (list), Study (full),
StudyResultsSummary (summary), dict (per_participant),
TranscriptsResponse or ChatTranscript (transcripts),
SliceResponse (group_by set), or a list of these (benchmark). Slice /
transcripts envelopes expose rows on response.rows.
Parameters
Default:
"summary".Default:
false.Default:
50.Default:
0.study_revise
Tier: write · Tags: study, write
Update study-level metadata (name / description / status / modality /
assignments / questions). Only fields you pass change; None leaves a
field untouched, assignments=[] / questions=[] clear the list. Does
NOT touch iterations - study_update_iteration edits an existing iteration,
study_add_iteration appends a new one. Changing modality invalidates
prior runs (rare).
study_id: UUID or alias (e.g. s-b2c) of the study.
name, description, status: study-level fields.
modality: interactive | text | video | audio | image | document | chat.
content_type: media modalities only; omit for interactive / chat.
assignments: as in study_create (strings, or Assignment objects
for test_context / side / steps).
questions: free-text interview questions.
Parameters
UUID or short alias (e.g. ‘w-6ec’, ‘tp-abc’)
study_run
Tier: long-running · Tags: dispatch, study
Run a study: resolve an audience (or reuse an existing panel), create
participants on an iteration if needed, and dispatch the modality-appropriate
simulation batch. Verb choice (study vs ask): docs_get("concepts/run-verbs").
Credit cost: each successfully-completed participant debits the
workspace’s plan credit pool - subscription-funded, so no per-dispatch
approval is needed; pre-flight failures (CSP refusals, NXDOMAIN, chatbot
smoke-test failures, etc.) cost zero and are retryable. Confirm the pool via
workspace_get(...).credits (empty → [insufficient_credits]). Model:
docs_get("reference/credits").
Three modes:
- Materialize + dispatch (default):
audience+dispatch=True. - Stage only:
audience+dispatch=False- creates participants but does NOT dispatch (review checkpoint before drawing credits). Run later withaudience=None. - Reuse panel:
audience=None- dispatches whatever participants already exist on the iteration.
study_id: UUID or alias (e.g. s-b2c) of the study.
iteration_id: UUID or alias (e.g. i-d4e); defaults to the latest.
audience: AudienceFilter (person_ids, or sample=N /
all_matching=True + demographic filters). None reuses the iteration’s
panel. See docs_get("concepts/people").
config_id: simulation-config override (alias c-...). Required for media
and chat studies unless every resolved person has a simulation_config_id.
For participant_pair chat, omitting it auto-infers from the first
group_a person; missing → validation_error. Optional for interactive.
dispatch: see modes above.
max_interactions: per-participant step cap (interactive / media). Defaults
to 20; caps runaway spend on a stuck participant. Ignored for chat. Must be ≥1.
max_turns: per-participant turn cap (chat / chat_pair). Omitted → backend
uses request > iteration’s stored value > 14. Ignored otherwise. Must be ≥1.
wait / timeout: blocking contract - docs_get("reference/long-running-jobs").
wait=True polls every participant to terminal or timeout; default
returns the post-dispatch snapshot with a next_action poll hint.
Caveat - client transport ceiling: many MCP clients cap a single tool
call at ~30s (e.g. Cursor/Replit), and that ceiling overrides timeout:
wait=True, timeout=300 still aborts at the client’s ~30s with no result.
Interactive/media runs take 1-5 min, so they routinely exceed it. Prefer the
default wait=False and poll via the next_action hint; reserve
wait=True for fast jobs or clients with no short transport cap.
Locally-served iterations (platform="code" or a localhost URL) need an
active ish connect tunnel; absent one, fails fast with
error_kind="TunnelInactive". A public but session-gated URL (an
app-builder editor preview - Lovable / Replit / Bolt / v0) passes this check
yet still fails for ish’s cloud testers: point the iteration at a published /
share-preview link, or register a login with site_access_set. See
docs_get("concepts/site-access").
participant_pair chat rejects audience (audiences live in the
iteration’s mode_details).
Returns a RunStudyResponse envelope discriminated by ok. Success →
response.dispatch (SimulationDispatchResult); dispatch=False leaves
it None with participant_ids populated. Failure → error_kind +
error_message; a wait that runs out of budget gives
error_kind="wait_timeout" with participant_ids set so you can resume
via study_get(view="summary").
Parameters
UUID or short alias (e.g. ‘w-6ec’, ‘tp-abc’)
Default:
true.Default:
false.Default:
600.0.study_update_iteration
Tier: write · Tags: study, write
Patch an EXISTING iteration’s content in place (cheap edits: rename,
re-description, partial details patch). For a full re-spec, or to ADD a
new content version, prefer study_add_iteration (its typed signature
guides every modality’s fields); for study-level metadata use study_revise.
details is the modality-specific nested payload; the type
discriminator is required on every shape and must match the iteration’s
modality (omitting it → [validation_error] Unable to extract tag using discriminator 'type'):
- interactive -
{type: "interactive", url, platform, screen_format, ...} - media (video/audio/document) -
{type: "media", content_url, title, ...} - image -
{type: "image", image_urls, title, ...} - text -
{type: "text", content_text, content_html, title, ...} - chat -
{type: "chat", endpoint, chatbot_endpoint_id, max_turns, ...}
study_id: UUID or alias of the parent study (alias hydration only).
iteration_id: UUID or alias (e.g. i-d4e) of the iteration.
details: modality-specific patch (see above).
name, description: iteration-level fields.
Parameters
UUID or short alias (e.g. ‘w-6ec’, ‘tp-abc’)
UUID or short alias (e.g. ‘w-6ec’, ‘tp-abc’)