@nex-ai/nex 0.1.17 → 0.1.19

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.
Files changed (69) hide show
  1. package/README.md +42 -23
  2. package/dist/commands/integrate.js +11 -2
  3. package/dist/commands/integrate.js.map +1 -1
  4. package/dist/commands/setup.d.ts +5 -4
  5. package/dist/commands/setup.js +141 -43
  6. package/dist/commands/setup.js.map +1 -1
  7. package/dist/lib/client.js +12 -1
  8. package/dist/lib/client.js.map +1 -1
  9. package/dist/lib/file-scanner.d.ts +1 -1
  10. package/dist/lib/file-scanner.js +4 -2
  11. package/dist/lib/file-scanner.js.map +1 -1
  12. package/dist/lib/installers.d.ts +62 -5
  13. package/dist/lib/installers.js +373 -34
  14. package/dist/lib/installers.js.map +1 -1
  15. package/dist/lib/platform-detect.d.ts +7 -0
  16. package/dist/lib/platform-detect.js +150 -8
  17. package/dist/lib/platform-detect.js.map +1 -1
  18. package/dist/lib/project-config.js +1 -1
  19. package/dist/plugin/adapters/cline-capture.d.ts +7 -0
  20. package/dist/plugin/adapters/cline-capture.js +25 -0
  21. package/dist/plugin/adapters/cline-capture.js.map +1 -0
  22. package/dist/plugin/adapters/cline-recall.d.ts +7 -0
  23. package/dist/plugin/adapters/cline-recall.js +30 -0
  24. package/dist/plugin/adapters/cline-recall.js.map +1 -0
  25. package/dist/plugin/adapters/cline-task-start.d.ts +7 -0
  26. package/dist/plugin/adapters/cline-task-start.js +30 -0
  27. package/dist/plugin/adapters/cline-task-start.js.map +1 -0
  28. package/dist/plugin/adapters/cursor-recall.d.ts +7 -0
  29. package/dist/plugin/adapters/cursor-recall.js +31 -0
  30. package/dist/plugin/adapters/cursor-recall.js.map +1 -0
  31. package/dist/plugin/adapters/cursor-session-start.d.ts +7 -0
  32. package/dist/plugin/adapters/cursor-session-start.js +30 -0
  33. package/dist/plugin/adapters/cursor-session-start.js.map +1 -0
  34. package/dist/plugin/adapters/cursor-stop.d.ts +7 -0
  35. package/dist/plugin/adapters/cursor-stop.js +25 -0
  36. package/dist/plugin/adapters/cursor-stop.js.map +1 -0
  37. package/dist/plugin/adapters/windsurf-capture.d.ts +7 -0
  38. package/dist/plugin/adapters/windsurf-capture.js +25 -0
  39. package/dist/plugin/adapters/windsurf-capture.js.map +1 -0
  40. package/dist/plugin/adapters/windsurf-recall.d.ts +7 -0
  41. package/dist/plugin/adapters/windsurf-recall.js +31 -0
  42. package/dist/plugin/adapters/windsurf-recall.js.map +1 -0
  43. package/dist/plugin/auto-capture.js +5 -106
  44. package/dist/plugin/auto-capture.js.map +1 -1
  45. package/dist/plugin/auto-recall.js +5 -79
  46. package/dist/plugin/auto-recall.js.map +1 -1
  47. package/dist/plugin/auto-session-start.d.ts +0 -3
  48. package/dist/plugin/auto-session-start.js +8 -114
  49. package/dist/plugin/auto-session-start.js.map +1 -1
  50. package/dist/plugin/shared.d.ts +38 -0
  51. package/dist/plugin/shared.js +241 -0
  52. package/dist/plugin/shared.js.map +1 -0
  53. package/package.json +3 -1
  54. package/platform-plugins/continue-provider.ts +62 -0
  55. package/platform-plugins/kilocode-modes.yaml +17 -0
  56. package/platform-plugins/opencode-plugin.ts +103 -0
  57. package/platform-plugins/vscode-agent.md +34 -0
  58. package/platform-plugins/windsurf-workflows/nex-ask.md +10 -0
  59. package/platform-plugins/windsurf-workflows/nex-remember.md +10 -0
  60. package/platform-plugins/windsurf-workflows/nex-search.md +10 -0
  61. package/platform-rules/aider-conventions.md +38 -0
  62. package/platform-rules/cline-rules.md +34 -0
  63. package/platform-rules/continue-rules.md +34 -0
  64. package/platform-rules/cursor-rules.md +34 -0
  65. package/platform-rules/kilocode-rules.md +34 -0
  66. package/platform-rules/opencode-agents.md +38 -0
  67. package/platform-rules/vscode-instructions.md +38 -0
  68. package/platform-rules/windsurf-rules.md +34 -0
  69. package/platform-rules/zed-rules.md +38 -0
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Shared hook logic — platform-agnostic recall, capture, and session-start.
3
+ *
4
+ * Extracted from auto-recall.ts, auto-capture.ts, auto-session-start.ts
5
+ * so adapters for Cursor, Windsurf, Cline, etc. can reuse the same logic
6
+ * without duplicating filter/client/format code.
7
+ */
8
+ import { loadConfig, loadScanConfig, ConfigError, isHookEnabled } from "./config.js";
9
+ import { NexClient } from "./nex-client.js";
10
+ import { formatNexContext } from "./context-format.js";
11
+ import { captureFilter } from "./capture-filter.js";
12
+ import { SessionStore } from "./session-store.js";
13
+ import { shouldRecall, recordRecall } from "./recall-filter.js";
14
+ import { RateLimiter } from "./rate-limiter.js";
15
+ import { scanAndIngest } from "./file-scanner.js";
16
+ import { ingestContextFiles } from "./context-files.js";
17
+ import { readManifest, writeManifest, isChanged, markIngested } from "./file-manifest.js";
18
+ import { readdirSync, statSync, readFileSync } from "node:fs";
19
+ import { join, extname } from "node:path";
20
+ const sessions = new SessionStore();
21
+ // ── Recall ──────────────────────────────────────────────────────────────
22
+ /**
23
+ * Run recall logic: filter prompt → query Nex /ask → return formatted context.
24
+ * Returns null if recall is skipped or fails.
25
+ */
26
+ export async function doRecall(prompt, sessionKey) {
27
+ if (!isHookEnabled("recall"))
28
+ return null;
29
+ const trimmed = prompt?.trim();
30
+ if (!trimmed || trimmed.length < 5)
31
+ return null;
32
+ if (trimmed.startsWith("/"))
33
+ return null;
34
+ const isFirst = sessionKey ? !sessions.get(sessionKey) : true;
35
+ const decision = shouldRecall(trimmed, isFirst);
36
+ if (!decision.shouldRecall)
37
+ return null;
38
+ const cfg = loadConfig();
39
+ const client = new NexClient(cfg.apiKey, cfg.baseUrl);
40
+ const nexSessionId = sessionKey ? sessions.get(sessionKey) : undefined;
41
+ const result = await client.ask(trimmed, nexSessionId, 10_000);
42
+ if (!result.answer)
43
+ return null;
44
+ if (result.session_id && sessionKey) {
45
+ sessions.set(sessionKey, result.session_id);
46
+ }
47
+ recordRecall(result.session_id);
48
+ const entityCount = result.entity_references?.length ?? 0;
49
+ const context = formatNexContext({
50
+ answer: result.answer,
51
+ entityCount,
52
+ sessionId: result.session_id,
53
+ });
54
+ return { context, nexSessionId: result.session_id };
55
+ }
56
+ // ── Capture ─────────────────────────────────────────────────────────────
57
+ const INGEST_TIMEOUT_MS = 3_000;
58
+ const MAX_PLAN_FILES = 2;
59
+ /**
60
+ * Run capture logic: filter message → ingest to Nex + scan plan files.
61
+ */
62
+ export async function doCapture(input) {
63
+ if (!isHookEnabled("capture"))
64
+ return;
65
+ let cfg;
66
+ try {
67
+ cfg = loadConfig();
68
+ }
69
+ catch {
70
+ return;
71
+ }
72
+ const client = new NexClient(cfg.apiKey, cfg.baseUrl);
73
+ const rateLimiter = new RateLimiter();
74
+ // Conversation capture
75
+ const message = input.message?.trim();
76
+ if (message) {
77
+ const filterResult = captureFilter(message);
78
+ if (!filterResult.skipped) {
79
+ if (rateLimiter.canProceed()) {
80
+ try {
81
+ await client.ingest(filterResult.text, "claude-code-conversation", INGEST_TIMEOUT_MS);
82
+ }
83
+ catch (err) {
84
+ process.stderr.write(`[nex-capture] Ingest failed: ${err instanceof Error ? err.message : String(err)}\n`);
85
+ }
86
+ }
87
+ }
88
+ }
89
+ // Plan file ingestion
90
+ const plansDir = input.planDir ?? join(process.cwd(), ".claude", "plans");
91
+ try {
92
+ await ingestPlanFiles(client, rateLimiter, plansDir);
93
+ }
94
+ catch (err) {
95
+ process.stderr.write(`[nex-capture] Plan file scan error: ${err instanceof Error ? err.message : String(err)}\n`);
96
+ }
97
+ }
98
+ async function ingestPlanFiles(client, rateLimiter, plansDir) {
99
+ const scanConfig = loadScanConfig();
100
+ if (!scanConfig.enabled)
101
+ return;
102
+ let entries;
103
+ try {
104
+ entries = readdirSync(plansDir, { withFileTypes: true });
105
+ }
106
+ catch {
107
+ return;
108
+ }
109
+ const manifest = readManifest();
110
+ let ingested = 0;
111
+ for (const entry of entries) {
112
+ if (ingested >= MAX_PLAN_FILES)
113
+ break;
114
+ if (!entry.isFile())
115
+ continue;
116
+ if (extname(entry.name).toLowerCase() !== ".md")
117
+ continue;
118
+ const fullPath = join(plansDir, entry.name);
119
+ try {
120
+ const stat = statSync(fullPath);
121
+ if (!isChanged(fullPath, stat, manifest))
122
+ continue;
123
+ if (!rateLimiter.canProceed())
124
+ break;
125
+ let content = readFileSync(fullPath, "utf-8");
126
+ if (content.length > 100_000) {
127
+ content = content.slice(0, 100_000) + "\n[...truncated]";
128
+ }
129
+ const context = `claude-code-plan:${entry.name}`;
130
+ await client.ingest(content, context, INGEST_TIMEOUT_MS);
131
+ markIngested(fullPath, stat, context, manifest);
132
+ ingested++;
133
+ }
134
+ catch {
135
+ // skip individual file errors
136
+ }
137
+ }
138
+ if (ingested > 0)
139
+ writeManifest(manifest);
140
+ }
141
+ // ── Session Start ───────────────────────────────────────────────────────
142
+ const SESSION_START_QUERY = "Summarize the key active context, recent interactions, and important updates for this user.";
143
+ /**
144
+ * Run session-start logic: scan files → query Nex baseline → return context.
145
+ * Returns null if disabled. Returns registrationPrompt if no API key.
146
+ */
147
+ export async function doSessionStart(source, sessionKey) {
148
+ if (!isHookEnabled("session_start"))
149
+ return null;
150
+ let cfg;
151
+ try {
152
+ cfg = loadConfig();
153
+ }
154
+ catch (err) {
155
+ if (err instanceof ConfigError) {
156
+ // No API key — return registration instructions
157
+ return {
158
+ context: "",
159
+ registrationPrompt: buildRegistrationPrompt(),
160
+ };
161
+ }
162
+ return null;
163
+ }
164
+ const client = new NexClient(cfg.apiKey, cfg.baseUrl);
165
+ const contextParts = [];
166
+ // File scan on startup or clear
167
+ const shouldScan = source === "startup" || source === "clear";
168
+ if (shouldScan) {
169
+ const rateLimiter = new RateLimiter();
170
+ const cwd = process.cwd();
171
+ try {
172
+ const ctxResult = await ingestContextFiles(client, rateLimiter, cwd);
173
+ if (ctxResult.ingested > 0) {
174
+ contextParts.push(`[Context files: ${ctxResult.ingested} ingested (${ctxResult.files.join(", ")})]`);
175
+ }
176
+ }
177
+ catch {
178
+ // non-fatal
179
+ }
180
+ try {
181
+ const scanConfig = loadScanConfig();
182
+ if (scanConfig.enabled) {
183
+ const scanResult = await scanAndIngest(client, rateLimiter, cwd, scanConfig);
184
+ if (scanResult.ingested > 0) {
185
+ contextParts.push(`[File scan: ${scanResult.ingested} file${scanResult.ingested === 1 ? "" : "s"} ingested, ${scanResult.scanned} scanned]`);
186
+ }
187
+ }
188
+ }
189
+ catch {
190
+ // non-fatal
191
+ }
192
+ }
193
+ const result = await client.ask(SESSION_START_QUERY, undefined, 10_000);
194
+ if (!result.answer && contextParts.length === 0)
195
+ return null;
196
+ if (result.session_id && sessionKey) {
197
+ sessions.set(sessionKey, result.session_id);
198
+ }
199
+ recordRecall(result.session_id);
200
+ const entityCount = result.entity_references?.length ?? 0;
201
+ const context = formatNexContext({
202
+ answer: result.answer,
203
+ entityCount,
204
+ sessionId: result.session_id,
205
+ });
206
+ const fullContext = contextParts.length > 0
207
+ ? `${context}\n${contextParts.join("\n")}`
208
+ : context;
209
+ return { context: fullContext, nexSessionId: result.session_id };
210
+ }
211
+ function buildRegistrationPrompt() {
212
+ return [
213
+ "[Nex Memory Plugin] No API key configured. Registration is required to enable persistent memory.",
214
+ "",
215
+ "IMPORTANT: Before proceeding with the user's request, you must set up Nex memory:",
216
+ "1. Ask the user for their email address to register for a Nex account",
217
+ "2. Run: nex register --email <email>",
218
+ "3. Then run: nex setup",
219
+ "",
220
+ "Keep it brief — just ask for the email and register. No restart needed after registration.",
221
+ ].join("\n");
222
+ }
223
+ // ── Helpers ─────────────────────────────────────────────────────────────
224
+ /** Read stdin as a string (shared across all hook scripts). */
225
+ export async function readStdin() {
226
+ const chunks = [];
227
+ for await (const chunk of process.stdin) {
228
+ chunks.push(chunk);
229
+ }
230
+ return Buffer.concat(chunks).toString("utf-8");
231
+ }
232
+ /** Wrap output in Claude Code hookSpecificOutput format. */
233
+ export function claudeCodeOutput(hookEventName, additionalContext) {
234
+ return JSON.stringify({
235
+ hookSpecificOutput: {
236
+ hookEventName,
237
+ additionalContext,
238
+ },
239
+ });
240
+ }
241
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/plugin/shared.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nex-ai/nex",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "Nex CLI provides organizational context & memory to AI agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,6 +9,8 @@
9
9
  "files": [
10
10
  "dist",
11
11
  "plugin-commands",
12
+ "platform-rules",
13
+ "platform-plugins",
12
14
  "README.md"
13
15
  ],
