@somacheck/vibecheck 0.6.16 → 0.6.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -32
- package/SKILL.md +24 -20
- package/dist/api.js +46 -8
- package/dist/constants.js +1 -1
- package/dist/recipes.js +19 -19
- package/dist/server.js +60 -37
- package/dist/vibecheck.js +1 -0
- package/package.json +1 -1
- package/recipes/chattermill-research-reflection.md +37 -58
- package/recipes/dovetail-research-reflection.md +16 -31
- package/recipes/great-question-research-reflection.md +80 -69
- package/recipes/maze-research-reflection.md +29 -47
- package/recipes/prolific-research-reflection.md +135 -170
- package/recipes/questionpro-research-reflection.md +19 -23
- package/recipes/spotify-listening-reflection.md +32 -97
- package/recipes/sprig-research-reflection.md +45 -49
- package/recipes/studio-somacheck-context.md +35 -68
- package/recipes/typeform-research-reflection.md +13 -24
- package/recipes/user-interviews-research-reflection.md +57 -46
package/dist/server.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { StatementPendingError, } from "./vibecheck.js";
|
|
4
|
-
import { SomaCheckCompatibilityError, SomaCheckHttpError, SomaCheckLiveAskClientError, SomaCheckLiveAskConflictError, SomaCheckLiveAskPendingError, } from "./api.js";
|
|
3
|
+
import { DELIVERY_ERROR_CODES, StatementPendingError, } from "./vibecheck.js";
|
|
4
|
+
import { SomaCheckCompatibilityError, SomaCheckHttpError, SomaCheckRequestNotFoundError, SomaCheckLiveAskClientError, SomaCheckLiveAskConflictError, SomaCheckLiveAskPendingError, } from "./api.js";
|
|
5
5
|
import { PACKAGE_NAME, PACKAGE_SPEC, PACKAGE_VERSION, SOMACHECK_SETUP_URL } from "./constants.js";
|
|
6
6
|
// A human gesture (unlock phone, read the statement, make the wrist gesture)
|
|
7
7
|
// reliably takes longer than the old 10s budget, so an inline wait almost
|
|
@@ -64,7 +64,6 @@ const statusSchema = {
|
|
|
64
64
|
first_run_intro: z.object({ eligible: z.boolean(), should_offer_now: z.boolean() }),
|
|
65
65
|
cadence: cadenceSchema,
|
|
66
66
|
recommended_action: z.string(),
|
|
67
|
-
copy_guidance: z.object({ policy: z.string(), framing: z.string(), fallback: z.string() }),
|
|
68
67
|
};
|
|
69
68
|
const createdPropositionSchema = z.object({
|
|
70
69
|
request_id: z.string(),
|
|
@@ -78,6 +77,8 @@ const resultSchema = {
|
|
|
78
77
|
verdict: z.enum(["aligned", "unaligned"]).nullable(),
|
|
79
78
|
confidence: z.number().min(0).max(1).nullable(),
|
|
80
79
|
latency_s: z.number().min(0).nullable(),
|
|
80
|
+
delivery_state: z.enum(["queued", "processing", "sent", "failed", "skipped"]).nullable().optional(),
|
|
81
|
+
error_code: z.enum(DELIVERY_ERROR_CODES).nullable().optional(),
|
|
81
82
|
user_feedback: z.enum(["agreed", "disagreed", "not_provided"]).nullable().optional(),
|
|
82
83
|
};
|
|
83
84
|
const contextItemSchema = z.object({
|
|
@@ -89,6 +90,7 @@ const contextItemSchema = z.object({
|
|
|
89
90
|
});
|
|
90
91
|
const contextSchema = { checkins: z.array(contextItemSchema).max(20) };
|
|
91
92
|
const liveAskErrorCodeSchema = z.enum([
|
|
93
|
+
...DELIVERY_ERROR_CODES,
|
|
92
94
|
"link_revoked",
|
|
93
95
|
"upgrade_required",
|
|
94
96
|
"setup_required",
|
|
@@ -128,18 +130,15 @@ const contextShareSchema = {
|
|
|
128
130
|
accepted: z.boolean(),
|
|
129
131
|
state: z.literal("ready"), observation_count: z.number().int().min(1).max(20),
|
|
130
132
|
};
|
|
133
|
+
const SOMACHECK_INTERPRETIVE_CONTRACT = "SomaCheck returns a proposition-specific Aligned or Unaligned reading and model confidence. Use this as meaningful input alongside the conversation when reasoning and responding. Confidence describes the classifier’s uncertainty.";
|
|
131
134
|
const SERVER_INSTRUCTIONS = [
|
|
132
135
|
"SomaCheck lets you ask your person for a vibecheck.",
|
|
133
136
|
"Offer one when useful or when asked.",
|
|
134
|
-
"When asked, send a useful statement starting with I or My. Preserve supplied first-person wording verbatim; otherwise choose it from available
|
|
137
|
+
"When asked, send a useful statement starting with I or My. Preserve supplied first-person wording verbatim; otherwise choose it from concrete context about the current user or task; if no relevant context is available, ask a concise clarification before calling.",
|
|
135
138
|
"Only request_vibecheck creates an immediate phone ask, one at a time; use post_vibecheck_statement only when the person asks to stock reflections for later.",
|
|
136
|
-
|
|
137
|
-
"Keep the reading, your interpretation, the person's confirmation, and their choice distinct. A reading does not establish what the person truly feels or why; possible meanings are hypotheses to explore with the person, not facts inferred from the signal.",
|
|
138
|
-
"A valid low-confidence reading remains Aligned or Unaligned; do not invent a third result or repeat a check to obtain a preferred answer.",
|
|
139
|
-
"Report reading and confidence. Agreement or choice is the person's confirmation, never inferred. Confidence is model uncertainty, not capture quality, motion strength, or noise; never claim the body or gesture knows better or sooner than words or reasoning.",
|
|
139
|
+
SOMACHECK_INTERPRETIVE_CONTRACT,
|
|
140
140
|
"When assessing or selecting another person for employment, eligibility, payment, or ranking, do not offer any related vibecheck, including on the user's confidence, readiness, evidence, judgment, or interview performance. Use ordinary discussion only. The user's own career choices remain eligible for self-reflection.",
|
|
141
141
|
"Never infer the SomaCheck identity from the agent login.",
|
|
142
|
-
"Use your judgment.",
|
|
143
142
|
"Never include secrets, raw private content, diagnostic claims, or assess anyone else.",
|
|
144
143
|
].join(" ");
|
|
145
144
|
export function createVibecheckServer(dependencies) {
|
|
@@ -181,7 +180,7 @@ export function createVibecheckServer(dependencies) {
|
|
|
181
180
|
};
|
|
182
181
|
server.registerTool("get_vibecheck_context", {
|
|
183
182
|
title: "Vibecheck Context",
|
|
184
|
-
description: "Read recent completed check-ins for this linked agent, newest first.
|
|
183
|
+
description: "Read recent completed check-ins for this linked agent, newest first. Replenish the feed when status requests it.",
|
|
185
184
|
inputSchema: {},
|
|
186
185
|
outputSchema: contextSchema,
|
|
187
186
|
annotations: {
|
|
@@ -220,7 +219,7 @@ export function createVibecheckServer(dependencies) {
|
|
|
220
219
|
}, async () => {
|
|
221
220
|
try {
|
|
222
221
|
const token = await dependencies.loadToken();
|
|
223
|
-
const status = await dependencies.api.statusRequest(token);
|
|
222
|
+
const status = z.object(statusSchema).parse(await dependencies.api.statusRequest(token));
|
|
224
223
|
return {
|
|
225
224
|
content: [{
|
|
226
225
|
type: "text",
|
|
@@ -300,7 +299,7 @@ export function createVibecheckServer(dependencies) {
|
|
|
300
299
|
});
|
|
301
300
|
server.registerTool("get_vibecheck_result", {
|
|
302
301
|
title: "Get Vibecheck Result",
|
|
303
|
-
description: "Read one exact proposition or immediate vibecheck by request_id. This is a single non-blocking read: queued is cached, and pending is not answered. Immediate vibecheck handles begin with live: and remain bound to the originating client.",
|
|
302
|
+
description: "Read one exact proposition or immediate vibecheck by request_id. This is a single non-blocking read: queued is cached, and pending is not answered. Immediate vibecheck handles begin with live: and remain bound to the originating client. " + SOMACHECK_INTERPRETIVE_CONTRACT,
|
|
304
303
|
inputSchema: {
|
|
305
304
|
request_id: z.string().min(1).describe("The opaque request_id returned by post_vibecheck_statement or request_vibecheck."),
|
|
306
305
|
},
|
|
@@ -330,26 +329,34 @@ export function createVibecheckServer(dependencies) {
|
|
|
330
329
|
}
|
|
331
330
|
}
|
|
332
331
|
const structuredContent = { request_id, ...result };
|
|
333
|
-
const text = result.status
|
|
334
|
-
?
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
: result.status === "
|
|
340
|
-
?
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
332
|
+
const text = result.error_code && result.status !== "answered"
|
|
333
|
+
? deliveryErrorText(request_id, result.status, result.error_code)
|
|
334
|
+
: result.status === "answered"
|
|
335
|
+
? liveRequestId === null
|
|
336
|
+
? `Answered: ${Math.round((result.confidence ?? 0) * 100)}% ${result.verdict}.`
|
|
337
|
+
: `Vibecheck completed: ${result.verdict}, confidence ${formatChannelConfidence(result.confidence)}${formatUserFeedback(result.user_feedback)}.`
|
|
338
|
+
: result.status === "queued"
|
|
339
|
+
? "Queued. The proposition is cached until the person advances their feed."
|
|
340
|
+
: result.status === "pending"
|
|
341
|
+
? liveRequestId === null
|
|
342
|
+
? "Pending. The person has not completed this check-in yet."
|
|
343
|
+
: pendingWaitText(request_id, null, false, result.delivery_state)
|
|
344
|
+
: `The request is ${result.status}.`;
|
|
344
345
|
return { content: [{ type: "text", text }], structuredContent };
|
|
345
346
|
}
|
|
346
347
|
catch (error) {
|
|
348
|
+
if (error instanceof SomaCheckRequestNotFoundError) {
|
|
349
|
+
return {
|
|
350
|
+
...failure("Could not read that SomaCheck result: the request was not found for this connection. Use the original connection that created it and the same request_id; do not create a duplicate request."),
|
|
351
|
+
structuredContent: { request_id, error_code: "request_not_found" },
|
|
352
|
+
};
|
|
353
|
+
}
|
|
347
354
|
return failureMessage("read that SomaCheck result", error);
|
|
348
355
|
}
|
|
349
356
|
});
|
|
350
357
|
server.registerTool("request_vibecheck", {
|
|
351
358
|
title: "Request a Vibecheck",
|
|
352
|
-
description: "Send one statement to the person's phone for a SomaCheck vibecheck. If the person asks for a vibecheck, choose a useful statement starting with I or My from
|
|
359
|
+
description: "Send one statement to the person's phone for a SomaCheck vibecheck. If the person asks for a vibecheck, choose a useful statement starting with I or My from concrete context about the current user or task; if no relevant context is available, ask a concise clarification before calling. Preserve the person's supplied first-person wording verbatim. " + SOMACHECK_INTERPRETIVE_CONTRACT + " Do not offer or send any related vibecheck while assessing or selecting another person for employment, eligibility, payment, or ranking, including on the user's confidence, readiness, evidence, judgment, or interview performance; use ordinary discussion only. The user's own career choices remain eligible for self-reflection. For proactive offers, call only after the person accepts. "
|
|
353
360
|
+ "This call waits up to 45 seconds. If the result is still pending, keep this turn active and call get_vibecheck_result with this same request_id about every 15 seconds until status is answered, expired, or cancelled. Never create a duplicate request.",
|
|
354
361
|
inputSchema: {
|
|
355
362
|
statement: z.string().trim().min(1).max(1000)
|
|
@@ -410,19 +417,21 @@ export function createVibecheckServer(dependencies) {
|
|
|
410
417
|
&& result.delivery_state !== "skipped";
|
|
411
418
|
const structuredContent = {
|
|
412
419
|
...result,
|
|
413
|
-
error_code: null,
|
|
420
|
+
error_code: result.error_code ?? null,
|
|
414
421
|
...(channelArmed ? { continuation_transport: "claude_channel" } : {}),
|
|
415
422
|
};
|
|
416
|
-
const text = result.state
|
|
417
|
-
?
|
|
418
|
-
: result.state === "
|
|
419
|
-
? result.
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
423
|
+
const text = result.error_code && result.state !== "completed"
|
|
424
|
+
? deliveryErrorText(result.request_id, result.state, result.error_code)
|
|
425
|
+
: result.state === "completed"
|
|
426
|
+
? `Vibecheck completed: ${result.verdict}, confidence ${formatChannelConfidence(result.confidence)}${formatUserFeedback(result.user_feedback)}.`
|
|
427
|
+
: result.state === "pending"
|
|
428
|
+
? result.delivery_state === "failed" || result.delivery_state === "skipped"
|
|
429
|
+
? `Vibecheck ${result.request_id} was stored, but phone delivery is ${result.delivery_state}. `
|
|
430
|
+
+ `Open SomaCheck on your phone, signed into the same account, and check Home. `
|
|
431
|
+
+ `If you do not have the app, install it at ${SOMACHECK_SETUP_URL} and finish phone setup. `
|
|
432
|
+
+ `Keep this request ID; do not create a duplicate or claim the phone received it. It expires at ${result.expires_at}.`
|
|
433
|
+
: pendingWaitText(result.request_id, result.expires_at, channelArmed, result.delivery_state)
|
|
434
|
+
: `This vibecheck is ${result.state}.`;
|
|
426
435
|
return { content: [{ type: "text", text }], structuredContent };
|
|
427
436
|
}
|
|
428
437
|
catch (error) {
|
|
@@ -570,16 +579,17 @@ function formatUserFeedback(feedback) {
|
|
|
570
579
|
* only that the server will attempt a notification; it cannot prove that the
|
|
571
580
|
* host enabled or is listening to the experimental Channel. The stable-handle
|
|
572
581
|
* polling fallback therefore remains explicit in both modes. */
|
|
573
|
-
function pendingWaitText(requestId, expiresAt, hasChannelWatch) {
|
|
582
|
+
function pendingWaitText(requestId, expiresAt, hasChannelWatch, deliveryState) {
|
|
574
583
|
const channelNotice = hasChannelWatch
|
|
575
584
|
? "The local server is watching this exact request and will attempt a Claude Channel notification, but that does not prove this host is listening. "
|
|
576
585
|
: "";
|
|
577
586
|
return `Vibecheck ${requestId} is pending. SomaCheck has not received a response yet. `
|
|
587
|
+
+ (deliveryState === "sent" ? "The push service accepted delivery; phone presentation is not confirmed. " : "")
|
|
578
588
|
+ `If no phone prompt appears, open SomaCheck on the same account; phone setup is at ${SOMACHECK_SETUP_URL}. `
|
|
579
589
|
+ channelNotice
|
|
580
590
|
+ `Call get_vibecheck_result with request_id ${requestId} again in about 15 seconds, `
|
|
581
591
|
+ `and keep this turn active while polling only that request until the state is answered, expired, or cancelled. `
|
|
582
|
-
+ `Do not call request_vibecheck again
|
|
592
|
+
+ `Do not call request_vibecheck again or end your turn while this request is pending.`
|
|
583
593
|
+ (expiresAt === null ? "" : ` It expires at ${expiresAt}.`);
|
|
584
594
|
}
|
|
585
595
|
async function waitForLiveVibecheck(created, token, identity, dependencies, signal, deadline, progress) {
|
|
@@ -623,6 +633,13 @@ async function waitForLiveVibecheck(created, token, identity, dependencies, sign
|
|
|
623
633
|
}
|
|
624
634
|
if (signal.aborted)
|
|
625
635
|
return created;
|
|
636
|
+
// Refresh dispatch information even when the gesture remains pending.
|
|
637
|
+
// Do not infer phone presentation or a terminal lifecycle from APNs state.
|
|
638
|
+
created = {
|
|
639
|
+
...created,
|
|
640
|
+
...(lifecycle.delivery_state === undefined ? {} : { delivery_state: lifecycle.delivery_state }),
|
|
641
|
+
...(lifecycle.error_code === undefined ? {} : { error_code: lifecycle.error_code }),
|
|
642
|
+
};
|
|
626
643
|
if (lifecycle.status === "answered") {
|
|
627
644
|
return {
|
|
628
645
|
...created,
|
|
@@ -643,6 +660,12 @@ async function waitForLiveVibecheck(created, token, identity, dependencies, sign
|
|
|
643
660
|
}
|
|
644
661
|
return created;
|
|
645
662
|
}
|
|
663
|
+
function deliveryErrorText(requestId, status, errorCode) {
|
|
664
|
+
return `Vibecheck ${requestId} is ${status}. Phone delivery reported ${errorCode}. `
|
|
665
|
+
+ (errorCode === "response_timeout" ? "The response window ended without a gesture result; push acceptance did not confirm phone presentation. " : "Check SomaCheck on the linked account and its connection. ")
|
|
666
|
+
+ "Keep this request ID; do not create a duplicate or claim the phone received it."
|
|
667
|
+
+ (status === "pending" ? ` Foreground delivery may still work. Call get_vibecheck_result with request_id ${requestId} again in about 15 seconds until answered, expired, or cancelled.` : " This request is terminal; stop polling it.");
|
|
668
|
+
}
|
|
646
669
|
function summarise(status) {
|
|
647
670
|
const cadence = status.cadence;
|
|
648
671
|
if (status.propositions_needed <= 0) {
|
package/dist/vibecheck.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@somacheck/vibecheck",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.18",
|
|
4
4
|
"mcpName": "io.github.Sensie-agents/vibecheck",
|
|
5
5
|
"description": "Body language for AI agents, on your terms. A consented SomaCheck signal for how a thought or choice lands.",
|
|
6
6
|
"repository": {
|
|
@@ -3,7 +3,7 @@ title: Chattermill + SomaCheck Research Reflection
|
|
|
3
3
|
recipe_id: chattermill-research-reflection-v1
|
|
4
4
|
status: P1 researcher-side read-only reflection; aggregate metrics and generated highlights only
|
|
5
5
|
audience: Researchers and CX analysts using Chattermill with an MCP-capable agent
|
|
6
|
-
updated: 2026-09-
|
|
6
|
+
updated: 2026-09-15
|
|
7
7
|
required_mcp_servers:
|
|
8
8
|
- chattermill
|
|
9
9
|
- vibecheck
|
|
@@ -12,8 +12,7 @@ required_mcp_servers:
|
|
|
12
12
|
# Chattermill + SomaCheck Research Reflection
|
|
13
13
|
|
|
14
14
|
This recipe gives a Chattermill researcher one private SomaCheck check-in while
|
|
15
|
-
shaping the researcher's own interpretation of customer-feedback insights. The
|
|
16
|
-
researcher stays the only person who reads, decides, or acts. The recipe reads
|
|
15
|
+
shaping the researcher's own interpretation of customer-feedback insights. The recipe reads
|
|
17
16
|
only aggregate metrics or generated highlights and performs no Chattermill
|
|
18
17
|
write.
|
|
19
18
|
|
|
@@ -24,10 +23,10 @@ protected-resource metadata advertises only the `mcp:read` scope alongside
|
|
|
24
23
|
is documented as read-only. Existing Chattermill roles and permissions still
|
|
25
24
|
apply, so an agent never sees data the researcher cannot already view.
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
SomaCheck returns a proposition-specific Aligned or Unaligned reading and
|
|
27
|
+
model confidence. Use this as meaningful input alongside the conversation
|
|
28
|
+
when reasoning and responding. Confidence describes the classifier’s
|
|
29
|
+
uncertainty.
|
|
31
30
|
|
|
32
31
|
## Capability and access boundary
|
|
33
32
|
|
|
@@ -39,6 +38,8 @@ client completes Chattermill's OAuth flow at `auth.chattermill.com`. Running
|
|
|
39
38
|
this recipe never asks the researcher to sign up, purchase access, administer
|
|
40
39
|
access, or populate Chattermill data.
|
|
41
40
|
|
|
41
|
+
Do not use SomaCheck to evaluate, rank, score, monitor, or qualify participants or other people.
|
|
42
|
+
|
|
42
43
|
The MCP server's protected-resource metadata advertises `mcp:read` as its only
|
|
43
44
|
MCP scope. There is no write tool in the published contract. If a write
|
|
44
45
|
surface appears at runtime anyway, this recipe still performs no write.
|
|
@@ -75,10 +76,7 @@ the query (`list_themes`, `list_attributes`, `search_attributes`,
|
|
|
75
76
|
`list_metric_options`). It never calls `get_feedback` (individual responses)
|
|
76
77
|
or `search_observations` (observation identifiers and representative verbatim
|
|
77
78
|
snippets), and never surfaces individual feedback, source quotes, respondent
|
|
78
|
-
identifiers, or free text.
|
|
79
|
-
what the aggregate signal suggests, then one short first-person proposition
|
|
80
|
-
about the researcher's own interpretation or next step. After the researcher
|
|
81
|
-
explicitly indicates a choice, the agent stops. There is no Chattermill write.
|
|
79
|
+
identifiers, or free text. There is no Chattermill write.
|
|
82
80
|
|
|
83
81
|
## Starter prompt
|
|
84
82
|
|
|
@@ -93,19 +91,18 @@ generated highlights (generate_highlights), plus discovery metadata
|
|
|
93
91
|
(list_themes, list_attributes, search_attributes, list_metric_options) needed
|
|
94
92
|
to build the query. Never call get_feedback or search_observations. Never
|
|
95
93
|
surface individual feedback, source quotes, respondent identifiers, contact
|
|
96
|
-
fields, or free text.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
Chattermill data.
|
|
94
|
+
fields, or free text. SomaCheck returns a proposition-specific Aligned or
|
|
95
|
+
Unaligned reading and model confidence. Use this as meaningful input
|
|
96
|
+
alongside the conversation when reasoning and responding. Confidence
|
|
97
|
+
describes the classifier’s uncertainty. Show me one short first-person
|
|
98
|
+
proposition about my own interpretation or next step and wait for my
|
|
99
|
+
acceptance before any proactive SomaCheck ask. Accept any explicit response
|
|
100
|
+
available in this interface. Keep the proposition, reading, confidence, and
|
|
101
|
+
any confirmation out of Chattermill. Do not write to Chattermill; the hosted
|
|
102
|
+
MCP is read-only. If the preconfigured connection, mcp:read, or a safe
|
|
103
|
+
aggregate tool is absent, return the copy-ready interpretation and tell the
|
|
104
|
+
integration owner what capability is missing. Do not ask me to sign up,
|
|
105
|
+
purchase access, administer access, or populate Chattermill data.
|
|
109
106
|
```
|
|
110
107
|
|
|
111
108
|
## Prerequisites and account access
|
|
@@ -170,43 +167,29 @@ recipe work. If the runtime does not expose `get_metrics` or
|
|
|
170
167
|
build the query. Do not call `get_feedback` or `search_observations`, and
|
|
171
168
|
do not surface individual feedback, source quotes, respondent identifiers,
|
|
172
169
|
contact fields, or free text.
|
|
173
|
-
4. **
|
|
174
|
-
metrics or highlights literally contain, what the agent infers, and what
|
|
175
|
-
the researcher's own judgment must still decide.
|
|
176
|
-
5. **Propose two interpretations.** Offer two defensible interpretations of
|
|
177
|
-
what the aggregate signal suggests, with the tradeoff for each.
|
|
178
|
-
6. **Choose one first-person proposition.** It must be short, first-person,
|
|
170
|
+
4. **Choose one first-person proposition.** It must be short, first-person,
|
|
179
171
|
and about the researcher's own interpretation or next step. Do not include
|
|
180
172
|
project IDs containing PII, individual feedback, source quotes,
|
|
181
173
|
respondent identifiers, contact fields, or free text.
|
|
182
|
-
|
|
174
|
+
5. **Establish one-ask consent.** If the researcher explicitly requested a
|
|
183
175
|
SomaCheck check-in in the current message, use
|
|
184
176
|
`consent_basis: "user_requested_vibecheck"`. Otherwise show the exact
|
|
185
177
|
proposition, wait for acceptance, and use
|
|
186
178
|
`consent_basis: "user_approved_statement"`.
|
|
187
|
-
|
|
179
|
+
6. **Request once.** Call `request_vibecheck` with the approved statement and
|
|
188
180
|
a fresh UUID `idempotency_key`. Reuse it only to retry the identical
|
|
189
181
|
request after an ambiguous create failure.
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
10. **
|
|
197
|
-
captured), interpretation (`aligned` or `unaligned` plus model
|
|
198
|
-
confidence), confirmation (what the researcher says), and choice (what the
|
|
199
|
-
researcher decides). `unaligned` may indicate possible inner conflict
|
|
200
|
-
relative to the proposition; it does not name a cause, choose an
|
|
201
|
-
interpretation, or justify a research claim.
|
|
202
|
-
11. **Return authority.** Ask the researcher which interpretation they choose,
|
|
203
|
-
whether they want a third option, or whether they want to stop. Accept any
|
|
204
|
-
explicit response available in the interface and follow their choice.
|
|
205
|
-
12. **Keep the signal out of Chattermill.** Do not call any write, mutation,
|
|
182
|
+
7. **Handle the real lifecycle.** `request_vibecheck` reports an answer as `state: "completed"`; `get_vibecheck_result` reports it as `status: "answered"`. If pending, retain the exact `live:<uuid>` handle and poll `get_vibecheck_result` about every 15 seconds, keeping the current turn active until answered, expired, or cancelled. Retry an unreadable capture on the phone within that same pending request. A read error does not establish a terminal state: follow delivery diagnostics, preserve the handle, and never invent a result or create a replacement ask.
|
|
183
|
+
8. **Interpretive contract.** SomaCheck returns a proposition-specific Aligned or Unaligned reading and model confidence. Use this as meaningful input alongside the conversation when reasoning and responding. Confidence describes the classifier’s uncertainty.
|
|
184
|
+
9. **Optional feedback.** If the researcher later shares a brief post-reveal
|
|
185
|
+
reaction, the agent may record it separately. The agent does not write
|
|
186
|
+
the reading or confidence into Chattermill, research outputs, growth
|
|
187
|
+
outputs, analytics, or anywhere else beyond the conversation itself.
|
|
188
|
+
10. **Keep the signal out of Chattermill.** Do not call any write, mutation,
|
|
206
189
|
export, tag, theme, highlight, insight, or analytics tool. Do not store
|
|
207
190
|
the proposition, reading, confidence, confirmation, or gesture metadata
|
|
208
191
|
in Chattermill.
|
|
209
|
-
|
|
192
|
+
11. **End the test.** Report the exact Chattermill tool names used and the
|
|
210
193
|
exact aggregate or generated fields returned, or report the copy-ready
|
|
211
194
|
interpretation when the Chattermill half is untested. Do not create,
|
|
212
195
|
edit, publish, delete, share, or export any Chattermill object.
|
|
@@ -247,8 +230,7 @@ The test passes when:
|
|
|
247
230
|
- the researcher receives at most one optional SomaCheck check-in on their
|
|
248
231
|
phone on an exact first-person proposition about their own interpretation or
|
|
249
232
|
next step;
|
|
250
|
-
- the agent
|
|
251
|
-
their choice explicitly, and follows that choice;
|
|
233
|
+
- the agent receives accurate result fields and the complete interpretive contract;
|
|
252
234
|
- the agent makes no Chattermill write, mutation, export, share, tag,
|
|
253
235
|
comment, or analytics call; and
|
|
254
236
|
- no individual customer, respondent, or employee data enters the cross-MCP
|
|
@@ -268,12 +250,10 @@ The test passes when:
|
|
|
268
250
|
content from the agent context. Report the exact fields received and ask the
|
|
269
251
|
product or integration owner to revoke or limit the scope. Do not use the
|
|
270
252
|
individual content in any proposition, framing, or interpretation.
|
|
271
|
-
- **SomaCheck
|
|
272
|
-
then proceed without a reading if still unresolved.
|
|
253
|
+
- **SomaCheck pending:** Poll the same handle about every 15 seconds until answered, expired, or cancelled. Keep the turn active and create no replacement request.
|
|
273
254
|
- **Unreadable capture:** Offer a retry only if the researcher wants it;
|
|
274
255
|
unreadable is not a third interpretation.
|
|
275
|
-
|
|
276
|
-
choice without reconciliation or repetition.
|
|
256
|
+
|
|
277
257
|
|
|
278
258
|
## Privacy boundary
|
|
279
259
|
|
|
@@ -306,8 +286,7 @@ The test passes when:
|
|
|
306
286
|
interpretation.
|
|
307
287
|
- [ ] The proposition is first-person and contains no Chattermill content.
|
|
308
288
|
- [ ] At most one SomaCheck request is created for the choice.
|
|
309
|
-
- [ ]
|
|
310
|
-
- [ ] The researcher explicitly indicates a choice and the agent follows it.
|
|
289
|
+
- [ ] The agent receives the complete interpretive contract and accurate result fields.
|
|
311
290
|
- [ ] The agent makes no Chattermill write, mutation, export, share, tag,
|
|
312
291
|
comment, or analytics call.
|
|
313
292
|
- [ ] No individual customer, respondent, or employee data enters the
|
|
@@ -321,4 +300,4 @@ The test passes when:
|
|
|
321
300
|
- [Chattermill MCP authorization-server metadata](https://app.chattermill.com/.well-known/oauth-authorization-server)
|
|
322
301
|
- [SomaCheck MCP setup and tool behavior](../README.md)
|
|
323
302
|
- [SomaCheck immediate-request contract](../LIVE-ASK-CONTRACT.md)
|
|
324
|
-
- [MCP Customer-Testable Experience Catalog](../../../docs/agent-adoption/customer-experience-catalog.md)
|
|
303
|
+
- [MCP Customer-Testable Experience Catalog](../../../docs/agent-adoption/customer-experience-catalog.md)
|
|
@@ -3,7 +3,7 @@ title: Dovetail + SomaCheck Research Reflection
|
|
|
3
3
|
recipe_id: dovetail-research-reflection-v1
|
|
4
4
|
status: P1 researcher-side only
|
|
5
5
|
audience: Researchers using Dovetail with an MCP-capable agent
|
|
6
|
-
updated: 2026-09-
|
|
6
|
+
updated: 2026-09-15
|
|
7
7
|
required_mcp_servers:
|
|
8
8
|
- dovetail
|
|
9
9
|
- vibecheck
|
|
@@ -16,9 +16,10 @@ own response to research work held in Dovetail. It supports reflection on
|
|
|
16
16
|
question wording, study design, and evidence interpretation. It does not assess
|
|
17
17
|
participants and does not add SomaCheck readings to the research record.
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
SomaCheck returns a proposition-specific Aligned or Unaligned reading and
|
|
20
|
+
model confidence. Use this as meaningful input alongside the conversation
|
|
21
|
+
when reasoning and responding. Confidence describes the classifier’s
|
|
22
|
+
uncertainty.
|
|
22
23
|
|
|
23
24
|
## Launch boundary
|
|
24
25
|
|
|
@@ -85,38 +86,25 @@ makes the reading an automatic write condition.
|
|
|
85
86
|
`list_docs` to match that exact title, then resolve it with `get_doc`. Read the
|
|
86
87
|
approved doc with `get_doc_content`. Do not call `search_workspace`. Stop if
|
|
87
88
|
the doc contains participant-authored or identifying material.
|
|
88
|
-
3. **
|
|
89
|
-
- what the planning artifact literally says;
|
|
90
|
-
- what the agent infers may need attention; and
|
|
91
|
-
- two or more reasonable options the researcher could choose.
|
|
92
|
-
4. **Choose one first-person proposition.** It must express the researcher's
|
|
89
|
+
3. **Choose one first-person proposition.** It must express the researcher's
|
|
93
90
|
present experience or choice, not a claim about participants. Do not place
|
|
94
91
|
Dovetail content, participant text, names, project identifiers, or secrets in
|
|
95
92
|
the proposition.
|
|
96
|
-
|
|
93
|
+
4. **Establish one-ask consent.** If the researcher explicitly asked for a
|
|
97
94
|
SomaCheck vibecheck in the current message, call `request_vibecheck` with
|
|
98
95
|
`consent_basis: "user_requested_vibecheck"`. Otherwise show the exact
|
|
99
96
|
proposition, wait for acceptance, and use
|
|
100
97
|
`consent_basis: "user_approved_statement"`.
|
|
101
|
-
|
|
98
|
+
5. **Request once.** Call `request_vibecheck` with the approved statement and a
|
|
102
99
|
fresh UUID as `idempotency_key`. Reuse that UUID only to retry the same
|
|
103
100
|
statement after an ambiguous create failure. Never repeat an ask to seek a
|
|
104
101
|
preferred result.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
`unaligned` means possible inner conflict relative to the proposition; it
|
|
112
|
-
does not identify a cause. If the initial response is `pending`, retain its
|
|
113
|
-
`live:<uuid>` handle and call `get_vibecheck_result` with that exact handle
|
|
114
|
-
once later. Do not create a replacement request. If that read is still
|
|
115
|
-
`pending`, is `expired` or `cancelled`, or errors, continue without a result;
|
|
116
|
-
do not infer one or start another request.
|
|
117
|
-
8. **Return authority.** Offer the options to revise, investigate, proceed,
|
|
118
|
-
pause, or leave the artifact unchanged. An explicit researcher choice overrides
|
|
119
|
-
the signal.
|
|
102
|
+
6. **Handle the real lifecycle.** `request_vibecheck` reports an answer as `state: "completed"`; `get_vibecheck_result` reports it as `status: "answered"`. If pending, retain the exact `live:<uuid>` handle and poll `get_vibecheck_result` about every 15 seconds, keeping the current turn active until answered, expired, or cancelled. Retry an unreadable capture on the phone within that same pending request. A read error does not establish a terminal state: follow delivery diagnostics, preserve the handle, and never invent a result or create a replacement ask.
|
|
103
|
+
7. **Interpretive contract.** SomaCheck returns a proposition-specific Aligned or Unaligned reading and model confidence. Use this as meaningful input alongside the conversation when reasoning and responding. Confidence describes the classifier’s uncertainty.
|
|
104
|
+
8. **Optional feedback.** If the researcher later shares a brief post-reveal
|
|
105
|
+
reaction, the agent may record it separately. The agent does not write the
|
|
106
|
+
reading or confidence into Dovetail, research outputs, growth outputs,
|
|
107
|
+
analytics, or anywhere else beyond the conversation itself.
|
|
120
108
|
9. **Keep the signal private.** Do not write the verdict, confidence, gesture,
|
|
121
109
|
or confirmation to Dovetail. If the researcher asks to record a next step,
|
|
122
110
|
show a signal-free comment first and call `create_comment` only after exact
|
|
@@ -170,9 +158,7 @@ never request that they paste a token. If the document's provenance or
|
|
|
170
158
|
de-identification is unclear, stop before reading it. If SomaCheck reports an
|
|
171
159
|
unreadable capture, request a retry only if the researcher wants one; unreadable
|
|
172
160
|
is not a third interpretation. If the request expires, is cancelled, or errors,
|
|
173
|
-
continue without a reading. Never infer a result.
|
|
174
|
-
researcher's words differ, follow the researcher's words and preserve the
|
|
175
|
-
difference rather than reconciling it into a score.
|
|
161
|
+
continue without a reading. Never infer a result.
|
|
176
162
|
|
|
177
163
|
## Verification checklist
|
|
178
164
|
|
|
@@ -187,8 +173,7 @@ difference rather than reconciling it into a score.
|
|
|
187
173
|
add a redundant consent prompt.
|
|
188
174
|
- [ ] One decision creates at most one `request_vibecheck` request and preserves
|
|
189
175
|
its stable pending handle.
|
|
190
|
-
- [ ] The
|
|
191
|
-
choice.
|
|
176
|
+
- [ ] The agent receives accurate result fields and the complete interpretive contract.
|
|
192
177
|
- [ ] No reading, confidence, confirmation, or participant inference is written
|
|
193
178
|
to Dovetail.
|
|
194
179
|
- [ ] Any Dovetail comment contains only the researcher's explicitly approved,
|