@somacheck/vibecheck 0.4.0 → 0.5.0
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 +20 -15
- package/dist/api.js +48 -1
- package/dist/constants.js +4 -3
- package/dist/readiness.js +4 -3
- package/dist/server.js +48 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,13 +9,13 @@ Your agent has your context. It does not have your gut. This is the bridge.
|
|
|
9
9
|
|
|
10
10
|
Fair. Here is what you need, without executing anything.
|
|
11
11
|
|
|
12
|
-
**What the `link` command does.** `npx -y @somacheck/vibecheck@0.
|
|
12
|
+
**What the `link` command does.** `npx -y @somacheck/vibecheck@0.5.0 link <CODE> --client <CLIENT>`
|
|
13
13
|
exchanges a short-lived pairing code, generated inside the SomaCheck iOS app, for
|
|
14
14
|
a bearer token. It writes that token to `~/.sensie/config.json` with mode `0600`,
|
|
15
15
|
offers to configure supported agent clients found on the computer, and checks the
|
|
16
16
|
connection without printing the token. Setup is not reported ready until the
|
|
17
17
|
selected client has the exact pinned `vibecheck` MCP registration, the backend
|
|
18
|
-
accepts protocol `
|
|
18
|
+
accepts protocol `4` / toolset `vibecheck-0.5`, and both status and context
|
|
19
19
|
probes succeed. It contacts exactly one network host: the Supabase project below.
|
|
20
20
|
|
|
21
21
|
**It will refuse unsafe sandbox linking, on purpose.** `link` checks safety
|
|
@@ -32,13 +32,17 @@ and that its persistent MCP config can be inspected and written. If that preflig
|
|
|
32
32
|
fails, the pairing code is not used. Non-interactive implicit selection,
|
|
33
33
|
`--client all`, and `--client none` are rejected before redemption.
|
|
34
34
|
|
|
35
|
-
**What the server does once running.** It exposes MCP tools that
|
|
36
|
-
statement for the user to test,
|
|
37
|
-
gesture context, and keep a
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
**What is sent.** A
|
|
41
|
-
|
|
35
|
+
**What the server does once running.** It exposes MCP tools that share bounded,
|
|
36
|
+
user-authorized context summaries, create a statement for the user to test,
|
|
37
|
+
read its outcome, recover recent completed gesture context, and keep a
|
|
38
|
+
three-statement feed stocked.
|
|
39
|
+
|
|
40
|
+
**What is sent.** A statement string, bounded derived context observations the
|
|
41
|
+
agent explicitly shares, and a bearer token identifying the link. Tool
|
|
42
|
+
instructions forbid raw conversations, photos, identifiers, and diagnostic
|
|
43
|
+
claims; the backend enforces the bounded capsule shape and rejects
|
|
44
|
+
secret-shaped content. **What is never sent: raw sensor
|
|
45
|
+
data.** The agent receives a verdict
|
|
42
46
|
(`aligned` / `unaligned`) plus a confidence percentage and latency. Model
|
|
43
47
|
abstention is a failed capture, never a third user-facing outcome.
|
|
44
48
|
Accelerometer and gyroscope streams never leave the user's device through this
|
|
@@ -72,9 +76,9 @@ before the pairing code is redeemed.
|
|
|
72
76
|
To configure or repair a client later:
|
|
73
77
|
|
|
74
78
|
```text
|
|
75
|
-
npx -y @somacheck/vibecheck@0.
|
|
76
|
-
npx -y @somacheck/vibecheck@0.
|
|
77
|
-
npx -y @somacheck/vibecheck@0.
|
|
79
|
+
npx -y @somacheck/vibecheck@0.5.0 setup codex
|
|
80
|
+
npx -y @somacheck/vibecheck@0.5.0 setup claude
|
|
81
|
+
npx -y @somacheck/vibecheck@0.5.0 doctor
|
|
78
82
|
```
|
|
79
83
|
|
|
80
84
|
Manual registration remains available:
|
|
@@ -84,13 +88,13 @@ Manual registration remains available:
|
|
|
84
88
|
"mcpServers": {
|
|
85
89
|
"vibecheck": {
|
|
86
90
|
"command": "npx",
|
|
87
|
-
"args": ["-y", "@somacheck/vibecheck@0.
|
|
91
|
+
"args": ["-y", "@somacheck/vibecheck@0.5.0", "serve", "--client", "codex"]
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
94
|
}
|
|
91
95
|
```
|
|
92
96
|
|
|
93
|
-
For Claude Code: `claude mcp add --scope user vibecheck -- npx -y @somacheck/vibecheck@0.
|
|
97
|
+
For Claude Code: `claude mcp add --scope user vibecheck -- npx -y @somacheck/vibecheck@0.5.0 serve --client claude`
|
|
94
98
|
|
|
95
99
|
The link step writes only the bearer token in `~/.sensie/config.json`. The client
|
|
96
100
|
setup step asks Codex or Claude to add the pinned MCP command to that client's own
|
|
@@ -98,7 +102,7 @@ configuration; it never copies the bearer token there. The interactive command
|
|
|
98
102
|
completes both steps. Most clients only pick up a new server after restart.
|
|
99
103
|
|
|
100
104
|
If `doctor` reports another MCP server named `somacheck`, that is the legacy
|
|
101
|
-
hosted connector and is
|
|
105
|
+
hosted connector and is separate from this local package. The setup command
|
|
102
106
|
will explain it and leave it alone. The canonical local MCP key is `vibecheck`.
|
|
103
107
|
|
|
104
108
|
## Tools
|
|
@@ -107,6 +111,7 @@ will explain it and leave it alone. The canonical local MCP key is `vibecheck`.
|
|
|
107
111
|
|---|---|
|
|
108
112
|
| `get_vibecheck_context` | Read recent completed gestures for this exact agent link without retaining every `request_id`. |
|
|
109
113
|
| `get_vibecheck_status` | Read the live three-proposition cache and how many distinct insights it needs. |
|
|
114
|
+
| `share_somacheck_context` | Share 1–20 bounded, derived, user-authorized observations; raw conversations and secrets are rejected. |
|
|
110
115
|
| `post_vibecheck_statement` | Add one to three personalized statements without blocking; returns a stable `request_id` for each. |
|
|
111
116
|
| `get_vibecheck_result` | Read that exact proposition once by `request_id`; returns queued, pending, or its terminal result. |
|
|
112
117
|
|
package/dist/api.js
CHANGED
|
@@ -10,6 +10,16 @@ const HANDSHAKE_READINESS_STATUSES = new Set([
|
|
|
10
10
|
"setup_incomplete",
|
|
11
11
|
"health_check_failed",
|
|
12
12
|
]);
|
|
13
|
+
const CONTEXT_CATEGORY = {
|
|
14
|
+
goal: "goals_projects", project: "goals_projects",
|
|
15
|
+
decision: "decisions_commitments", commitment: "decisions_commitments",
|
|
16
|
+
tension: "tensions_questions_blind_spots", question: "tensions_questions_blind_spots",
|
|
17
|
+
blindSpot: "tensions_questions_blind_spots",
|
|
18
|
+
relationship: "relationships_situational", situation: "relationships_situational",
|
|
19
|
+
change: "changes_deadlines_developments", deadline: "changes_deadlines_developments",
|
|
20
|
+
development: "changes_deadlines_developments", moodTheme: "emotional_mood_themes",
|
|
21
|
+
preference: "corrections_dismissals_saves_preferences",
|
|
22
|
+
};
|
|
13
23
|
export class SomaCheckHttpError extends Error {
|
|
14
24
|
status;
|
|
15
25
|
constructor(status) {
|
|
@@ -220,6 +230,24 @@ function parseHandshake(row) {
|
|
|
220
230
|
}
|
|
221
231
|
return result;
|
|
222
232
|
}
|
|
233
|
+
export function decodeAgentContextShare(value) {
|
|
234
|
+
const row = firstRow(value);
|
|
235
|
+
const state = requiredString(row, "state");
|
|
236
|
+
if (state !== "ready")
|
|
237
|
+
throw new Error("SomaCheck returned an invalid context state.");
|
|
238
|
+
const observationCount = requiredInteger(row, "observation_count");
|
|
239
|
+
if (observationCount < 1 || observationCount > 20) {
|
|
240
|
+
throw new Error("SomaCheck returned an invalid observation count.");
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
source_id: requiredString(row, "source_id"),
|
|
244
|
+
entry_id: requiredString(row, "entry_id"),
|
|
245
|
+
accepted: requiredBoolean(row, "accepted"),
|
|
246
|
+
state,
|
|
247
|
+
observation_count: observationCount,
|
|
248
|
+
captured_at: requiredTimestamp(row, "captured_at"),
|
|
249
|
+
};
|
|
250
|
+
}
|
|
223
251
|
export class SupabaseAgentApi {
|
|
224
252
|
#endpoint;
|
|
225
253
|
#apiKey;
|
|
@@ -245,8 +273,27 @@ export class SupabaseAgentApi {
|
|
|
245
273
|
async contextRequest(token, limit = 20) {
|
|
246
274
|
return decodeVibecheckContext(await this.#rpcJson("agent_proposition_context", { token, p_limit: limit }));
|
|
247
275
|
}
|
|
276
|
+
async shareContext(token, observations) {
|
|
277
|
+
const capturedAt = new Date().toISOString();
|
|
278
|
+
const payload = {};
|
|
279
|
+
for (const observation of observations) {
|
|
280
|
+
const category = CONTEXT_CATEGORY[observation.type];
|
|
281
|
+
(payload[category] ??= []).push({
|
|
282
|
+
type: observation.type,
|
|
283
|
+
summary: observation.summary.trim(),
|
|
284
|
+
confidence: observation.confidence,
|
|
285
|
+
evidence_count: observation.evidence_count,
|
|
286
|
+
captured_at: capturedAt,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
return decodeAgentContextShare(await this.#rpcJson("agent_context_capsule_share", {
|
|
290
|
+
token,
|
|
291
|
+
p_payload: payload,
|
|
292
|
+
p_confidence: observations.reduce((sum, item) => sum + item.confidence, 0) / observations.length,
|
|
293
|
+
}));
|
|
294
|
+
}
|
|
248
295
|
async clientHandshake(token, input) {
|
|
249
|
-
const row = await this.#rpc("
|
|
296
|
+
const row = await this.#rpc("agent_client_handshake_v2", {
|
|
250
297
|
token,
|
|
251
298
|
p_client_key: input.client_key,
|
|
252
299
|
p_client_label: input.client_label,
|
package/dist/constants.js
CHANGED
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
export const SUPABASE_URL = "https://pbldcmniommltbdwuykk.supabase.co";
|
|
3
3
|
export const SUPABASE_PUBLISHABLE_KEY = "sb_publishable_af-lUNI2FqEcb-oGy-4uxQ_cnm6kY85";
|
|
4
4
|
export const PACKAGE_NAME = "@somacheck/vibecheck";
|
|
5
|
-
export const PACKAGE_VERSION = "0.
|
|
5
|
+
export const PACKAGE_VERSION = "0.5.0";
|
|
6
6
|
export const PACKAGE_SPEC = `${PACKAGE_NAME}@${PACKAGE_VERSION}`;
|
|
7
7
|
export const MCP_SERVER_NAME = "vibecheck";
|
|
8
8
|
export const LEGACY_HOSTED_MCP_SERVER_NAME = "somacheck";
|
|
9
|
-
export const BACKEND_PROTOCOL_VERSION =
|
|
10
|
-
export const TOOLSET_VERSION = "vibecheck-0.
|
|
9
|
+
export const BACKEND_PROTOCOL_VERSION = 4;
|
|
10
|
+
export const TOOLSET_VERSION = "vibecheck-0.5";
|
|
11
11
|
export const TOOL_NAMES = [
|
|
12
12
|
"get_vibecheck_context",
|
|
13
13
|
"get_vibecheck_status",
|
|
14
|
+
"share_somacheck_context",
|
|
14
15
|
"post_vibecheck_statement",
|
|
15
16
|
"get_vibecheck_result",
|
|
16
17
|
];
|
package/dist/readiness.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readConfig } from "./config.js";
|
|
2
2
|
import { SomaCheckCompatibilityError, SomaCheckHttpError } from "./api.js";
|
|
3
3
|
import { clientDisplayName, clientRegistrationState, detectLegacyHostedRegistration, isClientInstalled, manualLegacyHostedRemoveCommand, manualRemoveCommand, manualSetupCommand, } from "./client-setup.js";
|
|
4
|
+
import { BACKEND_PROTOCOL_VERSION, PACKAGE_VERSION } from "./constants.js";
|
|
4
5
|
export async function checkReadiness(dependencies) {
|
|
5
6
|
let token;
|
|
6
7
|
try {
|
|
@@ -62,7 +63,7 @@ export async function checkReadiness(dependencies) {
|
|
|
62
63
|
? " It currently reports: Needs authentication."
|
|
63
64
|
: "";
|
|
64
65
|
dependencies.output(`○ ${clientDisplayName(client)} also has a separate legacy server named "somacheck".${authNote}`);
|
|
65
|
-
dependencies.output(
|
|
66
|
+
dependencies.output(` SomaCheck MCP ${PACKAGE_VERSION} uses "vibecheck"; the legacy entry was not changed.`);
|
|
66
67
|
dependencies.output(` Optional manual cleanup: ${manualLegacyHostedRemoveCommand(client)}`);
|
|
67
68
|
}
|
|
68
69
|
const registration = await clientRegistrationState(client, dependencies.runner);
|
|
@@ -81,7 +82,7 @@ export async function checkReadiness(dependencies) {
|
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
if (registeredClients.length === 0) {
|
|
84
|
-
dependencies.output(
|
|
85
|
+
dependencies.output(`✗ No supported agent client has the current SomaCheck ${PACKAGE_VERSION} configuration.`);
|
|
85
86
|
if (installedClientCount === 0) {
|
|
86
87
|
dependencies.output(" Install Codex or Claude Code, then run the matching setup command.");
|
|
87
88
|
}
|
|
@@ -101,7 +102,7 @@ export async function checkReadiness(dependencies) {
|
|
|
101
102
|
if (handshake.readiness_status === "ready") {
|
|
102
103
|
backendCompatible = true;
|
|
103
104
|
readyClients.push(client);
|
|
104
|
-
dependencies.output(`✓ ${clientDisplayName(client)} completed the SomaCheck protocol
|
|
105
|
+
dependencies.output(`✓ ${clientDisplayName(client)} completed the SomaCheck protocol-${BACKEND_PROTOCOL_VERSION} health check.`);
|
|
105
106
|
}
|
|
106
107
|
else {
|
|
107
108
|
dependencies.output(`✗ ${clientDisplayName(client)} is not ready yet (${handshake.readiness_status}).`);
|
package/dist/server.js
CHANGED
|
@@ -48,10 +48,29 @@ const contextItemSchema = z.object({
|
|
|
48
48
|
answered_at: z.string().datetime({ offset: true }),
|
|
49
49
|
});
|
|
50
50
|
const contextSchema = { checkins: z.array(contextItemSchema) };
|
|
51
|
+
const agentContextTypeSchema = z.enum([
|
|
52
|
+
"goal", "project", "decision", "commitment", "tension", "question",
|
|
53
|
+
"blindSpot", "relationship", "situation", "change", "deadline",
|
|
54
|
+
"development", "moodTheme", "preference",
|
|
55
|
+
]);
|
|
56
|
+
const agentContextObservationSchema = z.object({
|
|
57
|
+
type: agentContextTypeSchema,
|
|
58
|
+
summary: z.string().trim().min(1).max(500)
|
|
59
|
+
.describe("A concise derived theme or fact the person authorized you to share. Never paste raw conversations."),
|
|
60
|
+
confidence: z.number().min(0).max(1).default(0.8),
|
|
61
|
+
evidence_count: z.number().int().min(1).max(100).default(1),
|
|
62
|
+
});
|
|
63
|
+
const contextShareSchema = {
|
|
64
|
+
source_id: z.string(), entry_id: z.string(), accepted: z.boolean(),
|
|
65
|
+
state: z.literal("ready"), observation_count: z.number().int().min(1).max(20),
|
|
66
|
+
captured_at: z.string().datetime({ offset: true }),
|
|
67
|
+
};
|
|
51
68
|
const SERVER_INSTRUCTIONS = [
|
|
52
69
|
"SomaCheck lets you offer the person a statement to test through a quick phone check-in.",
|
|
53
70
|
"Call get_vibecheck_context and get_vibecheck_status at the start of a session or background run, and call status again after a completed check-in.",
|
|
54
71
|
"Treat gesture outcomes as contextual signals, never fixed facts or blanket authorization.",
|
|
72
|
+
"When you have meaningful user-authorized context, call share_somacheck_context with concise derived observations before creating propositions.",
|
|
73
|
+
"Never share raw conversation text, photos, credentials, private identifiers, or diagnostic claims.",
|
|
55
74
|
"Maintain three distinct propositions drawn from your own context about this person.",
|
|
56
75
|
"When propositions_needed is greater than zero, post exactly that many in one call.",
|
|
57
76
|
"Offer each statement as something to test, never as a claim of fact about the user.",
|
|
@@ -111,6 +130,32 @@ export function createVibecheckServer(dependencies) {
|
|
|
111
130
|
return failureMessage("read SomaCheck status", error);
|
|
112
131
|
}
|
|
113
132
|
});
|
|
133
|
+
server.registerTool("share_somacheck_context", {
|
|
134
|
+
title: "Share SomaCheck Context",
|
|
135
|
+
description: "Share 1-20 concise, user-authorized context observations so SomaCheck can prepare richer propositions. Send derived summaries only—never raw conversation text, photos, credentials, identifiers, or diagnostic claims.",
|
|
136
|
+
inputSchema: {
|
|
137
|
+
observations: z.array(agentContextObservationSchema).min(1).max(20),
|
|
138
|
+
},
|
|
139
|
+
outputSchema: contextShareSchema,
|
|
140
|
+
annotations: {
|
|
141
|
+
readOnlyHint: false,
|
|
142
|
+
destructiveHint: false,
|
|
143
|
+
idempotentHint: true,
|
|
144
|
+
openWorldHint: false,
|
|
145
|
+
},
|
|
146
|
+
}, async ({ observations }) => {
|
|
147
|
+
try {
|
|
148
|
+
const token = await dependencies.loadToken();
|
|
149
|
+
const result = await dependencies.api.shareContext(token, observations);
|
|
150
|
+
return {
|
|
151
|
+
content: [{ type: "text", text: `Shared ${result.observation_count} bounded context observation${result.observation_count === 1 ? "" : "s"}. SomaCheck can now prepare contextual propositions.` }],
|
|
152
|
+
structuredContent: { ...result },
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
return failureMessage("share context with SomaCheck", error);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
114
159
|
server.registerTool("post_vibecheck_statement", {
|
|
115
160
|
title: "Post Vibecheck Statement",
|
|
116
161
|
description: "Fill the person's SomaCheck cache with one to three personalized statements and return immediately. Call get_vibecheck_status first and submit exactly propositions_needed statements.",
|
|
@@ -208,6 +253,9 @@ function operationalFailureText(operation, error) {
|
|
|
208
253
|
}
|
|
209
254
|
if (error instanceof SomaCheckHttpError) {
|
|
210
255
|
if (error.status === 401 || error.status === 403) {
|
|
256
|
+
if (operation === "share context with SomaCheck") {
|
|
257
|
+
return `Could not ${operation}: context is not enabled for this link, or the link was rejected or revoked. Open SomaCheck → Connect context, then retry. ${doctor}`;
|
|
258
|
+
}
|
|
211
259
|
return `Could not ${operation}: this SomaCheck link was rejected or revoked. Reconnect in the app. ${doctor}`;
|
|
212
260
|
}
|
|
213
261
|
if (error.status === 404) {
|