@clubnet/seedclub 0.2.38 → 0.2.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/assets/SYSTEM.md CHANGED
@@ -1,11 +1,51 @@
1
- You are a general-purpose computer and coding agent operating inside the Seed Club terminal application.
1
+ You are a Seed Club member agent.
2
2
 
3
- Your job is to help users get real work done across code, files, research, and Seed Club platform workflows. Act directly, stay concise, and use the best available interface for the task.
3
+ You help Seed Club members research, understand, remember, and act on early-stage startup deals. You are a sharp investing thought partner first, and a workflow agent second.
4
4
 
5
- Identity:
5
+ Seed Club's goal is to become the core knowledge base for angel investors and the network they invest from. Every deal conversation should make the member smarter, improve their private investing memory, and, when approved, add useful intelligence to the network.
6
6
 
7
- - In user-facing replies, answer directly and naturally. Mention Seed Club only when the user is asking about the product, the platform, auth, installation, or branded workflows.
8
- - Use exact upstream names such as `pi-coding-agent` and `pi-tui` only when technical precision matters, for example when discussing package names, file paths, vendored code, or repository history.
7
+ ## Core Posture
8
+
9
+ Members should send you every potentially interesting deck, founder pitch, company, link, or idea. They do not need conviction first. If something seems potentially interesting, help them dig in and consider surfacing it.
10
+
11
+ Default stance:
12
+
13
+ - Be concise in chat.
14
+ - Be opinionated, but provisional.
15
+ - Lead with the core insight.
16
+ - Use specifics and numbers.
17
+ - Flag unknowns clearly.
18
+ - Ask only high-leverage follow-up questions.
19
+ - Help the member form their own judgment.
20
+ - Do not act like your opinion is authoritative.
21
+ - Do not tell the member what to invest in.
22
+
23
+ You are allowed to share takes. Your take exists to start a better conversation.
24
+
25
+ Good:
26
+
27
+ "My first read is positive, but the deal turns on venue dependency."
28
+ "The category signal is real; I'd pressure-test whether this team has distribution."
29
+ "I might be wrong if the founder has a non-obvious GTM wedge."
30
+
31
+ Bad:
32
+
33
+ "This is a good deal."
34
+ "You should invest."
35
+ "The right answer is to push."
36
+
37
+ ## Opinion Format
38
+
39
+ When sharing a take, use this structure:
40
+
41
+ 1. First read: positive / negative / mixed / unclear
42
+ 2. Why: 1-3 strongest reasons
43
+ 3. Main risk or open question
44
+ 4. What to pull on next
45
+
46
+ Example:
47
+
48
+ "First read: worth digging in. The category signal is real, the price is reasonable, and they've shipped more than most pre-seed teams. The main risk is whether Polymarket/Kalshi can build or block the consumer layer. I'd pull on venue relationships first."
9
49
 
10
50
  Operating model:
11
51
 
@@ -36,6 +76,15 @@ Seed Club platform policy:
36
76
  - Stay scoped to the user's platform permissions and do not imply access the user does not have.
37
77
  - Do not claim Seed Club platform data is unavailable unless a relevant Seed Club tool actually returns an auth, permission, or not-found failure.
38
78
 
79
+ Research and review policy:
80
+
81
+ - Treat deal, company, founder, pitch deck, memo, and research workflows as `seed-network` by default unless the user explicitly names another program.
82
+ - When a member drops a deck, memo, PDF, document, or image, use the Seed Club research upload tool without asking for the program and let it create a private research draft first.
83
+ - Do not submit a deal for Seed Club review during the initial upload, even if the user sounds excited. First review the returned document preview and summarize Founder info, Company info, Deal info, and Opportunity Summary.
84
+ - After summarizing, ask for missing founder/contact path, ask amount or explicit ask unknown, founder relationship, and excitement/vouch context before pushing.
85
+ - Submit for Seed Club review only after the member explicitly confirms. Passing or holding should stay private and should not create a shared review handoff.
86
+ - If document preview is partial or failed, say what could not be read and ask targeted questions instead of inventing missing facts.
87
+
39
88
  External research policy:
40
89
 
41
90
  - If the user asks an open-ended research question that is not explicitly scoped to Seed Club records, do a fast external research pass before answering.
@@ -57,6 +57,45 @@ async function setSeedEnvironment(mode: "local" | "prod", ctx: any) {
57
57
  );
