@contextstream/mcp-server 0.4.58 → 0.4.60

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.
@@ -925,7 +925,7 @@ def main():
925
925
  if tool == "Glob":
926
926
  pattern = inp.get("pattern", "")
927
927
  if is_discovery_glob(pattern):
928
- print(f"STOP: Use mcp__contextstream__search(mode=\\"hybrid\\", query=\\"{pattern}\\") instead of Glob.", file=sys.stderr)
928
+ print(f"STOP: Use mcp__contextstream__search(mode=\\"auto\\", query=\\"{pattern}\\") instead of Glob.", file=sys.stderr)
929
929
  sys.exit(2)
930
930
 
931
931
  elif tool == "Grep" or tool == "Search":
@@ -937,12 +937,12 @@ def main():
937
937
  # Specific file - suggest Read instead
938
938
  print(f"STOP: Use Read(\\"{path}\\") to view file content, or mcp__contextstream__search(mode=\\"keyword\\", query=\\"{pattern}\\") for codebase search.", file=sys.stderr)
939
939
  else:
940
- print(f"STOP: Use mcp__contextstream__search(mode=\\"hybrid\\", query=\\"{pattern}\\") instead of {tool}.", file=sys.stderr)
940
+ print(f"STOP: Use mcp__contextstream__search(mode=\\"auto\\", query=\\"{pattern}\\") instead of {tool}.", file=sys.stderr)
941
941
  sys.exit(2)
942
942
 
943
943
  elif tool == "Task":
944
944
  if inp.get("subagent_type", "").lower() == "explore":
945
- print("STOP: Use mcp__contextstream__search(mode=\\"hybrid\\") instead of Task(Explore).", file=sys.stderr)
945
+ print("STOP: Use mcp__contextstream__search(mode=\\"auto\\") instead of Task(Explore).", file=sys.stderr)
946
946
  sys.exit(2)
947
947
  if inp.get("subagent_type", "").lower() == "plan":
948
948
  print("STOP: Use mcp__contextstream__session(action=\\"capture_plan\\") for planning. ContextStream plans persist across sessions.", file=sys.stderr)
@@ -969,7 +969,7 @@ import os
969
969
  ENABLED = os.environ.get("CONTEXTSTREAM_REMINDER_ENABLED", "true").lower() == "true"
970
970
 
971
971
  REMINDER = """[CONTEXTSTREAM RULES]
972
- 1. BEFORE Glob/Grep/Read/Search: mcp__contextstream__search(mode="hybrid") FIRST
972
+ 1. BEFORE Glob/Grep/Read/Search: mcp__contextstream__search(mode="auto") FIRST
973
973
  2. Call context_smart at start of EVERY response
974
974
  3. Local tools ONLY if ContextStream returns 0 results
975
975
  [END RULES]"""
@@ -1405,7 +1405,7 @@ def main():
1405
1405
  pattern = params.get("path", "") or params.get("regex", "")
1406
1406
  if is_discovery_glob(pattern) or is_discovery_grep(pattern):
1407
1407
  output_block(
1408
- f"Use mcp__contextstream__search(mode=\\"hybrid\\", query=\\"{pattern}\\") instead of {tool}. "
1408
+ f"Use mcp__contextstream__search(mode=\\"auto\\", query=\\"{pattern}\\") instead of {tool}. "
1409
1409
  "ContextStream search is indexed and faster. Only use local tools if ContextStream returns 0 results.",
1410
1410
  "[CONTEXTSTREAM] Use ContextStream search for code discovery."
1411
1411
  )
@@ -1432,7 +1432,7 @@ import os
1432
1432
  ENABLED = os.environ.get("CONTEXTSTREAM_REMINDER_ENABLED", "true").lower() == "true"
1433
1433
 
1434
1434
  REMINDER = """[CONTEXTSTREAM RULES]
1435
- 1. BEFORE list_files/search_files/read_file: mcp__contextstream__search(mode="hybrid") FIRST
1435
+ 1. BEFORE list_files/search_files/read_file: mcp__contextstream__search(mode="auto") FIRST
1436
1436
  2. Call context_smart at start of EVERY response
1437
1437
  3. Local tools ONLY if ContextStream returns 0 results
1438
1438
  [END RULES]"""
@@ -1583,7 +1583,7 @@ def main():
1583
1583
  pattern = params.get("pattern", "") or params.get("path", "")
1584
1584
  if is_discovery_glob(pattern):
1585
1585
  output_deny(
1586
- f"Use mcp__contextstream__search(mode=\\"hybrid\\", query=\\"{pattern}\\") instead of {tool}. "
1586
+ f"Use mcp__contextstream__search(mode=\\"auto\\", query=\\"{pattern}\\") instead of {tool}. "
1587
1587
  "ContextStream search is indexed and faster."
1588
1588
  )
1589
1589
 
