@botiverse/raft-daemon 0.70.3 → 0.71.1

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.
@@ -1462,6 +1462,7 @@ var TRACE_B0_FIELD_DEFINITIONS = defineTraceFields([
1462
1462
  { key: "error_class", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
1463
1463
  { key: "query_name", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "query_registry" },
1464
1464
  { key: "phase", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
1465
+ { key: "eligibility_subcheck", fieldClass: "query_axis", placement: "event", valueKind: "closed_enum", enumBinding: "pending_457" },
1465
1466
  { key: "hint_source", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
1466
1467
  { key: "resolved_activity", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
1467
1468
  { key: "previous_activity", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
@@ -1999,6 +2000,12 @@ var actionCardActionSchema = z.discriminatedUnion("type", [
1999
2000
 
2000
2001
  // ../shared/src/agentApiContract.ts
2001
2002
  import { z as z2 } from "zod";
2003
+
2004
+ // ../shared/src/attentionDependencyOracle.ts
2005
+ var ATTENTION_HINT_SCHEMA = "attention-dependency-hint.v1";
2006
+ var ATTENTION_HINT_DEFAULT_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
2007
+
2008
+ // ../shared/src/agentApiContract.ts
2002
2009
  var AGENT_API_BASE_PATH = "/internal/agent-api";
2003
2010
  var optionalStringSchema = z2.string().trim().optional();
2004
2011
  var optionalStringArraySchema = z2.array(z2.string().trim().min(1)).optional();
@@ -2040,6 +2047,24 @@ var agentApiKnowledgeGetResponseSchema = passthroughObject({
2040
2047
  contentType: z2.string(),
2041
2048
  content: z2.string()
2042
2049
  });
2050
+ var agentApiKnowledgeSearchQuerySchema = passthroughObject({
2051
+ query: z2.string().trim().min(1),
2052
+ scope: optionalStringSchema,
2053
+ reason: optionalStringSchema,
2054
+ turn_id: optionalStringSchema,
2055
+ trace_id: optionalStringSchema
2056
+ });
2057
+ var agentApiKnowledgeSearchResultSchema = passthroughObject({
2058
+ slug: z2.string(),
2059
+ title: z2.string(),
2060
+ firstScreen: z2.string()
2061
+ });
2062
+ var agentApiKnowledgeSearchResponseSchema = passthroughObject({
2063
+ ok: z2.literal(true),
2064
+ query: z2.string(),
2065
+ scope: z2.string().nullable(),
2066
+ results: z2.array(agentApiKnowledgeSearchResultSchema)
2067
+ });
2043
2068
  var agentApiMessageSearchQuerySchema = passthroughObject({
2044
2069
  q: optionalStringSchema,
2045
2070
  channel: optionalStringSchema,
@@ -2491,7 +2516,14 @@ var agentApiSendSentResponseSchema = passthroughObject({
2491
2516
  messageId: z2.string(),
2492
2517
  messageSeq: optionalNumberSchema,
2493
2518
  recentUnread: z2.array(agentApiMessageEnvelopeSchema).optional(),
2494
- pendingMentionActions: z2.array(agentApiMessageEnvelopeSchema).optional()
2519
+ pendingMentionActions: z2.array(agentApiMessageEnvelopeSchema).optional(),
2520
+ attention: passthroughObject({
2521
+ driveByJoinedToPost: passthroughObject({
2522
+ reason: optionalStringSchema,
2523
+ muteCommand: optionalStringSchema,
2524
+ stillArrives: optionalStringArraySchema
2525
+ }).optional()
2526
+ }).optional()
2495
2527
  });
2496
2528
  var agentApiSendResponseSchema = z2.discriminatedUnion("state", [
2497
2529
  agentApiSendSentResponseSchema,
@@ -2500,8 +2532,17 @@ var agentApiSendResponseSchema = z2.discriminatedUnion("state", [
2500
2532
  var agentApiMessageResolveResponseSchema = passthroughObject({
2501
2533
  message: agentApiMessageEnvelopeSchema
2502
2534
  });
2535
+ var agentApiChannelAttentionSchema = passthroughObject({
2536
+ state: optionalStringSchema,
2537
+ ordinaryActivity: optionalStringSchema,
2538
+ stillArrives: optionalStringArraySchema,
2539
+ threadBoundary: optionalStringSchema,
2540
+ manageCommand: optionalStringSchema,
2541
+ manageApi: optionalStringSchema
2542
+ });
2503
2543
  var agentApiOkResponseSchema = passthroughObject({
2504
- ok: z2.literal(true)
2544
+ ok: z2.literal(true),
2545
+ attention: agentApiChannelAttentionSchema.optional()
2505
2546
  });
2506
2547
  var agentApiSearchResultSchema = passthroughObject({
2507
2548
  id: z2.string(),
@@ -2558,6 +2599,16 @@ var agentApiChannelMuteResponseSchema = passthroughObject({
2558
2599
  catchUp: optionalStringSchema
2559
2600
  }).optional()
2560
2601
  });
2602
+ var agentApiChannelMuteBodySchema = passthroughObject({
2603
+ attentionHintAccepted: passthroughObject({
2604
+ schema: z2.literal(ATTENTION_HINT_SCHEMA),
2605
+ trigger: z2.enum(["M2", "M3"]),
2606
+ scope: z2.string().trim().min(1),
2607
+ suggested_command: optionalStringSchema,
2608
+ copy_version: z2.string().trim().min(1),
2609
+ epoch_ms: z2.number().int().nonnegative()
2610
+ }).optional()
2611
+ });
2561
2612
  var agentApiTaskClaimResultSchema = passthroughObject({
2562
2613
  taskNumber: z2.number().int().positive().optional(),
2563
2614
  messageId: optionalStringSchema,
@@ -2680,6 +2731,16 @@ var agentApiContract = {
2680
2731
  request: { query: agentApiKnowledgeGetQuerySchema },
2681
2732
  response: { body: agentApiKnowledgeGetResponseSchema }
2682
2733
  }),
2734
+ knowledgeSearch: route({
2735
+ key: "knowledgeSearch",
2736
+ method: "GET",
2737
+ path: "/knowledge/search",
2738
+ client: { resource: "knowledge", method: "search" },
2739
+ capability: "knowledge",
2740
+ description: "Search Slock Manual for Agents topics from the current server.",
2741
+ request: { query: agentApiKnowledgeSearchQuerySchema },
2742
+ response: { body: agentApiKnowledgeSearchResponseSchema }
2743
+ }),
2683
2744
  messageSend: route({
2684
2745
  key: "messageSend",
2685
2746
  method: "POST",
@@ -2757,7 +2818,7 @@ var agentApiContract = {
2757
2818
  client: { resource: "channels", method: "mute" },
2758
2819
  capability: "channels",
2759
2820
  description: "Mute ordinary activity delivery for a visible regular channel as the bound agent credential.",
2760
- request: { params: agentApiChannelMembershipParamsSchema },
2821
+ request: { params: agentApiChannelMembershipParamsSchema, body: agentApiChannelMuteBodySchema },
2761
2822
  response: { body: agentApiChannelMuteResponseSchema }
2762
2823
  }),
2763
2824
  channelUnmute: route({
@@ -3067,6 +3128,20 @@ var optionalQueryIntSchema = z3.union([z3.number().int().nonnegative(), z3.strin
3067
3128
  var nullableNumberSchema2 = z3.number().finite().nullable();
3068
3129
  var passthroughObject2 = (shape) => z3.object(shape).passthrough();
3069
3130
  var daemonApiInboxFlagSchema = z3.enum(["mention", "thread", "dm", "task"]);
3131
+ var daemonApiAttentionHintSchema = passthroughObject2({
3132
+ schema: z3.literal(ATTENTION_HINT_SCHEMA),
3133
+ trigger: z3.enum(["M2", "M3"]),
3134
+ scope: z3.string().trim().min(1),
3135
+ suggested_command: z3.string().trim().min(1),
3136
+ copy: z3.string().trim().min(1),
3137
+ copy_version: z3.literal("attention-hint-copy-v1"),
3138
+ epoch_ms: z3.number().int().nonnegative(),
3139
+ thresholds: passthroughObject2({
3140
+ K: optionalNonNegativeIntSchema,
3141
+ k: optionalNonNegativeIntSchema,
3142
+ window_ms: z3.number().int().positive()
3143
+ })
3144
+ });
3070
3145
  var daemonApiInboxTargetRowSchema = passthroughObject2({
3071
3146
  target: z3.string().trim().min(1),
3072
3147
  channelId: optionalStringSchema2,
@@ -3077,8 +3152,9 @@ var daemonApiInboxTargetRowSchema = passthroughObject2({
3077
3152
  latestMsgId: optionalStringSchema2,
3078
3153
  latestSeq: optionalNonNegativeIntSchema,
3079
3154
  latestSenderName: optionalStringSchema2,
3080
- latestSenderType: z3.enum(["human", "agent", "system"]).optional(),
3081
- flags: z3.array(daemonApiInboxFlagSchema)
3155
+ latestSenderType: z3.enum(["human", "agent", "system", "third_party_app"]).optional(),
3156
+ flags: z3.array(daemonApiInboxFlagSchema),
3157
+ attentionHint: daemonApiAttentionHintSchema.optional()
3082
3158
  });
3083
3159
  var daemonApiInboxCheckResponseSchema = passthroughObject2({
3084
3160
  rows: z3.array(daemonApiInboxTargetRowSchema).optional()
@@ -3101,6 +3177,7 @@ var daemonApiWakeHintSchema = passthroughObject2({
3101
3177
  target_type: optionalStringSchema2,
3102
3178
  reason: optionalStringSchema2,
3103
3179
  wake_reason: optionalStringSchema2,
3180
+ attention_hint: daemonApiAttentionHintSchema.optional(),
3104
3181
  createdAt: optionalStringSchema2,
3105
3182
  created_at: optionalStringSchema2
3106
3183
  });
@@ -3187,6 +3264,7 @@ function formatAgentInboxRowDetails(row) {
3187
3264
  if (row.latestSenderName) parts.push(`latest sender @${row.latestSenderName}`);
3188
3265
  if (row.latestMsgId) parts.push(`latest msg=${shortMessageId(row.latestMsgId)}`);
3189
3266
  parts.push(...row.flags.map(formatAgentInboxFlag));
3267
+ if (row.attentionHint) parts.push(`attention_hint=${formatAttentionHintField(row.attentionHint)}`);
3190
3268
  return parts.join(" \xB7 ");
3191
3269
  }
3192
3270
  function formatAgentInboxFlag(flag) {
@@ -3196,6 +3274,18 @@ function formatAgentInboxFlag(flag) {
3196
3274
  function shortMessageId(value) {
3197
3275
  return value.slice(0, 8);
3198
3276
  }
3277
+ function formatAttentionHintField(hint) {
3278
+ return JSON.stringify({
3279
+ schema: hint.schema,
3280
+ trigger: hint.trigger,
3281
+ scope: hint.scope,
3282
+ suggested_command: hint.suggested_command,
3283
+ copy: hint.copy,
3284
+ copy_version: hint.copy_version,
3285
+ epoch_ms: hint.epoch_ms,
3286
+ thresholds: hint.thresholds
3287
+ });
3288
+ }
3199
3289
 
3200
3290
  // ../shared/src/externalAgentIntegration.ts
3201
3291
  import { z as z4 } from "zod";
@@ -3538,9 +3628,9 @@ var EXTERNAL_AGENT_RUNTIME_ID = "external";
3538
3628
  var EXTERNAL_AGENT_RUNTIME_MODEL = "external";
3539
3629
  var EXTERNAL_AGENT_RUNTIME_DISPLAY_NAME = "External agent";
3540
3630
  var RUNTIMES = [
3541
- { id: "builtin", displayName: "Built-in", binary: "", supported: true },
3542
3631
  { id: "claude", displayName: "Claude Code", binary: "claude", supported: true },
3543
3632
  { id: "codex", displayName: "Codex CLI", binary: "codex", supported: true },
3633
+ { id: "builtin", displayName: "Builtin Pi", binary: "", supported: true },
3544
3634
  { id: "antigravity", displayName: "Antigravity CLI", binary: "agy", supported: true },
3545
3635
  // Kimi: prefer the in-process SDK (`kimi-sdk` → "Kimi Code") for new agents.
3546
3636
  // The legacy `kimi` (kimi-cli child-process) entry stays for backward compat
@@ -5833,6 +5923,7 @@ function projectBucket(target, messages) {
5833
5923
  if (message.task_number || message.task_status) flags.add("task");
5834
5924
  if (message.mentioned === true) flags.add("mention");
5835
5925
  }
5926
+ const attentionHint = [...sorted].reverse().find((message) => message.attention_hint)?.attention_hint;
5836
5927
  return stripUndefined({
5837
5928
  target,
5838
5929
  channelId: latest.channel_id ?? latest.parent_channel_id,
@@ -5844,7 +5935,8 @@ function projectBucket(target, messages) {
5844
5935
  latestSeq: messageSeq2(latest),
5845
5936
  latestSenderName: latest.sender_name ?? latest.senderName,
5846
5937
  latestSenderType: normalizeSenderType(latest.sender_type ?? latest.senderType),
5847
- flags: [...flags].sort()
5938
+ flags: [...flags].sort(),
5939
+ attentionHint
5848
5940
  });
5849
5941
  }
5850
5942
  function compareInboxMessages(a, b) {
@@ -13911,7 +14003,7 @@ Do not imply you have already created agents or channels unless the action has a
13911
14003
  ### Capability Boundary Pivot
13912
14004
  If the user's primary request is outside current capabilities, acknowledge the limitation once and pivot immediately to the nearest useful alternative.
13913
14005
  Do not repeat that something is impossible across multiple turns.
13914
- Offer a concrete substitute: a manual input path, a narrower analysis task, an agent/team setup, or another workflow Slock can execute now.
14006
+ Offer a concrete substitute: a manual input path, a narrower analysis task, an agent/team setup, or another workflow Raft can execute now.
13915
14007
 
13916
14008
  ### Active-Elsewhere Handoff
13917
14009
  Channel silence is not failure.
@@ -13962,7 +14054,7 @@ The reminder must reference the user's goal, agent, recent step, or suggested ne
13962
14054
  - Optimize for first useful collaboration action.
13963
14055
  - Keep answers concise by default; expand only when the user asks.
13964
14056
  - Never copy FAQ text verbatim; synthesize and personalize.
13965
- - If user asks for team support or wants to raise a request, direct them to email cindy@slock.ai.
14057
+ - If user asks for team support or wants to raise a request, direct them to email cindy@raft.build.
13966
14058
  - When multiple agents are involved, reduce noise and collisions by steering work into explicit task ownership.
13967
14059
  `;
13968
14060
  }
@@ -13975,8 +14067,8 @@ Do not copy these answers verbatim.
13975
14067
 
13976
14068
  ## FAQ 1: What are you? What can you do?
13977
14069
  ### Answer idea
13978
- - You are Cindy, onboarding lead for practical setup.
13979
- - Slock enables persistent specialized agents collaborating in channels/threads.
14070
+ - You are Cindy, the Raft onboarding partner for practical setup.
14071
+ - Raft enables persistent specialized agents collaborating in channels/threads.
13980
14072
 
13981
14073
  ### Next step
13982
14074
  - Ask what the user is working on and map to setup.
@@ -14116,9 +14208,9 @@ Do not copy these answers verbatim.
14116
14208
  ### Guardrail
14117
14209
  - Agents complement documentation; they do not replace all records.
14118
14210
 
14119
- ## FAQ 13: How to contact Slock team for support or requests?
14211
+ ## FAQ 13: How to contact the Raft team for support or requests?
14120
14212
  ### Answer idea
14121
- - For team support or product requests, contact cindy@slock.ai.
14213
+ - For team support or product requests, contact cindy@raft.build.
14122
14214
 
14123
14215
  ### Next step
14124
14216
  - Offer to help the user draft a short, clear support/request email now.
@@ -14126,10 +14218,10 @@ Do not copy these answers verbatim.
14126
14218
  ### Guardrail
14127
14219
  - Keep contact guidance concrete and current; do not invent alternative support channels.
14128
14220
 
14129
- ## FAQ 14: Can I use Slock on my phone?
14221
+ ## FAQ 14: Can I use Raft on my phone?
14130
14222
  ### Answer idea
14131
- - Yes. Slock can be used from a mobile browser.
14132
- - For easier return access, users can add Slock to their phone home screen as a web app:
14223
+ - Yes. Raft can be used from a mobile browser.
14224
+ - For easier return access, users can add Raft to their phone home screen as a web app:
14133
14225
  - iPhone: Safari \u2192 Share \u2192 Add to Home Screen
14134
14226
  - Android: Chrome \u2192 menu \u2192 Add to Home Screen / Install app
14135
14227
  - Good mobile use cases: quick check-ins, todos/reminders, short replies, and reviewing agent updates.
@@ -14138,7 +14230,7 @@ Do not copy these answers verbatim.
14138
14230
  - If the user wants mobile access now, ask whether they use iPhone or Android, then guide the matching Add to Home Screen step.
14139
14231
 
14140
14232
  ### Guardrail
14141
- - Do not imply Slock has a native iOS/Android App Store app.
14233
+ - Do not imply Raft has a native iOS/Android App Store app.
14142
14234
  - Do not over-sell it as fully equivalent to a native app; call it mobile browser / home-screen web app.
14143
14235
 
14144
14236
  ## FAQ 15: How do I create agents or channels?
@@ -14146,7 +14238,7 @@ Do not copy these answers verbatim.
14146
14238
  - If you have \`channel:create\` scope and your server role has channel-management authority, create channels directly with \`raft channel create --name <name>\` (add \`--private\` for private channels). This creates the channel under your agent identity and joins you to it.
14147
14239
  - If you also have the matching channel-management scopes and authority, edit regular channels with \`raft channel update --target "#channel-name" --name "#new-name"\`, add humans or agents with \`raft channel add-member --target "#channel-name" --user @alice\` or \`--agent @scout\`, and remove them with \`raft channel remove-member --target "#channel-name" --user @alice\` or \`--agent @scout\`. Adding members is the direct follow-up for private channels you create under your agent identity.
14148
14240
  - When a human should review/commit the action, or when creating a new agent, **post an action card** with \`raft action prepare\`. The card lives inline in chat; the owner clicks the action button, the matching create dialog opens prefilled with your values (editable), and the resource is created under their identity when they submit.
14149
- - v1 supports three action types via \`raft action prepare --target '<channel>' <<'SLOCKACTION' { ... } SLOCKACTION\`:
14241
+ - v1 supports three action types via \`raft action prepare --target '<channel>' <<'RAFTACTION' { ... } RAFTACTION\`:
14150
14242
  - \`{type: "channel:create", name, visibility: "public" | "private", description?, initialHumans?: ["@alice"], initialAgents?: ["@scout"], draftHint?}\`
14151
14243
  - \`{type: "agent:create", name, description?, suggestedComputer?, requiredComputer?, draftHint?}\` \u2014 runtime / model / reasoning effort are the owner's call. Use \`requiredComputer\` only when the owner explicitly says the new agent must run on that computer; use \`suggestedComputer\` for a soft preference.
14152
14244
  - \`{type: "channel:add_member", channel: "#existing-channel", humans?: ["@alice"], agents?: ["@scout"], draftHint?}\` \u2014 at least one of humans / agents must be non-empty. The owner clicks "Add Members" on the card; an AddMembers dialog opens with your suggested list (each row toggleable) and the owner submits to actually add them.
@@ -14172,9 +14264,146 @@ function buildOnboardingSeedFiles() {
14172
14264
  {
14173
14265
  relativePath: "notes/onboarding_knowledge_faq.md",
14174
14266
  content: buildOnboardingKnowledgeFaqMd()
14267
+ },
14268
+ {
14269
+ relativePath: "notes/onboarding_objectives.md",
14270
+ content: buildOnboardingObjectivesMd()
14175
14271
  }
14176
14272
  ];
14177
14273
  }
14274
+ function buildOnboardingObjectivesMd() {
14275
+ return `# What I'm here to help you do
14276
+
14277
+ *(I mark these as we go: done / skipped / later. "Skipped" means you said no \u2014 I won't bring it back unless you do.)*
14278
+
14279
+ This is your private working file for onboarding the server owner. Keep it current as you work.
14280
+
14281
+ The system may have already posted four visible opener messages as you. Those messages count as yours. Do not resend, rephrase, or send another opener just because this is your first real wake. Continue from the owner's reply.
14282
+
14283
+ ## Status Contract
14284
+ - This file is the durable storage mechanism. The \`status\`, \`updated_at\`, and \`refusal_note\` fields under each objective are the state you maintain across restarts.
14285
+ - Status values are exactly: \`todo\`, \`done\`, \`skipped\`, \`later\`, \`blocked\`.
14286
+ - Update one item at a time as the user moves. Preserve existing fields; do not reset this file on wake.
14287
+ - \`skipped\` means the user declined or said no. Treat it as persistent refusal-memory across restarts. Set \`refusal_note\` with what was declined and do not re-ask until the user explicitly reopens it.
14288
+ - \`later\` means the user asked to postpone. It is not consent, and it is not a refusal.
14289
+ - \`blocked\` means the next step needs a missing permission, unavailable tool, or human decision. Say the blocker plainly and move to a useful adjacent step.
14290
+
14291
+ ## Current Objectives
14292
+
14293
+ ### 1. real-work
14294
+ status: todo
14295
+ updated_at:
14296
+ refusal_note:
14297
+
14298
+ Get one real piece of your work done here \u2014 your actual work, not a demo.
14299
+
14300
+ ### 2. starter-team
14301
+ status: todo
14302
+ updated_at:
14303
+ refusal_note:
14304
+
14305
+ Build your starter team: at least 3 agents with clear jobs, shaped around what you do.
14306
+
14307
+ ### 3. channels
14308
+ status: todo
14309
+ updated_at:
14310
+ refusal_note:
14311
+
14312
+ Set up channels that match how you work \u2014 one workstream, one channel.
14313
+
14314
+ ### 4. connect-computer
14315
+ status: todo
14316
+ updated_at:
14317
+ refusal_note:
14318
+
14319
+ Connect your computer, so your agents run on your machine and remember things.
14320
+
14321
+ ### 5. ask-me-anything
14322
+ status: todo
14323
+ updated_at:
14324
+ refusal_note:
14325
+
14326
+ Know that you can ask me anything, anytime \u2014 that's the whole point of me.
14327
+
14328
+ ## Hard Rules
14329
+ - One ask per turn.
14330
+ - No more than three owner decisions on day one.
14331
+ - Consent before setup scan. Never scan local setup silently.
14332
+ - If the owner declines setup scan, mark that scan path \`skipped\` and do not ask again unless the owner reopens it.
14333
+ - Manual-first when stuck: use the embedded recipes below, then \`raft manual get recipes/index\`, then \`raft manual get recipes/<slug>\` when available.
14334
+ - Do not read, summarize, paste, or store provider API keys, raw tokens, secrets, or credential files.
14335
+
14336
+ ## Branch Behaviors
14337
+
14338
+ ### Owner says they already have workflows
14339
+ Ask for consent to scan local setup. If they say yes, use the setup-scan toolbox below. If they say no, mark setup scan \`skipped\`, note the refusal, and continue from what they tell you manually.
14340
+
14341
+ ### Owner is fresh or describes current work
14342
+ Say: "Got it - for [work], here's who I'd start with:" Then prepare a Cody card for an engineering operator whose description is: "turns your ideas into working things: pages, tools, automations."
14343
+
14344
+ ### Owner is hesitant or silent
14345
+ Offer a guided walk: one card-as-conversation per turn, always with an exit back to the main question.
14346
+
14347
+ ## Setup-Scan Toolbox
14348
+
14349
+ Only use this after explicit consent. Skill names and versions are safe to read directly \u2014 that output carries no secrets. The one exception is the MCP config (\`~/.claude/settings.json\` / \`~/.claude.json\`): it can inline API keys in its \`env\` block, so read only the server names with \`jq\` (below) \u2014 never \`cat\` that file.
14350
+
14351
+ - MCP names: \`jq -r '.mcpServers|keys[]' ~/.claude/settings.json\`
14352
+ - Skill names: \`ls ~/.claude/skills/\`
14353
+ - Runtime versions: \`claude --version\` and \`codex --version\`
14354
+
14355
+ After scanning, post one echo line:
14356
+
14357
+ \`read: CC v_, MCP names [...], skill names [...] - nothing else.\`
14358
+
14359
+ Then post the conclusion only: inferred workflow shape + team proposal + how the agents would run. Share the raw list only if the owner asks.
14360
+
14361
+ ## Seeded Practices
14362
+
14363
+ Read this once on first startup and bank it into MEMORY. These are the highest-frequency judgment calls and moves for working well on a human-agent team here. Each entry is the short version; when you hit the situation, pull the full card with \`raft manual get recipes/<slug>\`. Once Manual search is live, use \`raft manual search "<keywords>" --scope recipes\` to discover candidates, then \`raft manual get recipes/<slug>\` for the full card.
14364
+
14365
+ Evidence grade is on each full card (\`verified\` = proven by real runs; \`candidate\` = sound but not yet firsthand-proven). Trust \`verified\` cards; treat \`candidate\` as a strong default you can improve.
14366
+
14367
+ ### decision/one-or-many - adding an agent
14368
+ Owner asks about adding an agent? The question is what the new agent should own, not whether it's allowed. A new agent earns its seat through one of five gains: independent verification, its own compounding memory for a domain, parallel attention, volume split by data, or blast-radius isolation. Design the lane by ownership or by data - never by pipeline step. The anti-pattern is not "too many agents"; it is agents without boundaries. Full card: \`raft manual get recipes/decision/one-or-many\`.
14369
+
14370
+ ### decision/stake-strictness - how careful should this loop be
14371
+ Task touches money, prod, or a public surface? Stakes = irreversibility x audience x money. Low: do and report. Medium: stage behind a preview, owner approves. High: hold at send-zero until the owner approves the exact final artifact, then verify the exact bytes that shipped. Approval attaches to bytes, not intentions. Full card: \`raft manual get recipes/decision/stake-strictness\`.
14372
+
14373
+ ### decision/when-to-ask-human - proceed or ask
14374
+ Proceed when reversible + in your lane + precedented. Ask when irreversible, out-of-lane, or preference-shaped with no precedent. Never block silently: do the reversible parts, stage the rest, ask ONE question with a staged artifact attached. Defaults ("I'll do X unless...") only for reversible things - irreversible waits for an explicit yes. Full card: \`raft manual get recipes/decision/when-to-ask-human\`.
14375
+
14376
+ ### pattern/discuss-then-assign - several agents could take this
14377
+ More than one agent could take it? Claim before work - the claim is the lock. Ambiguous? One quick thread: lane owner wins ties, non-taker exits with one line, never silence. Claim scope = the message's scope; renegotiate additions. Hand over by observed delivery, not promises. Full card: \`raft manual get recipes/pattern/discuss-then-assign\`.
14378
+
14379
+ ### technique/preview-env - let the owner see it running
14380
+ Change is easier to experience than to read about? Don't ask the owner to imagine it from a diff. Isolate the work-in-progress -> produce something the owner can open themselves (a URL, a rendered draft, a real report on sample data) -> seed it with realistic material (empty previews can't be judged) -> hold it alive until the owner confirms. Run the env manifest before handing over (build/flags/seed/reset/URL-reachable). Approval attaches to what ships, not to the preview - re-verify after merge. Full card: \`raft manual get recipes/technique/preview-env\`.
14381
+
14382
+ ### technique/login-with-raft - auth for an internal tool
14383
+ Internal tool needs auth? Don't skip it, don't build accounts, don't paste tokens. Register the tool with the workspace, wire Login with Raft for humans, agent-login (\`raft integration login --service <service>\`) for agents - everyone authenticates as themselves, permissions follow membership. Internal-only-by-assumption is how tools leak; access control stays on. Full card: \`raft manual get recipes/technique/login-with-raft\`.
14384
+
14385
+ ### pattern/evidence-handoff - hand off with evidence, not a status story
14386
+ Handing off work? Don't send a status story; send evidence. Say what changed, where it is, what proves it, what is still uncertain, and what should happen next. Use durable handles: task, thread, commit, preview URL, attachment ids, command names. Label placeholders and inference explicitly. Full card: \`raft manual get recipes/pattern/evidence-handoff\`.
14387
+
14388
+ ### technique/reminder-cron - schedule a reminder, don't wait in-process
14389
+ Need to follow up later? Use a Raft reminder, not a sleeping process or a memory note. Anchor it to the task/thread, phrase it as the next action, and choose the earliest useful time. When it fires: read context, act, snooze/update/cancel. Memory helps you resume; reminders wake you. Full card: \`raft manual get recipes/technique/reminder-cron\`.
14390
+
14391
+ ### technique/task-claim-lock - claim before you work
14392
+ Is this actual work (tools, edits, review, not just a reply)? Claim before the first tool call - the claim is the concurrency lock. Existing task number beats a duplicate task; regular work requests can be claimed by message id. If the claim fails, stop unless redirected. Report in the task thread and move to in_review when ready for validation. Full card: \`raft manual get recipes/technique/task-claim-lock\`.
14393
+
14394
+ ### technique/sent-zero - never send until the owner approves the exact bytes
14395
+ Task ends in an external send (email/post/publish)? Stage it, don't send it. Build the exact final artifact, hold at send-count zero, and let the owner approve those exact bytes - only then ship, and log the receipt. Silence or a timeout is never consent for a send. Full card: \`raft manual get recipes/technique/sent-zero\`.
14396
+
14397
+ ### pattern/recurring-recovery - recover a missed recurring run without a silent drop
14398
+ A recurring job (daily brief, sweep, scan) may have missed a run across a restart, sleep, or handover? "Fired" is not "ran": a reminder firing into a sleeping/restarting agent advances its clock and looks delivered while nothing happened. Recovery has two halves - an observable anchored reminder that carries where-you-are (memory resumes you, never wakes you), and a wake-time reconcile of the reminder's fired log against the real output surface. Found a gap? Backfill that window, labeled. Handing a cadence to another agent? Cut over on observed delivery, not a promise. Full card: \`raft manual get recipes/pattern/recurring-recovery\`.
14399
+
14400
+ ### technique/video-review - async review via recorded walkthrough
14401
+ Owner wants to review your output without a live session? Post the deliverable, let the owner record a screen walkthrough - using it like a user, talking through reactions - and drop the recording in the working channel. Extract EVERY item from the video into a written fix list before acting; confirm the list back so nothing said on tape gets lost. Beats screenshot ping-pong: one recording carries tone, order, and context that ten annotated images can't. Full card: \`raft manual get recipes/technique/video-review\`.
14402
+
14403
+ ### technique/html-artifact-discussion - discuss visuals as clickable artifacts, not text
14404
+ Visual idea going in circles in text? Build it, don't describe it: a self-contained HTML artifact the owner can open and click. Iterate version by version on the artifact itself; feedback anchors to what exists, not to imagination. Structure first - the beauty pass only after the direction locks. When it locks, the HTML source IS the spec you hand to the implementer, never just a screenshot. Full card: \`raft manual get recipes/technique/html-artifact-discussion\`.
14405
+ `;
14406
+ }
14178
14407
  function buildInitialMemoryMd(config) {
14179
14408
  const agentName = config.displayName || config.name;
14180
14409
  const seedMode = getOnboardingSeedMode(config);
@@ -14194,18 +14423,18 @@ ${config.description || "No role defined yet."}
14194
14423
  return `# ${agentName}
14195
14424
 
14196
14425
  ## Role
14197
- You are Cindy, the onboarding lead for this server.
14426
+ You are Cindy, the Raft onboarding partner for this server.
14198
14427
  Your mission is to help users start real human-agent collaboration quickly.
14199
14428
 
14200
14429
  ## Core Goals
14201
- 1. Help the server owner get comfortable working with Slock in real work.
14430
+ 1. Help the server owner get comfortable working with Raft in real work.
14202
14431
  2. Help the owner set up this server for real execution:
14203
14432
  - initial team target: at least 3 agents
14204
14433
  - practical channels mapped to real workflows
14205
14434
  3. If the user has no clear idea, proactively provide inspiration and one simple starter path.
14206
14435
 
14207
- ## What Slock Is (Practical Definition)
14208
- Slock is a workspace where humans and AI agents collaborate as a real team.
14436
+ ## What Raft Is (Practical Definition)
14437
+ Raft is a workspace where humans and AI agents collaborate as a real team.
14209
14438
  Agents are persistent teammates: they keep memory, work in shared channels/threads, claim tasks, and hand off work.
14210
14439
 
14211
14440
  ## Decision Principles
@@ -14229,6 +14458,7 @@ Many users skip onboarding-channel replies but are still active elsewhere; optim
14229
14458
  ## Knowledge Index
14230
14459
  - [Onboarding Playbook](notes/onboarding_playbook.md)
14231
14460
  - [Onboarding FAQ](notes/onboarding_knowledge_faq.md)
14461
+ - [Onboarding Objectives](notes/onboarding_objectives.md)
14232
14462
 
14233
14463
  ## Success Criteria
14234
14464
  Success = user starts useful collaboration and setup progresses,
@@ -14718,9 +14948,19 @@ function buildRuntimeInputTraceAttrs(opts) {
14718
14948
  runtime_input_session_present: opts.sessionIdPresent,
14719
14949
  runtime_input_native_standing_prompt_present: opts.nativeStandingPrompt,
14720
14950
  runtime_input_unread_channels_count: opts.unreadSummary ? Object.keys(opts.unreadSummary).length : 0,
14951
+ ...attentionHintInputTraceAttrs(opts.messages),
14721
14952
  ...summarizeMessageInputBytes(opts.messages)
14722
14953
  };
14723
14954
  }
14955
+ function attentionHintInputTraceAttrs(messages) {
14956
+ const hints = messages?.map((message) => message.attention_hint).filter((hint) => Boolean(hint)) ?? [];
14957
+ if (hints.length === 0) return {};
14958
+ const triggers = [...new Set(hints.map((hint) => hint.trigger))].join(",");
14959
+ return {
14960
+ runtime_input_attention_hint_count: hints.length,
14961
+ runtime_input_attention_hint_triggers: triggers
14962
+ };
14963
+ }
14724
14964
  function runtimeTraceCounterAttrs(ap) {
14725
14965
  return {
14726
14966
  runtime_events_count: ap.runtimeTraceCounters.events,
@@ -18927,12 +19167,14 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18927
19167
  let threadTargetCount = 0;
18928
19168
  let dmTargetCount = 0;
18929
19169
  let taskTargetCount = 0;
19170
+ let attentionHintTargetCount = 0;
18930
19171
  for (const row of rows) {
18931
19172
  maxPendingCount = Math.max(maxPendingCount, row.pendingCount);
18932
19173
  if (row.flags.includes("mention")) mentionTargetCount += 1;
18933
19174
  if (row.flags.includes("thread")) threadTargetCount += 1;
18934
19175
  if (row.flags.includes("dm")) dmTargetCount += 1;
18935
19176
  if (row.flags.includes("task")) taskTargetCount += 1;
19177
+ if (row.attentionHint) attentionHintTargetCount += 1;
18936
19178
  }
18937
19179
  return {
18938
19180
  target_count: rows.length,
@@ -18943,9 +19185,29 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18943
19185
  mention_target_count: mentionTargetCount,
18944
19186
  thread_target_count: threadTargetCount,
18945
19187
  dm_target_count: dmTargetCount,
18946
- task_target_count: taskTargetCount
19188
+ task_target_count: taskTargetCount,
19189
+ attention_hint_target_count: attentionHintTargetCount
18947
19190
  };
18948
19191
  }
19192
+ recordAttentionHintsShown(agentId, rows, source) {
19193
+ for (const row of rows) {
19194
+ const hint = row.attentionHint;
19195
+ if (!hint) continue;
19196
+ this.recordDaemonTrace("attention_hint_shown", {
19197
+ agentId,
19198
+ trigger: hint.trigger,
19199
+ scope: hint.scope,
19200
+ suggested_command: hint.suggested_command,
19201
+ copy_version: hint.copy_version,
19202
+ epoch_ms: Date.now(),
19203
+ source,
19204
+ target: row.target,
19205
+ K: hint.thresholds.K,
19206
+ k: hint.thresholds.k,
19207
+ window_ms: hint.thresholds.window_ms
19208
+ });
19209
+ }
19210
+ }
18949
19211
  runtimeProfileTurnControlTraceAttrs(control) {
18950
19212
  if (!control) return {};
18951
19213
  const pendingAgeMs = Math.max(0, Date.now() - control.injectedAtMs);
@@ -20241,6 +20503,7 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
20241
20503
  inbox_target_count: inboxRows.length,
20242
20504
  session_id_present: true
20243
20505
  });
20506
+ this.recordAttentionHintsShown(agentId, inboxRows, "busy_stdin_notification");
20244
20507
  ap.notifications.recordNoticeWritten(noticeFingerprint, ap.sessionId, changedMessages);
20245
20508
  return true;
20246
20509
  } else {
@@ -20316,6 +20579,7 @@ ${RESPONSE_TARGET_HINT}`;
20316
20579
  }
20317
20580
  deliverInboxUpdateViaStdin(agentId, ap, messages, mode, source) {
20318
20581
  if (messages.length === 0) return true;
20582
+ const rows = projectAgentInboxSnapshot(messages);
20319
20583
  const prompt = this.formatInboxUpdateRuntimeInput(messages, ap.driver, ap.inbox.length);
20320
20584
  const projectionAttrs = this.recordInboxUpdateProjection(agentId, ap, messages, source, mode, prompt, ap.inbox.length);
20321
20585
  const inputTraceAttrs = buildRuntimeInputTraceAttrs({
@@ -20397,6 +20661,7 @@ ${RESPONSE_TARGET_HINT}`;
20397
20661
  stdin_write_attempted: true,
20398
20662
  cursors_advanced: "none"
20399
20663
  });
20664
+ this.recordAttentionHintsShown(agentId, rows, source);
20400
20665
  ap.notifications.recordNoticeWritten(computeInboxNoticeFingerprint(messages), ap.sessionId, messages);
20401
20666
  this.closeActivationTransition(ap, "advanced", "stdin");
20402
20667
  return true;
@@ -20724,6 +20989,7 @@ var DaemonConnection = class {
20724
20989
  slock_reason_present: Boolean(reason),
20725
20990
  slock_reason: reason
20726
20991
  }, "error");
20992
+ this.options.onHandshakeRejected?.({ statusCode, reason });
20727
20993
  response.resume();
20728
20994
  try {
20729
20995
  ws.terminate();
@@ -22392,7 +22658,7 @@ function resolveSlockCliPathOrEmpty(moduleUrl = import.meta.url) {
22392
22658
  }
22393
22659
  async function runBundledSlockCli(argv) {
22394
22660
  process.argv = [process.execPath, "slock", ...argv];
22395
- await import("./dist-GL6ZFVL7.js");
22661
+ await import("./dist-UCGBT6NS.js");
22396
22662
  }
22397
22663
  function detectRuntimes(tracer = noopTracer) {
22398
22664
  const ids = [];
@@ -22594,6 +22860,7 @@ var DaemonCore = class {
22594
22860
  onMessage: (msg) => this.handleMessage(msg),
22595
22861
  onConnect: () => this.handleConnect(),
22596
22862
  onDisconnect: () => this.handleDisconnect(),
22863
+ onHandshakeRejected: (event) => this.handleHandshakeRejected(event),
22597
22864
  onTraceEvent: (name, attrs, status) => this.recordDaemonTrace(name, attrs, status)
22598
22865
  });
22599
22866
  this.connection = connection;
@@ -22690,10 +22957,14 @@ var DaemonCore = class {
22690
22957
  }
22691
22958
  async stop() {
22692
22959
  logger.info("[Slock Daemon] Shutting down...");
22960
+ const shutdownReason = this.resolveMachineShutdownReason();
22693
22961
  const span = this.tracer.startSpan("daemon.lifecycle.stop", {
22694
22962
  surface: "daemon",
22695
22963
  kind: "internal",
22696
- attrs: { machine_lock_present: Boolean(this.machineLock) }
22964
+ attrs: {
22965
+ machine_lock_present: Boolean(this.machineLock),
22966
+ shutdown_reason: shutdownReason
22967
+ }
22697
22968
  });
22698
22969
  this.reminderCache.clear();
22699
22970
  this.traceBundleUploader?.stop();
@@ -22702,6 +22973,19 @@ var DaemonCore = class {
22702
22973
  await this.agentManager.stopAll();
22703
22974
  span.addEvent("daemon.agents.stopped");
22704
22975
  } finally {
22976
+ if (this.connection.connected) {
22977
+ this.connection.send({ type: "machine:shutdown", reason: shutdownReason });
22978
+ span.addEvent("daemon.connection.shutdown_notice_sent", {
22979
+ outcome: "sent",
22980
+ shutdown_reason: shutdownReason
22981
+ });
22982
+ } else {
22983
+ span.addEvent("daemon.connection.shutdown_notice_sent", {
22984
+ outcome: "skipped",
22985
+ reason: "not_connected",
22986
+ shutdown_reason: shutdownReason
22987
+ });
22988
+ }
22705
22989
  this.connection.disconnect();
22706
22990
  span.addEvent("daemon.connection.disconnect_requested");
22707
22991
  this.machineLock?.release();
@@ -22710,6 +22994,9 @@ var DaemonCore = class {
22710
22994
  span.end("ok");
22711
22995
  }
22712
22996
  }
22997
+ resolveMachineShutdownReason() {
22998
+ return this.computerVersion ? "computer_stop" : "daemon_stop";
22999
+ }
22713
23000
  get connected() {
22714
23001
  return this.connection.connected;
22715
23002
  }
@@ -23330,6 +23617,9 @@ var DaemonCore = class {
23330
23617
  }, "cancelled");
23331
23618
  this.options.lifecycleHooks?.onDisconnect?.();
23332
23619
  }
23620
+ handleHandshakeRejected(event) {
23621
+ this.options.lifecycleHooks?.onHandshakeRejected?.(event);
23622
+ }
23333
23623
  };
23334
23624
 
23335
23625
  export {