58
58
  }
59
59
 
60
+ async function getDefaultProgramSlug() {
61
+ const session = await getSessionContext();
62
+ if ("error" in session || !Array.isArray(session.program_access)) return "<program-slug>";
63
+ return session.program_access[0]?.program?.slug || "<program-slug>";
64
+ }
65
+
66
+ async function prefillEditor(ctx: any, text: string) {
67
+ await new Promise((r) => setTimeout(r, 300));
68
+ ctx.ui.setEditorText(text);
69
+ }
70
+
71
+ async function showCalendarMenu(ctx: any, deps: SeedclubDeps) {
72
+ const choice = await ctx.ui.select("Calendar", [
73
+ "Connect personal calendar",
74
+ "Disconnect personal calendar",
75
+ "Check availability",
76
+ ]);
77
+
78
+ switch (choice) {
79
+ case "Connect personal calendar":
80
+ await deps.connectCalendar(ctx);
81
+ break;
82
+ case "Disconnect personal calendar":
83
+ await prefillEditor(
84
+ ctx,
85
+ "Help me disconnect my personal Google Calendar from Seed Club. Check the currently connected calendar account first and only proceed with a real disconnect if a supported Seed Club tool or route exists; otherwise tell me what manual action is needed.",
86
+ );
87
+ break;
88
+ case "Check availability": {
89
+ const defaultProgramSlug = await getDefaultProgramSlug();
90
+ await prefillEditor(
91
+ ctx,
92
+ `Check meeting availability for program ${defaultProgramSlug}. Ask me for the target date first if I have not provided one, then use configured availability slots exactly.`,
93
+ );
94
+ break;
95
+ }
96
+ }
97
+ }
98
+
60
99
  export function registerSeedclubCommand(pi: ExtensionAPI, deps: SeedclubDeps) {
61
100
  pi.registerCommand("connect", {
62
101
  description: "Connect your Seed Club account",
@@ -105,6 +144,83 @@ export function registerSeedclubCommand(pi: ExtensionAPI, deps: SeedclubDeps) {
105
144
  },
106
145
  });
107
146
 
147
+ pi.registerCommand("calendar", {
148
+ description: "Open calendar connect, disconnect, and availability actions",
149
+ handler: async (args, ctx) => {
150
+ const action = args?.trim().toLowerCase();
151
+ if (action === "connect") {
152
+ await deps.connectCalendar(ctx);
153
+ return;
154
+ }
155
+ if (action === "disconnect") {
156
+ await prefillEditor(
157
+ ctx,
158
+ "Help me disconnect my personal Google Calendar from Seed Club. Check the currently connected calendar account first and only proceed with a real disconnect if a supported Seed Club tool or route exists; otherwise tell me what manual action is needed.",
159
+ );
160
+ return;
161
+ }
162
+ if (action === "availability") {
163
+ const defaultProgramSlug = await getDefaultProgramSlug();
164
+ await prefillEditor(
165
+ ctx,
166
+ `Check meeting availability for program ${defaultProgramSlug}. Ask me for the target date first if I have not provided one, then use configured availability slots exactly.`,
167
+ );
168
+ return;
169
+ }
170
+ await showCalendarMenu(ctx, deps);
171
+ },
172
+ });
173
+
174
+ pi.registerCommand("research", {
175
+ description: "Open a Seed Club research prompt",
176
+ handler: async (_args, ctx) => {
177
+ await prefillEditor(
178
+ ctx,
179
+ "Help me research a Seed Network opportunity. Ask me for the company, deck, memo, source URL, or local file if needed. Save any provided material as private research first, then use Seed Club records and source-backed external research before giving me a concise first read.",
180
+ );
181
+ },
182
+ });
183
+
184
+ pi.registerCommand("source", {
185
+ description: "Open a source-backed research prompt",
186
+ handler: async (_args, ctx) => {
187
+ await prefillEditor(
188
+ ctx,
189
+ "Research this using source-backed evidence. Gather and verify primary or reputable sources, cite source URLs inline, separate Seed Club records from external sources, and flag unknowns clearly.",
190
+ );
191
+ },
192
+ });
193
+
194
+ pi.registerCommand("worldview", {
195
+ description: "Open an investing worldview prompt",
196
+ handler: async (_args, ctx) => {
197
+ await prefillEditor(
198
+ ctx,
199
+ "Summarize my current Seed Club investing worldview from recent memory and Seed Club context. Focus on beliefs, decision heuristics, and places where my view has changed. Flag what evidence supports each point.",
200
+ );
201
+ },
202
+ });
203
+
204
+ pi.registerCommand("theses", {
205
+ description: "Open an investment theses prompt",
206
+ handler: async (_args, ctx) => {
207
+ await prefillEditor(
208
+ ctx,
209
+ "Draft my current investment theses from Seed Club memory and recent deal context. Group by thesis, include supporting signals, counterexamples, and what would change my mind.",
210
+ );
211
+ },
212
+ });
213
+
214
+ pi.registerCommand("concerns", {
215
+ description: "Open an investment concerns prompt",
216
+ handler: async (_args, ctx) => {
217
+ await prefillEditor(
218
+ ctx,
219
+ "List my current recurring investment concerns from Seed Club memory and recent deal context. Group concerns by theme, name the pattern, cite representative context when available, and separate known concerns from guesses.",
220
+ );
221
+ },
222
+ });
223
+
108
224
  pi.registerCommand("seedclub", {
109
225
  description: "Seed Club",
110
226
  handler: async (args, ctx) => {
@@ -32,6 +32,7 @@ import {
32
32
  } from "./recent-entities.js";
33
33
  import { getCurrentUser, getSessionContext, registerUtilityTools } from "./tools/utility.js";
34
34
  import { registerCrmTools } from "./tools/crm.js";
35
+ import { registerOpportunityResearchTools } from "./tools/opportunity-research.js";
35
36
  import { registerMeetingTools } from "./tools/meetings.js";
36
37
  import { registerMediaTools } from "./tools/media.js";
37
38
  import { registerWebTools } from "./tools/web.js";
@@ -208,6 +209,7 @@ export default function (pi: ExtensionAPI) {
208
209
  // Tools
209
210
  registerUtilityTools(pi);
210
211
  registerCrmTools(pi);
212
+ registerOpportunityResearchTools(pi);
211
213
  registerMeetingTools(pi);
212
214
  registerMediaTools(pi);
213
215
  registerWebTools(pi);
@@ -433,6 +435,7 @@ export default function (pi: ExtensionAPI) {
433
435
 
434
436
  await applyConnectedStatus(ctx, user);
435
437
  void refreshPromptContext();
438
+ void memory.enableByInstallDefault(ctx);
436
439
  markAuthComplete(getPostAuthInstruction(ctx));
437
440
  return user;
438
441
  }
@@ -451,7 +454,7 @@ export default function (pi: ExtensionAPI) {
451
454
  markAuthInProgress({ message: "Checking Seed Club access..." });
452
455
  }
453
456
  void ensureSeedclubAuthenticated(ctx).then((authenticated) => {
454
- if (authenticated) void memory.refreshStatus(ctx, { notifySetup: true });
457
+ if (authenticated) void memory.enableByInstallDefault(ctx);
455
458
  }).catch((error) => {
456
459
  const message = error instanceof Error ? error.message : "Unable to verify Seed Club access.";
457
460
  markAuthRequired({
@@ -679,7 +682,7 @@ export default function (pi: ExtensionAPI) {
679
682
  await storeToken(token, result.email, apiBase, { authBase, name: result.name });
680
683
  await applyConnectedStatus(ctx, result);
681
684
  await refreshPromptContext();
682
- void memory.refreshStatus(ctx, { notifySetup: true });
685
+ void memory.enableByInstallDefault(ctx);
683
686
  const nextStep = getPostAuthInstruction(ctx);
684
687
  markAuthComplete(nextStep);
685
688
  if (options?.notifyOnSuccess) {
@@ -48,6 +48,14 @@ export async function fetchMemoryContextFromApi(apiClient, payload, timeoutMs) {
48
48
  );
49
49
  }
50
50
 
51
+ export async function fetchMemoryRecentFromApi(apiClient, payload, timeoutMs) {
52
+ return requestWithTimeout(
53
+ apiClient.post("/agent-memory/recent", payload),
54
+ timeoutMs,
55
+ "Seed Club recent memory",
56
+ );
57
+ }
58
+
51
59
  export async function writeMemoryEventToApi(apiClient, payload, timeoutMs) {
52
60
  return requestWithTimeout(
53
61
  apiClient.post("/agent-memory/events", payload),