14
16
  "scripts": {
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Nex context provider for Continue.dev
3
+ *
4
+ * Add this to your ~/.continue/config.ts to enable @nex context:
5
+ *
6
+ * import { nexProvider } from "./.plugins/nex-provider";
7
+ * export default { contextProviders: [nexProvider] };
8
+ *
9
+ * This file is copied to ~/.continue/.plugins/nex-provider.ts by `nex setup`.
10
+ */
11
+
12
+ import { readFileSync } from "node:fs";
13
+ import { join } from "node:path";
14
+ import { homedir } from "node:os";
15
+
16
+ function loadApiKey(): string | null {
17
+ try {
18
+ const raw = readFileSync(join(homedir(), ".nex-mcp.json"), "utf-8");
19
+ return JSON.parse(raw).api_key ?? null;
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+
25
+ export const nexProvider = {
26
+ title: "nex",
27
+ displayTitle: "Nex Context",
28
+ description: "Query organizational context, CRM, and memory from Nex",
29
+ type: "query" as const,
30
+
31
+ async getContextItems(query: string) {
32
+ const apiKey = loadApiKey();
33
+ if (!apiKey || !query.trim()) return [];
34
+
35
+ try {
36
+ const baseUrl = process.env.NEX_API_BASE_URL ?? "https://app.nex.ai";
37
+ const res = await fetch(`${baseUrl}/api/developers/v1/context/ask`, {
38
+ method: "POST",
39
+ headers: {
40
+ Authorization: `Bearer ${apiKey}`,
41
+ "Content-Type": "application/json",
42
+ },
43
+ body: JSON.stringify({ query }),
44
+ signal: AbortSignal.timeout(10_000),
45
+ });
46
+
47
+ if (!res.ok) return [];
48
+ const data = (await res.json()) as { answer?: string };
49
+ if (!data.answer) return [];
50
+
51
+ return [
52
+ {
53
+ name: "Nex Context",
54
+ description: `Results for: ${query}`,
55
+ content: data.answer,
56
+ },
57
+ ];
58
+ } catch {
59
+ return [];
60
+ }
61
+ },
62
+ };
@@ -0,0 +1,17 @@
1
+ customModes:
2
+ - slug: nex-crm
3
+ name: "Nex CRM"
4
+ roleDefinition: >
5
+ You are a CRM and organizational memory assistant powered by Nex.
6
+ You help users query their knowledge graph, CRM records, meetings,
7
+ communications, and organizational context. Use Nex MCP tools for
8
+ all queries about people, companies, deals, meetings, and emails.
9
+ customInstructions: >
10
+ Available Nex MCP tools: nex_ask (natural language query),
11
+ nex_remember (store information), nex_search (CRM lookup),
12
+ nex_list_integrations (check connections), nex_connect_integration (OAuth).
13
+ Always use nex_ask for knowledge queries. Use nex_search for name lookups.
14
+ Present results clearly with key entities highlighted.
15
+ groups:
16
+ - read
17
+ - mcp
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Nex plugin for OpenCode — organizational context & memory.
3
+ *
4
+ * This file is copied to .opencode/plugins/nex.ts by `nex setup`.
5
+ * OpenCode's bun runtime resolves imports at load time.
6
+ *
7
+ * Provides:
8
+ * - Session lifecycle hooks (context loading on session create)
9
+ * - Context preservation during compaction
10
+ */
11
+
12
+ import { readFileSync } from "node:fs";
13
+ import { join } from "node:path";
14
+ import { homedir } from "node:os";
15
+
16
+ // Read API key from shared Nex config
17
+ function loadApiKey(): string | null {
18
+ try {
19
+ const raw = readFileSync(join(homedir(), ".nex-mcp.json"), "utf-8");
20
+ const config = JSON.parse(raw);
21
+ return config.api_key ?? null;
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
26
+
27
+ async function nexAsk(query: string, apiKey: string): Promise<string> {
28
+ const baseUrl = process.env.NEX_API_BASE_URL ?? "https://app.nex.ai";
29
+ const res = await fetch(`${baseUrl}/api/developers/v1/context/ask`, {
30
+ method: "POST",
31
+ headers: {
32
+ Authorization: `Bearer ${apiKey}`,
33
+ "Content-Type": "application/json",
34
+ },
35
+ body: JSON.stringify({ query }),
36
+ signal: AbortSignal.timeout(10_000),
37
+ });
38
+ if (!res.ok) return "";
39
+ const data = await res.json() as { answer?: string };
40
+ return data.answer ?? "";
41
+ }
42
+
43
+ async function nexIngest(content: string, context: string, apiKey: string): Promise<void> {
44
+ const baseUrl = process.env.NEX_API_BASE_URL ?? "https://app.nex.ai";
45
+ await fetch(`${baseUrl}/api/developers/v1/context/text`, {
46
+ method: "POST",
47
+ headers: {
48
+ Authorization: `Bearer ${apiKey}`,
49
+ "Content-Type": "application/json",
50
+ },
51
+ body: JSON.stringify({ content, context }),
52
+ signal: AbortSignal.timeout(5_000),
53
+ });
54
+ }
55
+
56
+ let cachedContext = "";
57
+
58
+ export default {
59
+ name: "nex",
60
+
61
+ async "session.created"() {
62
+ const apiKey = loadApiKey();
63
+ if (!apiKey) return;
64
+
65
+ try {
66
+ const answer = await nexAsk(
67
+ "Summarize the key active context, recent interactions, and important updates for this user.",
68
+ apiKey,
69
+ );
70
+ if (answer) {
71
+ cachedContext = `<nex-context>\n${answer}\n</nex-context>`;
72
+ }
73
+ } catch {
74
+ // graceful degradation
75
+ }
76
+
77
+ return cachedContext ? { context: cachedContext } : undefined;
78
+ },
79
+
80
+ async "experimental.session.compacting"(_input: unknown, output: { context: string[] }) {
81
+ if (cachedContext) {
82
+ output.context.push(cachedContext);
83
+ }
84
+ },
85
+
86
+ async "session.completed"(_input: { messages?: Array<{ role: string; content: string }> }) {
87
+ const apiKey = loadApiKey();
88
+ if (!apiKey) return;
89
+
90
+ // Capture last assistant message
91
+ const messages = (_input as any)?.messages;
92
+ if (!Array.isArray(messages)) return;
93
+
94
+ const lastAssistant = [...messages].reverse().find((m) => m.role === "assistant");
95
+ if (!lastAssistant?.content || lastAssistant.content.length < 20) return;
96
+
97
+ try {
98
+ await nexIngest(lastAssistant.content.slice(0, 50_000), "opencode-conversation", apiKey);
99
+ } catch {
100
+ // graceful degradation
101
+ }
102
+ },
103
+ };
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: nex
3
+ description: "Query organizational context, CRM, meetings, and memory via Nex"
4
+ tools:
5
+ - nex
6
+ ---
7
+
8
+ You are the Nex agent. You help users query their organizational knowledge, CRM records, meetings, and communications.
9
+
10
+ ## Available MCP Tools
11
+
12
+ - **nex_ask** — Query the knowledge graph with natural language (people, companies, deals, meetings, emails)
13
+ - **nex_remember** — Store information for future recall across all connected platforms
14
+ - **nex_search** — Search CRM records by name (people, companies, deals)
15
+ - **nex_list_integrations** — Check connected data sources (Gmail, Slack, Salesforce, etc.)
16
+ - **nex_connect_integration** — Connect a new data source via OAuth
17
+
18
+ ## When to Use
19
+
20
+ Use Nex tools when the user asks about:
21
+ - People, companies, organizations, or contacts
22
+ - Deals, opportunities, or sales pipeline
23
+ - Meetings, calendar events, or scheduling
24
+ - Emails, messages, or communications
25
+ - Organizational context, history, or relationships
26
+ - Storing notes or information for later
27
+
28
+ ## Guidelines
29
+
30
+ - Always use `nex_ask` for natural language queries about organizational knowledge
31
+ - Use `nex_search` when looking up specific CRM records by name
32
+ - Use `nex_remember` to store meeting notes, decisions, or important context
33
+ - Present results clearly with key entities highlighted
34
+ - If no results are found, suggest the user connect relevant data sources
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: nex-ask
3
+ description: Ask Nex a question about organizational context, people, companies, deals, or meetings
4
+ ---
5
+
6
+ Use the Nex MCP tool `nex_ask` to answer the user's question about organizational context.
7
+
8
+ If the user provides a query, pass it directly. If not, ask what they'd like to know about their organizational context, CRM records, meetings, or communications.
9
+
10
+ Always present the response clearly, highlighting key entities (people, companies, deals) and any relevant dates or action items.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: nex-remember
3
+ description: Store information in Nex knowledge base for future recall
4
+ ---
5
+
6
+ Use the Nex MCP tool `nex_remember` to store the provided information in the user's knowledge base.
7
+
8
+ If the user provides content, ingest it directly. If not, ask what they'd like to remember.
9
+
10
+ Confirm what was stored and mention that it will be available for future recall across all connected platforms.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: nex-search
3
+ description: Search for CRM records (people, companies, deals) by name
4
+ ---
5
+
6
+ Use the Nex MCP tool `nex_search` to search for CRM records matching the user's query.
7
+
8
+ If the user provides a search term, use it directly. If not, ask what they're looking for.
9
+
10
+ Present results in a structured format showing name, type, and key details for each match.
@@ -0,0 +1,38 @@
1
+ # --- Nex Context & Memory ---
2
+
3
+ # Nex — Organizational Context & Memory
4
+
5
+ Nex provides your AI agent with real-time organizational knowledge — contacts, deals, meetings, emails, notes, and more — via MCP tools.
6
+
7
+ ## MCP Tools Available
8
+
9
+ ### `nex_ask` — AI-powered context query (recommended)
10
+ Use for natural language questions about organizational context.
11
+ Examples: "what's the latest on the Acme deal?", "when did I last talk to Sarah?"
12
+
13
+ ### `nex_remember` — Store information
14
+ Save notes, observations, meeting summaries, or any text to the knowledge base.
15
+ Examples: "remember that John prefers email over Slack", store meeting notes
16
+
17
+ ### `nex_search` — Fuzzy record lookup
18
+ Search CRM records (people, companies, deals) by name or keyword.
19
+ Use when looking up a specific named entity rather than asking a question.
20
+
21
+ ### `nex_list_integrations` — Check connected data sources
22
+ Shows which integrations (Gmail, Slack, Calendar, CRM) are connected and active.
23
+
24
+ ### `nex_connect_integration` — Connect a data source
25
+ Initiate OAuth connection for Gmail, Google Calendar, Outlook, Slack, Salesforce, HubSpot, or Attio.
26
+
27
+ ## When to Use Nex
28
+
29
+ When the user asks about:
30
+ - **People or companies** — contacts, relationships, org charts
31
+ - **Deals or opportunities** — status, history, next steps
32
+ - **Meetings or calls** — past conversations, upcoming schedules
33
+ - **Emails or messages** — communication history
34
+ - **Organizational context** — company knowledge, team notes, decisions
35
+
36
+ Always try `nex_ask` first for general queries. Use `nex_search` when you need to find a specific record by name.
37
+
38
+ # --- End Nex ---
@@ -0,0 +1,34 @@
1
+ # Nex — Organizational Context & Memory
2
+
3
+ Nex provides your AI agent with real-time organizational knowledge — contacts, deals, meetings, emails, notes, and more — via MCP tools.
4
+
5
+ ## MCP Tools Available
6
+
7
+ ### `nex_ask` — AI-powered context query (recommended)
8
+ Use for natural language questions about organizational context.
9
+ Examples: "what's the latest on the Acme deal?", "when did I last talk to Sarah?"
10
+
11
+ ### `nex_remember` — Store information
12
+ Save notes, observations, meeting summaries, or any text to the knowledge base.
13
+ Examples: "remember that John prefers email over Slack", store meeting notes
14
+
15
+ ### `nex_search` — Fuzzy record lookup
16
+ Search CRM records (people, companies, deals) by name or keyword.
17
+ Use when looking up a specific named entity rather than asking a question.
18
+
19
+ ### `nex_list_integrations` — Check connected data sources
20
+ Shows which integrations (Gmail, Slack, Calendar, CRM) are connected and active.
21
+
22
+ ### `nex_connect_integration` — Connect a data source
23
+ Initiate OAuth connection for Gmail, Google Calendar, Outlook, Slack, Salesforce, HubSpot, or Attio.
24
+
25
+ ## When to Use Nex
26
+
27
+ When the user asks about:
28
+ - **People or companies** — contacts, relationships, org charts
29
+ - **Deals or opportunities** — status, history, next steps
30
+ - **Meetings or calls** — past conversations, upcoming schedules
31
+ - **Emails or messages** — communication history
32
+ - **Organizational context** — company knowledge, team notes, decisions
33
+
34
+ Always try `nex_ask` first for general queries. Use `nex_search` when you need to find a specific record by name.
@@ -0,0 +1,34 @@
1
+ # Nex — Organizational Context & Memory
2
+
3
+ Nex provides your AI agent with real-time organizational knowledge — contacts, deals, meetings, emails, notes, and more — via MCP tools.
4
+
5
+ ## MCP Tools Available
6
+
7
+ ### `nex_ask` — AI-powered context query (recommended)
8
+ Use for natural language questions about organizational context.
9
+ Examples: "what's the latest on the Acme deal?", "when did I last talk to Sarah?"
10
+
11
+ ### `nex_remember` — Store information
12
+ Save notes, observations, meeting summaries, or any text to the knowledge base.
13
+ Examples: "remember that John prefers email over Slack", store meeting notes
14
+
15
+ ### `nex_search` — Fuzzy record lookup
16
+ Search CRM records (people, companies, deals) by name or keyword.
17
+ Use when looking up a specific named entity rather than asking a question.
18
+
19
+ ### `nex_list_integrations` — Check connected data sources
20
+ Shows which integrations (Gmail, Slack, Calendar, CRM) are connected and active.
21
+
22
+ ### `nex_connect_integration` — Connect a data source
23
+ Initiate OAuth connection for Gmail, Google Calendar, Outlook, Slack, Salesforce, HubSpot, or Attio.
24
+
25
+ ## When to Use Nex
26
+
27
+ When the user asks about:
28
+ - **People or companies** — contacts, relationships, org charts
29
+ - **Deals or opportunities** — status, history, next steps
30
+ - **Meetings or calls** — past conversations, upcoming schedules
31
+ - **Emails or messages** — communication history
32
+ - **Organizational context** — company knowledge, team notes, decisions
33
+
34
+ Always try `nex_ask` first for general queries. Use `nex_search` when you need to find a specific record by name.
@@ -0,0 +1,34 @@
1
+ # Nex — Organizational Context & Memory
2
+
3
+ Nex provides your AI agent with real-time organizational knowledge — contacts, deals, meetings, emails, notes, and more — via MCP tools.
4
+
5
+ ## MCP Tools Available
6
+
7
+ ### `nex_ask` — AI-powered context query (recommended)
8
+ Use for natural language questions about organizational context.
9
+ Examples: "what's the latest on the Acme deal?", "when did I last talk to Sarah?"
10
+
11
+ ### `nex_remember` — Store information
12
+ Save notes, observations, meeting summaries, or any text to the knowledge base.
13
+ Examples: "remember that John prefers email over Slack", store meeting notes
14
+
15
+ ### `nex_search` — Fuzzy record lookup
16
+ Search CRM records (people, companies, deals) by name or keyword.
17
+ Use when looking up a specific named entity rather than asking a question.
18
+
19
+ ### `nex_list_integrations` — Check connected data sources
20
+ Shows which integrations (Gmail, Slack, Calendar, CRM) are connected and active.
21
+
22
+ ### `nex_connect_integration` — Connect a data source
23
+ Initiate OAuth connection for Gmail, Google Calendar, Outlook, Slack, Salesforce, HubSpot, or Attio.
24
+
25
+ ## When to Use Nex
26
+
27
+ When the user asks about:
28
+ - **People or companies** — contacts, relationships, org charts
29
+ - **Deals or opportunities** — status, history, next steps
30
+ - **Meetings or calls** — past conversations, upcoming schedules
31
+ - **Emails or messages** — communication history
32
+ - **Organizational context** — company knowledge, team notes, decisions
33
+
34
+ Always try `nex_ask` first for general queries. Use `nex_search` when you need to find a specific record by name.