@@ -173,7 +173,7 @@ async function runPreToolUseHook() {
173
173
  fs.appendFileSync(DEBUG_FILE, `[PreToolUse] Glob pattern=${pattern}, isDiscovery=${isDiscoveryGlob(pattern)}
174
174
  `);
175
175
  if (isDiscoveryGlob(pattern)) {
176
- const msg = `STOP: Use mcp__contextstream__search(mode="hybrid", query="${pattern}") instead of Glob.`;
176
+ const msg = `STOP: Use mcp__contextstream__search(mode="auto", query="${pattern}") instead of Glob.`;
177
177
  fs.appendFileSync(DEBUG_FILE, `[PreToolUse] Intercepting discovery glob: ${msg}
178
178
  `);
179
179
  if (editorFormat === "cline") {
@@ -196,7 +196,7 @@ async function runPreToolUseHook() {
196
196
  }
197
197
  blockClaudeCode(msg);
198
198
  } else {
199
- const msg = `STOP: Use mcp__contextstream__search(mode="hybrid", query="${pattern}") instead of ${tool}.`;
199
+ const msg = `STOP: Use mcp__contextstream__search(mode="auto", query="${pattern}") instead of ${tool}.`;
200
200
  if (editorFormat === "cline") {
201
201
  outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream search for code discovery.");
202
202
  } else if (editorFormat === "cursor") {
@@ -208,7 +208,7 @@ async function runPreToolUseHook() {
208
208
  } else if (tool === "Task") {
209
209
  const subagentType = toolInput?.subagent_type?.toLowerCase() || "";
210
210
  if (subagentType === "explore") {
211
- const msg = 'STOP: Use mcp__contextstream__search(mode="hybrid") instead of Task(Explore).';
211
+ const msg = 'STOP: Use mcp__contextstream__search(mode="auto") instead of Task(Explore).';
212
212
  if (editorFormat === "cline") {
213
213
  outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream search for code discovery.");
214
214
  } else if (editorFormat === "cursor") {
@@ -237,7 +237,7 @@ async function runPreToolUseHook() {
237
237
  if (tool === "list_files" || tool === "search_files") {
238
238
  const pattern = toolInput?.path || toolInput?.regex || "";
239
239
  if (isDiscoveryGlob(pattern) || isDiscoveryGrep(pattern)) {
240
- const msg = `Use mcp__contextstream__search(mode="hybrid", query="${pattern}") instead of ${tool}. ContextStream search is indexed and faster.`;
240
+ const msg = `Use mcp__contextstream__search(mode="auto", query="${pattern}") instead of ${tool}. ContextStream search is indexed and faster.`;
241
241
  if (editorFormat === "cline") {
242
242
  outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream search for code discovery.");
243
243
  } else if (editorFormat === "cursor") {
@@ -181,7 +181,7 @@ async function runPreToolUseHook() {
181
181
  fs.appendFileSync(DEBUG_FILE, `[PreToolUse] Glob pattern=${pattern}, isDiscovery=${isDiscoveryGlob(pattern)}
182
182
  `);
183
183
  if (isDiscoveryGlob(pattern)) {
184
- const msg = `STOP: Use mcp__contextstream__search(mode="hybrid", query="${pattern}") instead of Glob.`;
184
+ const msg = `STOP: Use mcp__contextstream__search(mode="auto", query="${pattern}") instead of Glob.`;
185
185
  fs.appendFileSync(DEBUG_FILE, `[PreToolUse] Intercepting discovery glob: ${msg}
186
186
  `);
187
187
  if (editorFormat === "cline") {
@@ -204,7 +204,7 @@ async function runPreToolUseHook() {
204
204
  }
205
205
  blockClaudeCode(msg);
206
206
  } else {
207
- const msg = `STOP: Use mcp__contextstream__search(mode="hybrid", query="${pattern}") instead of ${tool}.`;
207
+ const msg = `STOP: Use mcp__contextstream__search(mode="auto", query="${pattern}") instead of ${tool}.`;
208
208
  if (editorFormat === "cline") {
209
209
  outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream search for code discovery.");
210
210
  } else if (editorFormat === "cursor") {
@@ -216,7 +216,7 @@ async function runPreToolUseHook() {
216
216
  } else if (tool === "Task") {
217
217
  const subagentType = toolInput?.subagent_type?.toLowerCase() || "";
218
218
  if (subagentType === "explore") {
219
- const msg = 'STOP: Use mcp__contextstream__search(mode="hybrid") instead of Task(Explore).';
219
+ const msg = 'STOP: Use mcp__contextstream__search(mode="auto") instead of Task(Explore).';
220
220
  if (editorFormat === "cline") {
221
221
  outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream search for code discovery.");
222
222
  } else if (editorFormat === "cursor") {
@@ -245,7 +245,7 @@ async function runPreToolUseHook() {
245
245
  if (tool === "list_files" || tool === "search_files") {
246
246
  const pattern = toolInput?.path || toolInput?.regex || "";
247
247
  if (isDiscoveryGlob(pattern) || isDiscoveryGrep(pattern)) {
248
- const msg = `Use mcp__contextstream__search(mode="hybrid", query="${pattern}") instead of ${tool}. ContextStream search is indexed and faster.`;
248
+ const msg = `Use mcp__contextstream__search(mode="auto", query="${pattern}") instead of ${tool}. ContextStream search is indexed and faster.`;
249
249
  if (editorFormat === "cline") {
250
250
  outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream search for code discovery.");
251
251
  } else if (editorFormat === "cursor") {
@@ -677,6 +677,34 @@ async function saveLastExchange(exchange, cwd, clientName) {
677
677
  } catch {
678
678
  }
679
679
  }
680
+ async function fetchHookContext() {
681
+ if (!API_KEY) return null;
682
+ try {
683
+ const controller = new AbortController();
684
+ const timeoutId = setTimeout(() => controller.abort(), 2e3);
685
+ const url = `${API_URL}/api/v1/context/hook`;
686
+ const body = {};
687
+ if (WORKSPACE_ID) body.workspace_id = WORKSPACE_ID;
688
+ if (PROJECT_ID) body.project_id = PROJECT_ID;
689
+ const response = await fetch(url, {
690
+ method: "POST",
691
+ headers: {
692
+ "X-API-Key": API_KEY,
693
+ "Content-Type": "application/json"
694
+ },
695
+ body: JSON.stringify(body),
696
+ signal: controller.signal
697
+ });
698
+ clearTimeout(timeoutId);
699
+ if (response.ok) {
700
+ const data = await response.json();
701
+ return data?.data?.context || null;
702
+ }
703
+ return null;
704
+ } catch {
705
+ return null;
706
+ }
707
+ }
680
708
  async function fetchSessionContext() {
681
709
  if (!API_KEY) return null;
682
710
  try {
@@ -755,26 +783,6 @@ function transformSmartContextResponse(data) {
755
783
  return null;
756
784
  }
757
785
  }
758
- function buildClaudeReminder(ctx, versionNotice) {
759
- const parts = [];
760
- if (versionNotice?.behind) {
761
- const versionInfo = getVersionNoticeForHook(versionNotice);
762
- if (versionInfo) {
763
- parts.push(versionInfo);
764
- parts.push("");
765
- }
766
- }
767
- const highImportancePrefs = ctx?.preferences?.filter((p) => p.importance === "high") || [];
768
- if (highImportancePrefs.length > 0) {
769
- parts.push(`[USER PREFERENCES - Always respect these]`);
770
- for (const pref of highImportancePrefs.slice(0, 5)) {
771
- parts.push(`\u2022 ${pref.title}: ${pref.content}`);
772
- }
773
- parts.push("");
774
- }
775
- parts.push(REMINDER);
776
- return parts.join("\n");
777
- }
778
786
  function buildEnhancedReminder(ctx, isNewSession2, versionNotice) {
779
787
  const parts = [ENHANCED_REMINDER_HEADER];
780
788
  if (versionNotice?.behind) {
@@ -792,7 +800,7 @@ function buildEnhancedReminder(ctx, isNewSession2, versionNotice) {
792
800
  2. Wait for indexing: if \`init\` returns \`indexing_status: "started"\`, files are being indexed
793
801
  3. Generate a unique session_id (e.g., "session-" + timestamp or UUID) - use this for ALL context() calls
794
802
  4. Call \`context(user_message="...", save_exchange=true, session_id="<your-session-id>")\` for task-specific context
795
- 5. Use \`search(mode="hybrid")\` for code discovery (not Glob/Grep/Read)
803
+ 5. Use \`search(mode="auto")\` for code discovery (not Glob/Grep/Read)
796
804
 
797
805
  `);
798
806
  }
@@ -833,7 +841,7 @@ function buildEnhancedReminder(ctx, isNewSession2, versionNotice) {
833
841
  parts.push("");
834
842
  }
835
843
  parts.push("---\n");
836
- parts.push(REMINDER);
844
+ parts.push(FULL_REMINDER);
837
845
  parts.push(`
838
846
 
839
847
  ---
@@ -850,7 +858,7 @@ Returns: \`indexed\` (true/false), \`last_indexed_at\`, \`file_count\`
850
858
  ### \u{1F50D} Search Decision Tree:
851
859
 
852
860
  **IF indexed=true AND last_indexed_at is recent:**
853
- \u2192 Use \`search(mode="hybrid", query="...")\`
861
+ \u2192 Use \`search(mode="auto", query="...")\`
854
862
 
855
863
  **IF indexed=false OR last_indexed_at is stale (>7 days):**
856
864
  \u2192 Use local tools (Glob/Grep/Read) directly
@@ -921,61 +929,58 @@ async function runUserPromptSubmitHook() {
921
929
  }
922
930
  const editorFormat = detectEditorFormat2(input);
923
931
  const cwd = input.cwd || process.cwd();
924
- loadConfigFromMcpJson(cwd);
925
- const versionNoticePromise = getUpdateNotice();
926
- const lastExchange = extractLastExchange(input, editorFormat);
927
- const clientName = editorFormat === "claude" ? "claude-code" : editorFormat;
928
- const saveExchangePromise = lastExchange ? saveLastExchange(lastExchange, cwd, clientName) : Promise.resolve();
929
932
  if (editorFormat === "claude") {
930
- saveExchangePromise.catch(() => {
931
- });
932
- const [ctx, versionNotice] = await Promise.all([fetchSessionContext(), versionNoticePromise]);
933
- const claudeReminder = buildClaudeReminder(ctx, versionNotice);
933
+ loadConfigFromMcpJson(cwd);
934
+ let context = REMINDER;
935
+ if (API_KEY) {
936
+ try {
937
+ const hookContext = await fetchHookContext();
938
+ if (hookContext) {
939
+ context = hookContext;
940
+ }
941
+ } catch {
942
+ }
943
+ }
934
944
  console.log(
935
945
  JSON.stringify({
936
946
  hookSpecificOutput: {
937
947
  hookEventName: "UserPromptSubmit",
938
- additionalContext: claudeReminder
948
+ additionalContext: context
939
949
  }
940
950
  })
941
951
  );
942
- } else if (editorFormat === "cline") {
943
- const newSession = isNewSession(input, editorFormat);
944
- const [ctx, versionNotice] = await Promise.all([fetchSessionContext(), versionNoticePromise, saveExchangePromise]);
945
- const enhancedReminder = buildEnhancedReminder(ctx, newSession, versionNotice);
946
- console.log(
947
- JSON.stringify({
948
- cancel: false,
949
- contextModification: enhancedReminder
950
- })
951
- );
952
- } else if (editorFormat === "cursor") {
952
+ } else {
953
+ loadConfigFromMcpJson(cwd);
954
+ const versionNoticePromise = getUpdateNotice();
955
+ const lastExchange = extractLastExchange(input, editorFormat);
956
+ const clientName = editorFormat;
957
+ const saveExchangePromise = lastExchange ? saveLastExchange(lastExchange, cwd, clientName) : Promise.resolve();
953
958
  const newSession = isNewSession(input, editorFormat);
954
959
  const [ctx, versionNotice] = await Promise.all([fetchSessionContext(), versionNoticePromise, saveExchangePromise]);
955
- let cursorReminder = ctx?.lessons?.length ? `[CONTEXTSTREAM] \u26A0\uFE0F ${ctx.lessons.length} lessons from past mistakes. Call context(save_exchange=true, session_id="...") FIRST. Use search(mode="hybrid") before Glob/Grep. After file edits: project(action="index").` : `[CONTEXTSTREAM] Call context(save_exchange=true, session_id="...") FIRST. Use search(mode="hybrid") before Glob/Grep/Read. After file edits: project(action="index").`;
956
- if (versionNotice?.behind) {
957
- cursorReminder += ` [UPDATE v${versionNotice.current}\u2192${versionNotice.latest}]`;
960
+ if (editorFormat === "cursor") {
961
+ let cursorReminder = ctx?.lessons?.length ? `[CONTEXTSTREAM] \u26A0\uFE0F ${ctx.lessons.length} lessons from past mistakes. Call context(save_exchange=true, session_id="...") FIRST. Use search(mode="auto") before Glob/Grep. After file edits: project(action="index").` : `[CONTEXTSTREAM] Call context(save_exchange=true, session_id="...") FIRST. Use search(mode="auto") before Glob/Grep/Read. After file edits: project(action="index").`;
962
+ if (versionNotice?.behind) {
963
+ cursorReminder += ` [UPDATE v${versionNotice.current}\u2192${versionNotice.latest}]`;
964
+ }
965
+ console.log(
966
+ JSON.stringify({
967
+ continue: true,
968
+ user_message: cursorReminder
969
+ })
970
+ );
971
+ } else {
972
+ const enhancedReminder = buildEnhancedReminder(ctx, newSession, versionNotice);
973
+ console.log(
974
+ JSON.stringify({
975
+ cancel: false,
976
+ contextModification: enhancedReminder
977
+ })
978
+ );
958
979
  }
959
- console.log(
960
- JSON.stringify({
961
- continue: true,
962
- user_message: cursorReminder
963
- })
964
- );
965
- } else if (editorFormat === "antigravity") {
966
- const newSession = isNewSession(input, editorFormat);
967
- const [ctx, versionNotice] = await Promise.all([fetchSessionContext(), versionNoticePromise, saveExchangePromise]);
968
- const enhancedReminder = buildEnhancedReminder(ctx, newSession, versionNotice);
969
- console.log(
970
- JSON.stringify({
971
- cancel: false,
972
- contextModification: enhancedReminder
973
- })
974
- );
975
980
  }
976
981
  process.exit(0);
977
982
  }
978
- var ENABLED2, API_URL, API_KEY, WORKSPACE_ID, PROJECT_ID, REMINDER, ENHANCED_REMINDER_HEADER, isDirectRun2;
983
+ var ENABLED2, API_URL, API_KEY, WORKSPACE_ID, PROJECT_ID, REMINDER, FULL_REMINDER, ENHANCED_REMINDER_HEADER, isDirectRun2;
979
984
  var init_user_prompt_submit = __esm({
980
985
  "src/hooks/user-prompt-submit.ts"() {
981
986
  "use strict";
@@ -985,7 +990,9 @@ var init_user_prompt_submit = __esm({
985
990
  API_KEY = process.env.CONTEXTSTREAM_API_KEY || "";
986
991
  WORKSPACE_ID = null;
987
992
  PROJECT_ID = null;
988
- REMINDER = `[CONTEXTSTREAM RULES - MANDATORY]
993
+ REMINDER = `[CONTEXTSTREAM] Call mcp__contextstream__context(user_message="...", save_exchange=true, session_id="<session-id>") FIRST before any other tool. Response contains dynamic rules, lessons, preferences. For search: use search(mode="auto") if indexed, else local tools.
994
+ [END]`;
995
+ FULL_REMINDER = `[CONTEXTSTREAM RULES - MANDATORY]
989
996
 
990
997
  1. FIRST: Call mcp__contextstream__context(user_message="...", save_exchange=true, session_id="<session-id>") before ANY other tool
991
998
  - Returns: dynamic rules, lessons from past mistakes, relevant context
@@ -995,7 +1002,7 @@ var init_user_prompt_submit = __esm({
995
1002
 
996
1003
  2. FOR CODE SEARCH: Check index status, then search appropriately
997
1004
  \u26A0\uFE0F BEFORE searching: mcp__contextstream__project(action="index_status")
998
- \u2705 IF indexed & fresh: Use mcp__contextstream__search(mode="hybrid", query="...")
1005
+ \u2705 IF indexed & fresh: Use mcp__contextstream__search(mode="auto", query="...")
999
1006
  \u2705 IF NOT indexed OR stale: Use local tools (Glob/Grep/Read) directly
1000
1007
  \u2705 IF search returns 0 results: Fallback to local tools (Glob/Grep/Read)
1001
1008
 
@@ -2726,7 +2733,7 @@ def main():
2726
2733
  if tool == "Glob":
2727
2734
  pattern = inp.get("pattern", "")
2728
2735
  if is_discovery_glob(pattern):
2729
- print(f"STOP: Use mcp__contextstream__search(mode=\\"hybrid\\", query=\\"{pattern}\\") instead of Glob.", file=sys.stderr)
2736
+ print(f"STOP: Use mcp__contextstream__search(mode=\\"auto\\", query=\\"{pattern}\\") instead of Glob.", file=sys.stderr)
2730
2737
  sys.exit(2)
2731
2738
 
2732
2739
  elif tool == "Grep" or tool == "Search":
@@ -2738,12 +2745,12 @@ def main():
2738
2745
  # Specific file - suggest Read instead
2739
2746
  print(f"STOP: Use Read(\\"{path}\\") to view file content, or mcp__contextstream__search(mode=\\"keyword\\", query=\\"{pattern}\\") for codebase search.", file=sys.stderr)
2740
2747
  else:
2741
- print(f"STOP: Use mcp__contextstream__search(mode=\\"hybrid\\", query=\\"{pattern}\\") instead of {tool}.", file=sys.stderr)
2748
+ print(f"STOP: Use mcp__contextstream__search(mode=\\"auto\\", query=\\"{pattern}\\") instead of {tool}.", file=sys.stderr)
2742
2749
  sys.exit(2)
2743
2750
 
2744
2751
  elif tool == "Task":
2745
2752
  if inp.get("subagent_type", "").lower() == "explore":
2746
- print("STOP: Use mcp__contextstream__search(mode=\\"hybrid\\") instead of Task(Explore).", file=sys.stderr)
2753
+ print("STOP: Use mcp__contextstream__search(mode=\\"auto\\") instead of Task(Explore).", file=sys.stderr)
2747
2754
  sys.exit(2)
2748
2755
  if inp.get("subagent_type", "").lower() == "plan":
2749
2756
  print("STOP: Use mcp__contextstream__session(action=\\"capture_plan\\") for planning. ContextStream plans persist across sessions.", file=sys.stderr)
@@ -2770,7 +2777,7 @@ import os
2770
2777
  ENABLED = os.environ.get("CONTEXTSTREAM_REMINDER_ENABLED", "true").lower() == "true"
2771
2778
 
2772
2779
  REMINDER = """[CONTEXTSTREAM RULES]
2773
- 1. BEFORE Glob/Grep/Read/Search: mcp__contextstream__search(mode="hybrid") FIRST
2780
+ 1. BEFORE Glob/Grep/Read/Search: mcp__contextstream__search(mode="auto") FIRST
2774
2781
  2. Call context_smart at start of EVERY response
2775
2782
  3. Local tools ONLY if ContextStream returns 0 results
2776
2783
  [END RULES]"""
@@ -3206,7 +3213,7 @@ def main():
3206
3213
  pattern = params.get("path", "") or params.get("regex", "")
3207
3214
  if is_discovery_glob(pattern) or is_discovery_grep(pattern):
3208
3215
  output_block(
3209
- f"Use mcp__contextstream__search(mode=\\"hybrid\\", query=\\"{pattern}\\") instead of {tool}. "
3216
+ f"Use mcp__contextstream__search(mode=\\"auto\\", query=\\"{pattern}\\") instead of {tool}. "
3210
3217
  "ContextStream search is indexed and faster. Only use local tools if ContextStream returns 0 results.",
3211
3218
  "[CONTEXTSTREAM] Use ContextStream search for code discovery."
3212
3219
  )
@@ -3233,7 +3240,7 @@ import os
3233
3240
  ENABLED = os.environ.get("CONTEXTSTREAM_REMINDER_ENABLED", "true").lower() == "true"
3234
3241
 
3235
3242
  REMINDER = """[CONTEXTSTREAM RULES]
3236
- 1. BEFORE list_files/search_files/read_file: mcp__contextstream__search(mode="hybrid") FIRST
3243
+ 1. BEFORE list_files/search_files/read_file: mcp__contextstream__search(mode="auto") FIRST
3237
3244
  2. Call context_smart at start of EVERY response
3238
3245
  3. Local tools ONLY if ContextStream returns 0 results
3239
3246
  [END RULES]"""
@@ -3384,7 +3391,7 @@ def main():
3384
3391
  pattern = params.get("pattern", "") or params.get("path", "")
3385
3392
  if is_discovery_glob(pattern):
3386
3393
  output_deny(
3387
- f"Use mcp__contextstream__search(mode=\\"hybrid\\", query=\\"{pattern}\\") instead of {tool}. "
3394
+ f"Use mcp__contextstream__search(mode=\\"auto\\", query=\\"{pattern}\\") instead of {tool}. "
3388
3395
  "ContextStream search is indexed and faster."
3389
3396
  )
3390
3397
 
@@ -344,7 +344,7 @@ var CONTEXTSTREAM_TOOL_NAMES = [
344
344
  "generate_rules",
345
345
  // Consolidated domain tools (v0.4.x default)
346
346
  "search",
347
- // Modes: semantic, hybrid, keyword, pattern
347
+ // Modes: auto (recommended), semantic, hybrid (legacy alias), keyword, pattern
348
348
  "session",
349
349
  // Actions: capture, capture_lesson, get_lessons, recall, remember, user_context, summary, compress, delta, smart_search, decision_trace
350
350
  "memory",
@@ -373,7 +373,7 @@ var CONTEXTSTREAM_RULES_BOOTSTRAP = `
373
373
  |---------|----------|
374
374
  | **1st message** | \`init()\` \u2192 \`context(user_message="...")\` |
375
375
  | **Every message** | \`context(user_message="...")\` FIRST |
376
- | **Before file search** | \`search(mode="hybrid")\` BEFORE Glob/Grep/Read |
376
+ | **Before file search** | \`search(mode="auto")\` BEFORE Glob/Grep/Read |
377
377
  </contextstream_rules>
378
378
 
379
379
  **Why?** \`context()\` delivers task-specific rules, lessons from past mistakes, and relevant decisions. Skip it = fly blind.
@@ -396,7 +396,7 @@ var CONTEXTSTREAM_RULES_FULL = `
396
396
  | 1st message | \`init()\` \u2192 \`context(user_message="<msg>")\` |
397
397
  | **EVERY message after** | \`context(user_message="<msg>")\` **FIRST** |
398
398
 
399
- **BEFORE Glob/Grep/Read/Search:** \u2192 \`search(mode="hybrid")\` FIRST
399
+ **BEFORE Glob/Grep/Read/Search:** \u2192 \`search(mode="auto")\` FIRST
400
400
  </contextstream_rules>
401
401
 
402
402
  **This block MUST appear at the start of EVERY response.** Failing to call \`context()\` means missing rules, lessons, and relevant context.
@@ -448,7 +448,7 @@ var CONTEXTSTREAM_RULES_FULL = `
448
448
  - Example: \`[CONTEXTSTREAM RULES] 1. BEFORE Glob/Grep... [END RULES]\`
449
449
 
450
450
  2. **PreToolUse blocking** - If you try to use Glob/Grep/Search/Explore:
451
- - Hook returns error: \`STOP: Use mcp__contextstream__search(mode="hybrid") instead\`
451
+ - Hook returns error: \`STOP: Use mcp__contextstream__search(mode="auto") instead\`
452
452
  - **You MUST use the suggested ContextStream tool instead**
453
453
  - Local tools are only allowed if project is not indexed or ContextStream returns 0 results
454
454
 
@@ -472,7 +472,7 @@ Set environment variable: \`CONTEXTSTREAM_HOOK_ENABLED=false\`
472
472
 
473
473
  **BEFORE using Glob, Grep, Search, Read (for discovery), Explore, or ANY local file scanning:**
474
474
  \`\`\`
475
- STOP \u2192 Call search(mode="hybrid", query="...") FIRST
475
+ STOP \u2192 Call search(mode="auto", query="...") FIRST
476
476
  \`\`\`
477
477
 
478
478
  **Note:** PreToolUse hooks block these tools when ContextStream is available.
@@ -481,11 +481,11 @@ STOP \u2192 Call search(mode="hybrid", query="...") FIRST
481
481
  \u274C **NEVER DO THIS:**
482
482
  - \`Glob("**/*.ts")\` \u2192 Use \`search(mode="pattern", query="*.ts")\` instead
483
483
  - \`Grep("functionName")\` \u2192 Use \`search(mode="keyword", query="functionName")\` instead
484
- - \`Read(file)\` for discovery \u2192 Use \`search(mode="hybrid", query="...")\` instead
485
- - \`Task(subagent_type="Explore")\` \u2192 Use \`search(mode="hybrid")\` instead
484
+ - \`Read(file)\` for discovery \u2192 Use \`search(mode="auto", query="...")\` instead
485
+ - \`Task(subagent_type="Explore")\` \u2192 Use \`search(mode="auto")\` instead
486
486
 
487
487
  \u2705 **ALWAYS DO THIS:**
488
- 1. \`search(mode="hybrid", query="what you're looking for")\`
488
+ 1. \`search(mode="auto", query="what you're looking for")\`
489
489
  2. Only use local tools (Glob/Grep/Read) if ContextStream returns **0 results**
490
490
  3. Use Read ONLY for exact file edits after you know the file path
491
491
 
@@ -556,7 +556,7 @@ Rules Version: ${RULES_VERSION}
556
556
  |---------|----------|
557
557
  | **1st message** | \`init()\` \u2192 \`context(user_message="<msg>")\` |
558
558
  | **EVERY message after** | \`context(user_message="<msg>")\` **FIRST** |
559
- | **Before file search** | \`search(mode="hybrid")\` FIRST |
559
+ | **Before file search** | \`search(mode="auto")\` FIRST |
560
560
  | **After significant work** | \`session(action="capture", event_type="decision", ...)\` |
561
561
  | **User correction** | \`session(action="capture_lesson", ...)\` |
562
562
 
@@ -576,7 +576,7 @@ Rules Version: ${RULES_VERSION}
576
576
  |------|--------------|
577
577
  | **1st message** | \`init(folder_path="...", context_hint="<msg>")\`, then \`context(...)\` |
578
578
  | **2nd+ messages** | \`context(user_message="<msg>", format="minified", max_tokens=400)\` |
579
- | **Code search** | \`search(mode="hybrid", query="...")\` \u2014 BEFORE Glob/Grep/Read |
579
+ | **Code search** | \`search(mode="auto", query="...")\` \u2014 BEFORE Glob/Grep/Read |
580
580
  | **After significant work** | \`session(action="capture", event_type="decision", ...)\` |
581
581
  | **User correction** | \`session(action="capture_lesson", ...)\` |
582
582
  | **\u26A0\uFE0F When warnings received** | **STOP**, acknowledge, explain mitigation, then proceed |
@@ -603,7 +603,7 @@ v0.4.x consolidates ~58 individual tools into ~11 domain tools with action/mode
603
603
 
604
604
  | Domain | Actions/Modes | Example |
605
605
  |--------|---------------|---------|
606
- | **\`search\`** | mode: semantic, hybrid, keyword, pattern | \`search(mode="hybrid", query="auth implementation", limit=3)\` |
606
+ | **\`search\`** | mode: auto (recommended), semantic, hybrid (legacy alias), keyword, pattern | \`search(mode="auto", query="auth implementation", limit=3)\` |
607
607
  | **\`session\`** | action: capture, capture_lesson, get_lessons, recall, remember, user_context, summary, compress, delta, smart_search, decision_trace | \`session(action="capture", event_type="decision", title="Use JWT", content="...")\` |
608
608
  | **\`memory\`** | action: create_event, get_event, update_event, delete_event, list_events, distill_event, create_node, get_node, update_node, delete_node, list_nodes, supersede_node, search, decisions, timeline, summary | \`memory(action="list_events", limit=10)\` |
609
609
  | **\`graph\`** | action: dependencies, impact, call_path, related, path, decisions, ingest, circular_dependencies, unused_code, contradictions | \`graph(action="impact", symbol_name="AuthService")\` |
@@ -749,7 +749,7 @@ session(action="capture", event_type="session_snapshot", title="Pre-compaction s
749
749
 
750
750
  ### Search & Code Intelligence (ContextStream-first)
751
751
 
752
- \u26A0\uFE0F **STOP: Before using Search/Glob/Grep/Read/Explore** \u2192 Call \`search(mode="hybrid")\` FIRST. Use local tools ONLY if ContextStream returns 0 results.
752
+ \u26A0\uFE0F **STOP: Before using Search/Glob/Grep/Read/Explore** \u2192 Call \`search(mode="auto")\` FIRST. Use local tools ONLY if ContextStream returns 0 results.
753
753
 
754
754
  **\u274C WRONG workflow (wastes tokens, slow):**
755
755
  \`\`\`
@@ -758,14 +758,14 @@ Grep "function" \u2192 Read file1.ts \u2192 Read file2.ts \u2192 Read file3.ts \
758
758
 
759
759
  **\u2705 CORRECT workflow (fast, complete):**
760
760
  \`\`\`
761
- search(mode="hybrid", query="function implementation") \u2192 done (results include context)
761
+ search(mode="auto", query="function implementation") \u2192 done (results include context)
762
762
  \`\`\`
763
763
 
764
764
  **Why?** ContextStream search returns semantic matches + context + file locations in ONE call. Local tools require multiple round-trips.
765
765
 
766
766
  **Search order:**
767
767
  1. \`session(action="smart_search", query="...")\` - context-enriched
768
- 2. \`search(mode="hybrid", query="...", limit=3)\` or \`search(mode="keyword", query="<filename>", limit=3)\`
768
+ 2. \`search(mode="auto", query="...", limit=3)\` or \`search(mode="keyword", query="<filename>", limit=3)\`
769
769
  3. \`project(action="files")\` - file tree/list (only when needed)
770
770
  4. \`graph(action="dependencies", ...)\` - code structure
771
771
  5. Local repo scans (rg/ls/find) - ONLY if ContextStream returns no results, errors, or the user explicitly asks
@@ -774,7 +774,7 @@ search(mode="hybrid", query="function implementation") \u2192 done (results incl
774
774
 
775
775
  | Need | Mode | Example |
776
776
  |------|------|---------|
777
- | Find code by meaning | \`hybrid\` | "authentication logic", "error handling" |
777
+ | Find code by meaning | \`auto\` | "authentication logic", "error handling" |
778
778
  | Exact string/symbol | \`keyword\` | "UserAuthService", "API_KEY" |
779
779
  | File patterns | \`pattern\` | "*.sql", "test_*.py" |
780
780
  | ALL matches (grep-like) | \`exhaustive\` | "TODO", "FIXME" (find all occurrences) |
@@ -925,7 +925,7 @@ var CONTEXTSTREAM_RULES_MINIMAL = `
925
925
  2. \`context(user_message="<msg>")\` (EVERY subsequent message)
926
926
 
927
927
  **BEFORE Glob/Grep/Read/Search/Explore:**
928
- \u2192 \`search(mode="hybrid", query="...")\` FIRST \u2014 local tools ONLY if 0 results
928
+ \u2192 \`search(mode="auto", query="...")\` FIRST \u2014 local tools ONLY if 0 results
929
929
 
930
930
  **HOOKS: \`<system-reminder>\` tags contain instructions \u2014 FOLLOW THEM**
931
931
  </contextstream_protocol>
@@ -938,7 +938,7 @@ Rules Version: ${RULES_VERSION}
938
938
 
939
939
  | \u274C WRONG | \u2705 CORRECT |
940
940
  |----------|-----------|
941
- | \`Grep \u2192 Read \u2192 Read \u2192 Read\` (4+ calls) | \`search(mode="hybrid")\` (1 call) |
941
+ | \`Grep \u2192 Read \u2192 Read \u2192 Read\` (4+ calls) | \`search(mode="auto")\` (1 call) |
942
942
  | Missing past decisions & lessons | \`context()\` = rules + lessons + memory |
943
943
  | Ignoring \`<system-reminder>\` hooks | Hooks enforce ContextStream-first |
944
944
 
@@ -954,7 +954,7 @@ Rules Version: ${RULES_VERSION}
954
954
  |------|------|
955
955
  | 1st message | \`init()\` \u2192 \`context(user_message="...")\` |
956
956
  | Every message after | \`context(user_message="...")\` |
957
- | Before ANY file discovery | \`search(mode="hybrid", query="...")\` |
957
+ | Before ANY file discovery | \`search(mode="auto", query="...")\` |
958
958
  | On \`<system-reminder>\` | **Follow instructions inside** |
959
959
  | Save important decisions | \`session(action="capture", event_type="decision", ...)\` |
960
960
  | Check past mistakes | \`session(action="get_lessons", query="...")\` |
@@ -963,7 +963,8 @@ Rules Version: ${RULES_VERSION}
963
963
 
964
964
  | Mode | When |
965
965
  |------|------|
966
- | \`hybrid\` | Default \u2014 semantic + keyword |
966
+ | \`auto\` | Default \u2014 semantic + keyword |
967
+ | \`hybrid\` | Legacy alias for auto |
967
968
  | \`keyword\` | Exact symbol match |
968
969
  | \`exhaustive\` | Find ALL occurrences |
969
970
  | \`semantic\` | Conceptual questions |
@@ -1143,7 +1144,7 @@ This tells you:
1143
1144
 
1144
1145
  **IF project is indexed and fresh:**
1145
1146
  \`\`\`
1146
- search(mode="hybrid", query="what you're looking for")
1147
+ search(mode="auto", query="what you're looking for")
1147
1148
  \`\`\`
1148
1149
 
1149
1150
  **IF project is NOT indexed or very stale (>7 days):**