@thecorporation/corp-tools 1.0.5 → 26.3.3

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/dist/index.js CHANGED
@@ -5,6 +5,19 @@ var SessionExpiredError = class extends Error {
5
5
  this.name = "SessionExpiredError";
6
6
  }
7
7
  };
8
+ async function extractErrorMessage(resp) {
9
+ try {
10
+ const text = await resp.text();
11
+ try {
12
+ const json = JSON.parse(text);
13
+ return json.error || json.message || json.detail || text;
14
+ } catch {
15
+ return text;
16
+ }
17
+ } catch {
18
+ return resp.statusText;
19
+ }
20
+ }
8
21
  async function provisionWorkspace(apiUrl, name) {
9
22
  const url = `${apiUrl.replace(/\/+$/, "")}/v1/workspaces/provision`;
10
23
  const body = {};
@@ -14,7 +27,10 @@ async function provisionWorkspace(apiUrl, name) {
14
27
  headers: { "Content-Type": "application/json" },
15
28
  body: JSON.stringify(body)
16
29
  });
17
- if (!resp.ok) throw new Error(`Provision failed: ${resp.status} ${resp.statusText}`);
30
+ if (!resp.ok) {
31
+ const detail = await extractErrorMessage(resp);
32
+ throw new Error(`Provision failed: ${resp.status} ${resp.statusText} \u2014 ${detail}`);
33
+ }
18
34
  return resp.json();
19
35
  }
20
36
  var CorpAPIClient = class {
@@ -43,34 +59,36 @@ var CorpAPIClient = class {
43
59
  if (body !== void 0) opts.body = JSON.stringify(body);
44
60
  return fetch(url, opts);
45
61
  }
62
+ async throwIfError(resp) {
63
+ if (resp.status === 401) throw new SessionExpiredError();
64
+ if (!resp.ok) {
65
+ const detail = await extractErrorMessage(resp);
66
+ throw new Error(`${resp.status} ${resp.statusText} \u2014 ${detail}`);
67
+ }
68
+ }
46
69
  async get(path, params) {
47
70
  const resp = await this.request("GET", path, void 0, params);
48
- if (resp.status === 401) throw new SessionExpiredError();
49
- if (!resp.ok) throw new Error(`${resp.status} ${resp.statusText}`);
71
+ await this.throwIfError(resp);
50
72
  return resp.json();
51
73
  }
52
74
  async post(path, body) {
53
75
  const resp = await this.request("POST", path, body);
54
- if (resp.status === 401) throw new SessionExpiredError();
55
- if (!resp.ok) throw new Error(`${resp.status} ${resp.statusText}`);
76
+ await this.throwIfError(resp);
56
77
  return resp.json();
57
78
  }
58
79
  async postWithParams(path, body, params) {
59
80
  const resp = await this.request("POST", path, body, params);
60
- if (resp.status === 401) throw new SessionExpiredError();
61
- if (!resp.ok) throw new Error(`${resp.status} ${resp.statusText}`);
81
+ await this.throwIfError(resp);
62
82
  return resp.json();
63
83
  }
64
84
  async patch(path, body) {
65
85
  const resp = await this.request("PATCH", path, body);
66
- if (resp.status === 401) throw new SessionExpiredError();
67
- if (!resp.ok) throw new Error(`${resp.status} ${resp.statusText}`);
86
+ await this.throwIfError(resp);
68
87
  return resp.json();
69
88
  }
70
89
  async del(path) {
71
90
  const resp = await this.request("DELETE", path);
72
- if (resp.status === 401) throw new SessionExpiredError();
73
- if (!resp.ok) throw new Error(`${resp.status} ${resp.statusText}`);
91
+ await this.throwIfError(resp);
74
92
  }
75
93
  // --- Workspace ---
76
94
  getStatus() {
@@ -97,8 +115,8 @@ var CorpAPIClient = class {
97
115
  return this.get(`/v1/workspaces/${this.workspaceId}/entities`);
98
116
  }
99
117
  // --- Contacts ---
100
- listContacts() {
101
- return this.get(`/v1/workspaces/${this.workspaceId}/contacts`);
118
+ listContacts(entityId) {
119
+ return this.get(`/v1/entities/${entityId}/contacts`);
102
120
  }
103
121
  getContact(id) {
104
122
  return this.get(`/v1/contacts/${id}`);
@@ -107,7 +125,7 @@ var CorpAPIClient = class {
107
125
  return this.get(`/v1/contacts/${id}/profile`);
108
126
  }
109
127
  createContact(data) {
110
- return this.post(`/v1/workspaces/${this.workspaceId}/contacts`, data);
128
+ return this.post("/v1/contacts", data);
111
129
  }
112
130
  updateContact(id, data) {
113
131
  return this.patch(`/v1/contacts/${id}`, data);
@@ -122,11 +140,18 @@ var CorpAPIClient = class {
122
140
  getCapTable(entityId) {
123
141
  return this.get(`/v1/entities/${entityId}/cap-table`);
124
142
  }
125
- getSafeNotes(entityId) {
126
- return this.get(`/v1/entities/${entityId}/safe-notes`);
143
+ /** Extract SAFE instruments from the cap table (no dedicated list endpoint). */
144
+ async getSafeNotes(entityId) {
145
+ const ct = await this.getCapTable(entityId);
146
+ const instruments = ct.instruments ?? [];
147
+ const positions = ct.positions ?? [];
148
+ const safeIds = new Set(instruments.filter((i) => String(i.kind).toLowerCase() === "safe").map((i) => i.instrument_id));
149
+ if (safeIds.size === 0) return [];
150
+ return positions.filter((p) => safeIds.has(p.instrument_id));
127
151
  }
128
- getShareTransfers(entityId) {
129
- return this.get(`/v1/entities/${entityId}/share-transfers`);
152
+ /** Extract transfer-workflow info (no dedicated list endpoint for share transfers). */
153
+ async getShareTransfers(entityId) {
154
+ return [{ _note: "Use transfer workflows: POST /v1/equity/transfer-workflows to initiate transfers.", entity_id: entityId }];
130
155
  }
131
156
  getValuations(entityId) {
132
157
  return this.get(`/v1/entities/${entityId}/valuations`);
@@ -134,14 +159,19 @@ var CorpAPIClient = class {
134
159
  getCurrent409a(entityId) {
135
160
  return this.get(`/v1/entities/${entityId}/current-409a`);
136
161
  }
137
- issueEquity(data) {
138
- return this.post("/v1/equity/grants", data);
162
+ createValuation(data) {
163
+ return this.post("/v1/valuations", data);
139
164
  }
140
- issueSafe(data) {
141
- return this.post("/v1/safe-notes", data);
165
+ submitValuationForApproval(valuationId, entityId) {
166
+ return this.post(`/v1/valuations/${valuationId}/submit-for-approval`, { entity_id: entityId });
167
+ }
168
+ approveValuation(valuationId, entityId, resolutionId) {
169
+ const body = { entity_id: entityId };
170
+ if (resolutionId) body.resolution_id = resolutionId;
171
+ return this.post(`/v1/valuations/${valuationId}/approve`, body);
142
172
  }
143
173
  transferShares(data) {
144
- return this.post("/v1/share-transfers", data);
174
+ return this.post("/v1/equity/transfer-workflows", data);
145
175
  }
146
176
  calculateDistribution(data) {
147
177
  return this.post("/v1/distributions", data);
@@ -165,6 +195,16 @@ var CorpAPIClient = class {
165
195
  executeRoundConversion(data) {
166
196
  return this.post("/v1/equity/conversions/execute", data);
167
197
  }
198
+ // --- Staged equity rounds ---
199
+ startEquityRound(data) {
200
+ return this.post("/v1/equity/rounds/staged", data);
201
+ }
202
+ addRoundSecurity(roundId, data) {
203
+ return this.post(`/v1/equity/rounds/${roundId}/securities`, data);
204
+ }
205
+ issueRound(roundId, data) {
206
+ return this.post(`/v1/equity/rounds/${roundId}/issue`, data);
207
+ }
168
208
  // --- Intent lifecycle helpers ---
169
209
  createExecutionIntent(data) {
170
210
  return this.post("/v1/execution/intents", data);
@@ -197,6 +237,33 @@ var CorpAPIClient = class {
197
237
  castVote(entityId, meetingId, itemId, data) {
198
238
  return this.postWithParams(`/v1/meetings/${meetingId}/agenda-items/${itemId}/vote`, data, { entity_id: entityId });
199
239
  }
240
+ sendNotice(meetingId, entityId) {
241
+ return this.postWithParams(`/v1/meetings/${meetingId}/notice`, {}, { entity_id: entityId });
242
+ }
243
+ adjournMeeting(meetingId, entityId) {
244
+ return this.postWithParams(`/v1/meetings/${meetingId}/adjourn`, {}, { entity_id: entityId });
245
+ }
246
+ cancelMeeting(meetingId, entityId) {
247
+ return this.postWithParams(`/v1/meetings/${meetingId}/cancel`, {}, { entity_id: entityId });
248
+ }
249
+ finalizeAgendaItem(meetingId, itemId, data) {
250
+ return this.post(`/v1/meetings/${meetingId}/agenda-items/${itemId}/finalize`, data);
251
+ }
252
+ computeResolution(meetingId, itemId, entityId, data) {
253
+ return this.postWithParams(`/v1/meetings/${meetingId}/agenda-items/${itemId}/resolution`, data, { entity_id: entityId });
254
+ }
255
+ attachResolutionDocument(meetingId, resolutionId, data) {
256
+ return this.post(`/v1/meetings/${meetingId}/resolutions/${resolutionId}/attach-document`, data);
257
+ }
258
+ writtenConsent(data) {
259
+ return this.post("/v1/meetings/written-consent", data);
260
+ }
261
+ listAgendaItems(meetingId, entityId) {
262
+ return this.get(`/v1/meetings/${meetingId}/agenda-items`, { entity_id: entityId });
263
+ }
264
+ listVotes(meetingId, itemId, entityId) {
265
+ return this.get(`/v1/meetings/${meetingId}/agenda-items/${itemId}/votes`, { entity_id: entityId });
266
+ }
200
267
  // --- Documents ---
201
268
  getEntityDocuments(entityId) {
202
269
  return this.get(`/v1/formations/${entityId}/documents`);
@@ -221,7 +288,7 @@ var CorpAPIClient = class {
221
288
  return this.post("/v1/payments", data);
222
289
  }
223
290
  openBankAccount(data) {
224
- return this.post("/v1/bank-accounts", data);
291
+ return this.post("/v1/treasury/bank-accounts", data);
225
292
  }
226
293
  classifyContractor(data) {
227
294
  return this.post("/v1/contractors/classify", data);
@@ -251,8 +318,8 @@ var CorpAPIClient = class {
251
318
  createBillingPortal() {
252
319
  return this.post("/v1/billing/portal", { workspace_id: this.workspaceId });
253
320
  }
254
- createBillingCheckout(tier, entityId) {
255
- const body = { tier };
321
+ createBillingCheckout(planId, entityId) {
322
+ const body = { plan_id: planId };
256
323
  if (entityId) body.entity_id = entityId;
257
324
  return this.post("/v1/billing/checkout", body);
258
325
  }
@@ -266,6 +333,18 @@ var CorpAPIClient = class {
266
333
  createFormation(data) {
267
334
  return this.post("/v1/formations", data);
268
335
  }
336
+ createFormationWithCapTable(data) {
337
+ return this.post("/v1/formations/with-cap-table", data);
338
+ }
339
+ createPendingEntity(data) {
340
+ return this.post("/v1/formations/pending", data);
341
+ }
342
+ addFounder(entityId, data) {
343
+ return this.post(`/v1/formations/${entityId}/founders`, data);
344
+ }
345
+ finalizeFormation(entityId) {
346
+ return this.post(`/v1/formations/${entityId}/finalize`, {});
347
+ }
269
348
  // --- Human obligations ---
270
349
  getHumanObligations() {
271
350
  return this.get(`/v1/workspaces/${this.workspaceId}/human-obligations`);
@@ -289,7 +368,7 @@ var CorpAPIClient = class {
289
368
  return this.get("/v1/agents");
290
369
  }
291
370
  getAgent(id) {
292
- return this.get(`/v1/agents/${id}`);
371
+ return this.get(`/v1/agents/${id}/resolved`);
293
372
  }
294
373
  createAgent(data) {
295
374
  return this.post("/v1/agents", data);
@@ -298,16 +377,10 @@ var CorpAPIClient = class {
298
377
  return this.patch(`/v1/agents/${id}`, data);
299
378
  }
300
379
  deleteAgent(id) {
301
- return this.del(`/v1/agents/${id}`);
302
- }
303
- sendAgentMessage(id, body) {
304
- return this.post(`/v1/agents/${id}/messages`, { body });
380
+ return this.patch(`/v1/agents/${id}`, { status: "disabled" });
305
381
  }
306
- listAgentExecutions(id) {
307
- return this.get(`/v1/agents/${id}/executions`);
308
- }
309
- getAgentUsage(id) {
310
- return this.get(`/v1/agents/${id}/usage`);
382
+ sendAgentMessage(id, message) {
383
+ return this.post(`/v1/agents/${id}/messages`, { message });
311
384
  }
312
385
  addAgentSkill(id, data) {
313
386
  return this.post(`/v1/agents/${id}/skills`, data);
@@ -315,12 +388,12 @@ var CorpAPIClient = class {
315
388
  listSupportedModels() {
316
389
  return this.get("/v1/models");
317
390
  }
318
- // --- Approvals ---
319
- listPendingApprovals() {
320
- return this.get("/v1/approvals/pending");
391
+ // --- Governance bodies ---
392
+ createGovernanceBody(data) {
393
+ return this.post("/v1/governance-bodies", data);
321
394
  }
322
- respondApproval(id, decision, message = "") {
323
- return this.patch(`/v1/approvals/${id}`, { decision, message });
395
+ createGovernanceSeat(bodyId, data) {
396
+ return this.post(`/v1/governance-bodies/${bodyId}/seats`, data);
324
397
  }
325
398
  // --- API Keys ---
326
399
  listApiKeys() {
@@ -351,971 +424,630 @@ var GENERATED_TOOL_DEFINITIONS = [
351
424
  {
352
425
  "type": "function",
353
426
  "function": {
354
- "name": "get_workspace_status",
355
- "description": "Get workspace status summary",
356
- "parameters": {
357
- "type": "object",
358
- "properties": {},
359
- "required": []
360
- }
361
- }
362
- },
363
- {
364
- "type": "function",
365
- "function": {
366
- "name": "list_entities",
367
- "description": "List all entities in the workspace",
368
- "parameters": {
369
- "type": "object",
370
- "properties": {},
371
- "required": []
372
- }
373
- }
374
- },
375
- {
376
- "type": "function",
377
- "function": {
378
- "name": "get_cap_table",
379
- "description": "Get cap table for an entity",
380
- "parameters": {
381
- "type": "object",
382
- "properties": {
383
- "entity_id": {
384
- "type": "string"
385
- }
386
- },
387
- "required": [
388
- "entity_id"
389
- ]
390
- }
391
- }
392
- },
393
- {
394
- "type": "function",
395
- "function": {
396
- "name": "list_documents",
397
- "description": "List documents for an entity",
398
- "parameters": {
399
- "type": "object",
400
- "properties": {
401
- "entity_id": {
402
- "type": "string"
403
- }
404
- },
405
- "required": [
406
- "entity_id"
407
- ]
408
- }
409
- }
410
- },
411
- {
412
- "type": "function",
413
- "function": {
414
- "name": "list_safe_notes",
415
- "description": "List SAFE notes for an entity",
416
- "parameters": {
417
- "type": "object",
418
- "properties": {
419
- "entity_id": {
420
- "type": "string"
421
- }
422
- },
423
- "required": [
424
- "entity_id"
425
- ]
426
- }
427
- }
428
- },
429
- {
430
- "type": "function",
431
- "function": {
432
- "name": "list_agents",
433
- "description": "List all agents in the workspace",
434
- "parameters": {
435
- "type": "object",
436
- "properties": {},
437
- "required": []
438
- }
439
- }
440
- },
441
- {
442
- "type": "function",
443
- "function": {
444
- "name": "list_obligations",
445
- "description": "List obligations with urgency tiers",
427
+ "name": "workspace",
428
+ "description": "Workspace-level queries. Actions: status (get workspace summary), list_entities (list all entities), obligations (list obligations, optional tier filter), billing (get billing status and plans).",
446
429
  "parameters": {
447
430
  "type": "object",
448
431
  "properties": {
432
+ "action": {
433
+ "type": "string",
434
+ "enum": ["status", "list_entities", "obligations", "billing"]
435
+ },
449
436
  "tier": {
450
- "type": "string"
437
+ "type": "string",
438
+ "description": "obligations: filter by urgency tier"
451
439
  }
452
440
  },
453
- "required": []
454
- }
455
- }
456
- },
457
- {
458
- "type": "function",
459
- "function": {
460
- "name": "get_billing_status",
461
- "description": "Get billing status and plans",
462
- "parameters": {
463
- "type": "object",
464
- "properties": {},
465
- "required": []
441
+ "required": ["action"]
466
442
  }
467
443
  }
468
444
  },
469
445
  {
470
446
  "type": "function",
471
447
  "function": {
472
- "name": "form_entity",
473
- "description": "Form a new business entity (LLC or corporation)",
448
+ "name": "entity",
449
+ "description": "Entity reads and lifecycle. Actions: get_cap_table (entity_id), list_documents (entity_id), list_safe_notes (entity_id), form (entity_type + entity_name + jurisdiction + members \u2014 legacy one-shot formation), create (entity_type + entity_name \u2014 step 1 of staged formation), add_founder (entity_id + name + email + role + ownership_pct \u2014 step 2), finalize (entity_id \u2014 step 3, generates docs + cap table), convert (entity_id + target_type), dissolve (entity_id + reason).",
474
450
  "parameters": {
475
451
  "type": "object",
476
452
  "properties": {
477
- "entity_type": {
453
+ "action": {
478
454
  "type": "string",
479
- "enum": [
480
- "llc",
481
- "corporation"
482
- ]
483
- },
484
- "entity_name": {
485
- "type": "string"
486
- },
487
- "jurisdiction": {
488
- "type": "string"
455
+ "enum": ["get_cap_table", "list_documents", "list_safe_notes", "form", "create", "add_founder", "finalize", "convert", "dissolve"]
456
+ },
457
+ "entity_id": { "type": "string" },
458
+ "entity_type": { "type": "string", "enum": ["llc", "c_corp"] },
459
+ "entity_name": { "type": "string" },
460
+ "jurisdiction": { "type": "string", "description": "e.g. US-DE, US-WY. Defaults to US-WY for LLC, US-DE for corporation." },
461
+ "fiscal_year_end": { "type": "string", "description": "form: fiscal year end e.g. '12-31'" },
462
+ "s_corp_election": { "type": "boolean", "description": "form: elect S-Corp tax treatment" },
463
+ "transfer_restrictions": { "type": "boolean", "description": "form: include transfer restrictions in bylaws (corp)" },
464
+ "right_of_first_refusal": { "type": "boolean", "description": "form: include ROFR in bylaws (corp)" },
465
+ "company_address": {
466
+ "type": "object",
467
+ "properties": {
468
+ "street": { "type": "string" },
469
+ "street2": { "type": "string" },
470
+ "city": { "type": "string" },
471
+ "state": { "type": "string" },
472
+ "zip": { "type": "string" }
473
+ },
474
+ "required": ["street", "city", "state", "zip"]
489
475
  },
490
476
  "members": {
491
477
  "type": "array",
478
+ "description": "form: founding members array",
492
479
  "items": {
493
480
  "type": "object",
494
481
  "properties": {
495
- "name": {
496
- "type": "string"
497
- },
498
- "investor_type": {
499
- "type": "string",
500
- "enum": [
501
- "natural_person",
502
- "agent",
503
- "entity"
504
- ]
505
- },
506
- "email": {
507
- "type": "string"
508
- },
509
- "agent_id": {
510
- "type": "string"
482
+ "name": { "type": "string" },
483
+ "investor_type": { "type": "string", "enum": ["natural_person", "agent", "entity"] },
484
+ "email": { "type": "string" },
485
+ "agent_id": { "type": "string" },
486
+ "entity_id": { "type": "string" },
487
+ "ownership_pct": { "type": "number" },
488
+ "membership_units": { "type": "integer" },
489
+ "share_count": { "type": "integer" },
490
+ "share_class": { "type": "string" },
491
+ "role": { "type": "string", "enum": ["director", "officer", "manager", "member", "chair"] },
492
+ "officer_title": { "type": "string", "enum": ["ceo", "cfo", "secretary", "president", "vp", "other"] },
493
+ "shares_purchased": { "type": "integer" },
494
+ "address": {
495
+ "type": "object",
496
+ "properties": {
497
+ "street": { "type": "string" },
498
+ "street2": { "type": "string" },
499
+ "city": { "type": "string" },
500
+ "state": { "type": "string" },
501
+ "zip": { "type": "string" }
502
+ }
511
503
  },
512
- "entity_id": {
513
- "type": "string"
504
+ "vesting": {
505
+ "type": "object",
506
+ "properties": {
507
+ "total_months": { "type": "integer" },
508
+ "cliff_months": { "type": "integer" },
509
+ "acceleration": { "type": "string", "enum": ["single_trigger", "double_trigger"] }
510
+ }
514
511
  },
515
- "ownership_pct": {
516
- "type": "number"
517
- },
518
- "membership_units": {
519
- "type": "integer"
520
- },
521
- "share_count": {
522
- "type": "integer"
523
- },
524
- "share_class": {
525
- "type": "string"
526
- },
527
- "role": {
528
- "type": "string"
529
- }
512
+ "ip_description": { "type": "string" },
513
+ "is_incorporator": { "type": "boolean" }
530
514
  },
531
- "required": [
532
- "name",
533
- "investor_type"
534
- ]
515
+ "required": ["name", "investor_type"]
535
516
  }
536
- }
537
- },
538
- "required": [
539
- "entity_type",
540
- "entity_name",
541
- "jurisdiction",
542
- "members"
543
- ]
544
- }
545
- }
546
- },
547
- {
548
- "type": "function",
549
- "function": {
550
- "name": "issue_equity",
551
- "description": "Issue an equity grant",
552
- "parameters": {
553
- "type": "object",
554
- "properties": {
555
- "entity_id": {
556
- "type": "string"
557
- },
558
- "grant_type": {
559
- "type": "string"
560
517
  },
561
- "shares": {
562
- "type": "integer"
563
- },
564
- "recipient_name": {
565
- "type": "string"
566
- },
567
- "vesting_schedule": {
568
- "type": "string"
569
- }
518
+ "name": { "type": "string", "description": "add_founder: full legal name" },
519
+ "email": { "type": "string", "description": "add_founder: email address" },
520
+ "role": { "type": "string", "enum": ["director", "officer", "manager", "member", "chair"], "description": "add_founder: role" },
521
+ "ownership_pct": { "type": "number", "description": "add_founder: ownership percentage (e.g. 50 for 50%)" },
522
+ "officer_title": { "type": "string", "enum": ["ceo", "cfo", "secretary", "president", "vp", "other"], "description": "add_founder: officer title (corp only)" },
523
+ "is_incorporator": { "type": "boolean", "description": "add_founder: is sole incorporator (corp only)" },
524
+ "target_type": { "type": "string", "enum": ["llc", "c_corp"], "description": "convert: target entity type" },
525
+ "new_jurisdiction": { "type": "string", "description": "convert: target jurisdiction" },
526
+ "reason": { "type": "string", "description": "dissolve: dissolution reason" },
527
+ "effective_date": { "type": "string", "description": "dissolve: effective date" }
570
528
  },
571
- "required": [
572
- "entity_id",
573
- "grant_type",
574
- "shares",
575
- "recipient_name"
576
- ]
529
+ "required": ["action"]
577
530
  }
578
531
  }
579
532
  },
580
533
  {
581
534
  "type": "function",
582
535
  "function": {
583
- "name": "issue_safe",
584
- "description": "Issue a SAFE note",
536
+ "name": "equity",
537
+ "description": "Equity and cap table operations. Actions: start_round (entity_id + name + issuer_legal_entity_id \u2014 step 1), add_security (round_id + instrument_id + quantity + recipient_name \u2014 step 2), issue_round (round_id \u2014 step 3, closes round + creates board agenda item), issue (entity_id + grant_type + shares + recipient_name \u2014 legacy single grant), issue_safe (entity_id + investor_name + principal_amount_cents + safe_type + valuation_cap_cents), transfer (entity_id + from_holder + to_holder + shares + skip_governance_review=true \u2014 bypasses governance), distribution (entity_id + total_amount_cents).",
585
538
  "parameters": {
586
539
  "type": "object",
587
540
  "properties": {
588
- "entity_id": {
589
- "type": "string"
590
- },
591
- "investor_name": {
592
- "type": "string"
593
- },
594
- "principal_amount_cents": {
595
- "type": "integer"
596
- },
597
- "safe_type": {
598
- "type": "string"
599
- },
600
- "valuation_cap_cents": {
601
- "type": "integer"
602
- }
541
+ "action": {
542
+ "type": "string",
543
+ "enum": ["start_round", "add_security", "issue_round", "issue", "issue_safe", "transfer", "distribution"]
544
+ },
545
+ "entity_id": { "type": "string" },
546
+ "name": { "type": "string", "description": "start_round: round name (e.g. 'Seed Round')" },
547
+ "issuer_legal_entity_id": { "type": "string", "description": "start_round: from cap table" },
548
+ "pre_money_cents": { "type": "integer", "description": "start_round: pre-money valuation in cents" },
549
+ "round_price_cents": { "type": "integer", "description": "start_round: price per share in cents" },
550
+ "target_raise_cents": { "type": "integer", "description": "start_round: target raise in cents" },
551
+ "round_id": { "type": "string", "description": "add_security/issue_round: round ID" },
552
+ "instrument_id": { "type": "string", "description": "add_security: instrument ID from cap table" },
553
+ "quantity": { "type": "integer", "description": "add_security: number of shares/units" },
554
+ "recipient_name": { "type": "string", "description": "add_security/issue: recipient name" },
555
+ "holder_id": { "type": "string", "description": "add_security: existing holder ID" },
556
+ "email": { "type": "string", "description": "add_security: recipient email" },
557
+ "principal_cents": { "type": "integer", "description": "add_security: investment amount in cents" },
558
+ "grant_type": { "type": "string", "description": "issue/add_security: e.g. common, preferred, option" },
559
+ "shares": { "type": "integer", "description": "issue/transfer: number of shares" },
560
+ "vesting_schedule": { "type": "string", "description": "issue: vesting schedule" },
561
+ "investor_name": { "type": "string", "description": "issue_safe: investor name" },
562
+ "principal_amount_cents": { "type": "integer", "description": "issue_safe: principal in cents" },
563
+ "safe_type": { "type": "string", "description": "issue_safe: SAFE type" },
564
+ "valuation_cap_cents": { "type": "integer", "description": "issue_safe: valuation cap in cents" },
565
+ "from_holder": { "type": "string", "description": "transfer: source holder" },
566
+ "to_holder": { "type": "string", "description": "transfer: destination holder" },
567
+ "share_class_id": { "type": "string", "description": "transfer: share class" },
568
+ "transfer_type": { "type": "string", "description": "transfer: transfer type" },
569
+ "skip_governance_review": { "type": "boolean", "description": "transfer: must be true to confirm bypassing governance" },
570
+ "total_amount_cents": { "type": "integer", "description": "distribution: total amount in cents" },
571
+ "distribution_type": { "type": "string", "enum": ["dividend", "return", "liquidation"], "description": "distribution: type" },
572
+ "description": { "type": "string", "description": "distribution: description (required)" }
603
573
  },
604
- "required": [
605
- "entity_id",
606
- "investor_name",
607
- "principal_amount_cents",
608
- "safe_type",
609
- "valuation_cap_cents"
610
- ]
574
+ "required": ["action"]
611
575
  }
612
576
  }
613
577
  },
614
578
  {
615
579
  "type": "function",
616
580
  "function": {
617
- "name": "transfer_shares",
618
- "description": "Transfer shares between holders",
581
+ "name": "valuation",
582
+ "description": "Valuation lifecycle. Actions: create (entity_id + valuation_type + effective_date + methodology \u2192 Draft), submit (entity_id + valuation_id \u2192 PendingApproval, auto-creates board agenda item), approve (entity_id + valuation_id + optional resolution_id \u2192 Approved, auto-supersedes previous 409A).",
619
583
  "parameters": {
620
584
  "type": "object",
621
585
  "properties": {
622
- "entity_id": {
623
- "type": "string"
624
- },
625
- "share_class_id": {
626
- "type": "string"
627
- },
628
- "from_holder": {
629
- "type": "string"
630
- },
631
- "to_holder": {
632
- "type": "string"
586
+ "action": {
587
+ "type": "string",
588
+ "enum": ["create", "submit", "approve"]
633
589
  },
634
- "transfer_type": {
635
- "type": "string"
590
+ "entity_id": { "type": "string" },
591
+ "valuation_id": { "type": "string", "description": "submit/approve: valuation ID" },
592
+ "valuation_type": {
593
+ "type": "string",
594
+ "enum": ["four_oh_nine_a", "llc_profits_interest", "fair_market_value", "gift", "estate", "other"],
595
+ "description": "create: valuation type"
636
596
  },
637
- "shares": {
638
- "type": "integer"
639
- }
597
+ "effective_date": { "type": "string", "description": "create: effective date (ISO 8601)" },
598
+ "methodology": {
599
+ "type": "string",
600
+ "enum": ["income", "market", "asset", "backsolve", "hybrid", "other"],
601
+ "description": "create: valuation methodology"
602
+ },
603
+ "fmv_per_share_cents": { "type": "integer", "description": "create: FMV per share in cents" },
604
+ "enterprise_value_cents": { "type": "integer", "description": "create: enterprise value in cents" },
605
+ "hurdle_amount_cents": { "type": "integer", "description": "create: hurdle amount in cents" },
606
+ "provider_contact_id": { "type": "string", "description": "create: valuation provider contact ID" },
607
+ "report_document_id": { "type": "string", "description": "create: valuation report document ID" },
608
+ "resolution_id": { "type": "string", "description": "approve: resolution ID from board vote" }
640
609
  },
641
- "required": [
642
- "entity_id",
643
- "from_holder",
644
- "to_holder",
645
- "shares"
646
- ]
610
+ "required": ["action"]
647
611
  }
648
612
  }
649
613
  },
650
614
  {
651
615
  "type": "function",
652
616
  "function": {
653
- "name": "calculate_distribution",
654
- "description": "Calculate a distribution",
617
+ "name": "meeting",
618
+ "description": "Governance meeting lifecycle. Actions: schedule (entity_id + body_id + meeting_type + title), notice (entity_id + meeting_id \u2014 Draft\u2192Noticed), convene (entity_id + meeting_id + present_seat_ids \u2014 quorum check), vote (entity_id + meeting_id + agenda_item_id + voter_id + vote_value), resolve (entity_id + meeting_id + agenda_item_id + resolution_text \u2014 tally votes), finalize_item (entity_id + meeting_id + agenda_item_id + status), adjourn (entity_id + meeting_id), cancel (entity_id + meeting_id), consent (entity_id + body_id + title + description \u2014 written consent, no meeting), attach_document (entity_id + meeting_id + resolution_id + document_id), list_items (entity_id + meeting_id), list_votes (entity_id + meeting_id + agenda_item_id).",
655
619
  "parameters": {
656
620
  "type": "object",
657
621
  "properties": {
658
- "entity_id": {
659
- "type": "string"
660
- },
661
- "total_amount_cents": {
662
- "type": "integer"
663
- },
664
- "distribution_type": {
665
- "type": "string"
666
- }
622
+ "action": {
623
+ "type": "string",
624
+ "enum": ["schedule", "notice", "convene", "vote", "resolve", "finalize_item", "adjourn", "cancel", "consent", "attach_document", "list_items", "list_votes"]
625
+ },
626
+ "entity_id": { "type": "string" },
627
+ "meeting_id": { "type": "string" },
628
+ "body_id": { "type": "string", "description": "schedule/consent: governance body ID" },
629
+ "meeting_type": { "type": "string", "description": "schedule: meeting type" },
630
+ "title": { "type": "string", "description": "schedule/consent: meeting title" },
631
+ "description": { "type": "string", "description": "consent: description" },
632
+ "scheduled_date": { "type": "string", "description": "schedule: date (ISO 8601)" },
633
+ "agenda_item_titles": { "type": "array", "items": { "type": "string" }, "description": "schedule: agenda items" },
634
+ "present_seat_ids": { "type": "array", "items": { "type": "string" }, "description": "convene: seat IDs present" },
635
+ "agenda_item_id": { "type": "string", "description": "vote/resolve/finalize_item/list_votes: agenda item ID" },
636
+ "voter_id": { "type": "string", "description": "vote: voter seat ID" },
637
+ "vote_value": { "type": "string", "enum": ["for", "against", "abstain", "recusal"], "description": "vote: for, against, abstain, or recusal" },
638
+ "resolution_text": { "type": "string", "description": "resolve: resolution text" },
639
+ "effective_date": { "type": "string", "description": "resolve: optional effective date" },
640
+ "status": { "type": "string", "enum": ["Voted", "Discussed", "Tabled", "Withdrawn"], "description": "finalize_item: Voted, Discussed, Tabled, or Withdrawn" },
641
+ "resolution_id": { "type": "string", "description": "attach_document: resolution ID" },
642
+ "document_id": { "type": "string", "description": "attach_document: document ID" }
667
643
  },
668
- "required": [
669
- "entity_id",
670
- "total_amount_cents"
671
- ]
644
+ "required": ["action"]
672
645
  }
673
646
  }
674
647
  },
675
648
  {
676
649
  "type": "function",
677
650
  "function": {
678
- "name": "create_invoice",
679
- "description": "Create an invoice",
651
+ "name": "finance",
652
+ "description": "Financial operations. Actions: create_invoice (entity_id + customer_name + amount_cents + description + due_date), run_payroll (entity_id + pay_period_start + pay_period_end), submit_payment (entity_id + amount_cents + recipient), open_bank_account (entity_id + bank_name), reconcile (entity_id + start_date + end_date).",
680
653
  "parameters": {
681
654
  "type": "object",
682
655
  "properties": {
683
- "entity_id": {
684
- "type": "string"
685
- },
686
- "customer_name": {
687
- "type": "string"
688
- },
689
- "amount_cents": {
690
- "type": "integer"
691
- },
692
- "description": {
693
- "type": "string"
694
- },
695
- "due_date": {
696
- "type": "string"
697
- }
656
+ "action": {
657
+ "type": "string",
658
+ "enum": ["create_invoice", "run_payroll", "submit_payment", "open_bank_account", "reconcile"]
659
+ },
660
+ "entity_id": { "type": "string" },
661
+ "customer_name": { "type": "string", "description": "create_invoice: customer name" },
662
+ "amount_cents": { "type": "integer", "description": "create_invoice/submit_payment: amount in cents" },
663
+ "description": { "type": "string", "description": "create_invoice/submit_payment: description" },
664
+ "due_date": { "type": "string", "description": "create_invoice: due date" },
665
+ "pay_period_start": { "type": "string", "description": "run_payroll: start date" },
666
+ "pay_period_end": { "type": "string", "description": "run_payroll: end date" },
667
+ "recipient": { "type": "string", "description": "submit_payment: recipient" },
668
+ "bank_name": { "type": "string", "description": "open_bank_account: bank name (e.g. Mercury, SVB)" },
669
+ "start_date": { "type": "string", "description": "reconcile: start date" },
670
+ "end_date": { "type": "string", "description": "reconcile: end date" }
698
671
  },
699
- "required": [
700
- "entity_id",
701
- "customer_name",
702
- "amount_cents",
703
- "description",
704
- "due_date"
705
- ]
672
+ "required": ["action"]
706
673
  }
707
674
  }
708
675
  },
709
676
  {
710
677
  "type": "function",
711
678
  "function": {
712
- "name": "run_payroll",
713
- "description": "Run payroll",
679
+ "name": "compliance",
680
+ "description": "Compliance and legal operations. Actions: file_tax (entity_id + document_type + tax_year), track_deadline (entity_id + deadline_type + due_date + description), classify_contractor (entity_id + contractor_name + state + hours_per_week), generate_contract (entity_id + template_type + counterparty_name, optional effective_date).",
714
681
  "parameters": {
715
682
  "type": "object",
716
683
  "properties": {
717
- "entity_id": {
718
- "type": "string"
719
- },
720
- "pay_period_start": {
721
- "type": "string"
722
- },
723
- "pay_period_end": {
724
- "type": "string"
725
- }
684
+ "action": {
685
+ "type": "string",
686
+ "enum": ["file_tax", "track_deadline", "classify_contractor", "generate_contract"]
687
+ },
688
+ "entity_id": { "type": "string" },
689
+ "document_type": { "type": "string", "description": "file_tax: tax document type" },
690
+ "tax_year": { "type": "integer", "description": "file_tax: tax year" },
691
+ "deadline_type": { "type": "string", "description": "track_deadline: deadline type" },
692
+ "due_date": { "type": "string", "description": "track_deadline: due date" },
693
+ "description": { "type": "string", "description": "track_deadline: description" },
694
+ "recurrence": { "type": "string", "description": "track_deadline: recurrence" },
695
+ "contractor_name": { "type": "string", "description": "classify_contractor: contractor name" },
696
+ "state": { "type": "string", "description": "classify_contractor: state" },
697
+ "hours_per_week": { "type": "integer", "description": "classify_contractor: hours/week" },
698
+ "exclusive_client": { "type": "boolean", "description": "classify_contractor: exclusive?" },
699
+ "duration_months": { "type": "integer", "description": "classify_contractor: duration" },
700
+ "provides_tools": { "type": "boolean", "description": "classify_contractor: provides own tools?" },
701
+ "template_type": { "type": "string", "enum": ["consulting_agreement", "employment_offer", "contractor_agreement", "nda", "custom"], "description": "generate_contract: template type" },
702
+ "counterparty_name": { "type": "string", "description": "generate_contract: counterparty name" },
703
+ "effective_date": { "type": "string", "description": "generate_contract: effective date (ISO 8601, defaults to today)" },
704
+ "parameters": { "type": "object", "description": "generate_contract: additional template parameters" }
726
705
  },
727
- "required": [
728
- "entity_id",
729
- "pay_period_start",
730
- "pay_period_end"
731
- ]
706
+ "required": ["action"]
732
707
  }
733
708
  }
734
709
  },
735
710
  {
736
711
  "type": "function",
737
712
  "function": {
738
- "name": "submit_payment",
739
- "description": "Submit a payment",
713
+ "name": "document",
714
+ "description": "Document access, signing, and preview. Actions: signing_link (document_id \u2014 get signing link for a document), signer_link (obligation_id \u2014 generate signing link for a human obligation), download_link (document_id \u2014 get download link), preview_pdf (entity_id + document_id \u2014 preview a governance document as PDF without requiring a saved document).",
740
715
  "parameters": {
741
716
  "type": "object",
742
717
  "properties": {
743
- "entity_id": {
744
- "type": "string"
745
- },
746
- "amount_cents": {
747
- "type": "integer"
748
- },
749
- "recipient": {
750
- "type": "string"
718
+ "action": {
719
+ "type": "string",
720
+ "enum": ["signing_link", "signer_link", "download_link", "preview_pdf"]
751
721
  },
752
- "description": {
753
- "type": "string"
754
- }
722
+ "document_id": { "type": "string", "description": "signing_link/download_link/preview_pdf: document ID (or AST definition ID for preview_pdf)" },
723
+ "obligation_id": { "type": "string", "description": "signer_link: obligation ID" },
724
+ "entity_id": { "type": "string", "description": "preview_pdf: entity whose profile to use for rendering" }
755
725
  },
756
- "required": [
757
- "entity_id",
758
- "amount_cents",
759
- "recipient"
760
- ]
726
+ "required": ["action"]
761
727
  }
762
728
  }
763
729
  },
764
730
  {
765
731
  "type": "function",
766
732
  "function": {
767
- "name": "open_bank_account",
768
- "description": "Open a business bank account",
733
+ "name": "checklist",
734
+ "description": "Workspace progress checklist. Actions: get (retrieve current checklist), update (checklist \u2014 set checklist content in markdown checkbox format).",
769
735
  "parameters": {
770
736
  "type": "object",
771
737
  "properties": {
772
- "entity_id": {
773
- "type": "string"
738
+ "action": {
739
+ "type": "string",
740
+ "enum": ["get", "update"]
774
741
  },
775
- "institution_name": {
776
- "type": "string"
777
- }
742
+ "checklist": { "type": "string", "description": "update: markdown checklist content" }
778
743
  },
779
- "required": [
780
- "entity_id"
781
- ]
744
+ "required": ["action"]
782
745
  }
783
746
  }
784
747
  },
785
748
  {
786
749
  "type": "function",
787
750
  "function": {
788
- "name": "generate_contract",
789
- "description": "Generate a contract from a template",
751
+ "name": "agent",
752
+ "description": "Agent management. Agents are for delegating recurring tasks \u2014 NOT for research or one-off questions. Requires a paid plan. Actions: list (list all agents), create (name + system_prompt), message (agent_id + message), update (agent_id + optional status), add_skill (agent_id + name + description).",
790
753
  "parameters": {
791
754
  "type": "object",
792
755
  "properties": {
793
- "entity_id": {
794
- "type": "string"
795
- },
796
- "template_type": {
797
- "type": "string"
798
- },
799
- "parameters": {
800
- "type": "object"
801
- }
756
+ "action": {
757
+ "type": "string",
758
+ "enum": ["list", "create", "message", "update", "add_skill"]
759
+ },
760
+ "agent_id": { "type": "string", "description": "message/update/add_skill: agent ID" },
761
+ "name": { "type": "string", "description": "create: agent name; add_skill: skill name" },
762
+ "system_prompt": { "type": "string", "description": "create: agent system prompt" },
763
+ "model": { "type": "string", "description": "create: model name" },
764
+ "message": { "type": "string", "description": "message: message text" },
765
+ "status": { "type": "string", "enum": ["active", "paused", "disabled"], "description": "update: new status" },
766
+ "description": { "type": "string", "description": "add_skill: skill description" },
767
+ "parameters": { "type": "object", "description": "add_skill: skill parameters schema" }
802
768
  },
803
- "required": [
804
- "entity_id",
805
- "template_type"
806
- ]
769
+ "required": ["action"]
807
770
  }
808
771
  }
809
- },
810
- {
811
- "type": "function",
812
- "function": {
813
- "name": "file_tax_document",
814
- "description": "File a tax document",
815
- "parameters": {
816
- "type": "object",
817
- "properties": {
818
- "entity_id": {
819
- "type": "string"
820
- },
821
- "document_type": {
822
- "type": "string"
823
- },
824
- "tax_year": {
825
- "type": "integer"
826
- }
827
- },
828
- "required": [
829
- "entity_id",
830
- "document_type",
831
- "tax_year"
832
- ]
833
- }
772
+ }
773
+ ];
774
+
775
+ // src/tools.ts
776
+ function requiredString(args, key) {
777
+ const value = args[key];
778
+ if (typeof value !== "string" || value.trim().length === 0) {
779
+ throw new Error(`Missing required field: ${key}`);
780
+ }
781
+ return value;
782
+ }
783
+ var workspaceActions = {
784
+ status: async (_args, client) => client.getStatus(),
785
+ list_entities: async (_args, client) => client.listEntities(),
786
+ obligations: async (args, client) => client.getObligations(args.tier),
787
+ billing: async (_args, client) => {
788
+ const [status, plans] = await Promise.all([client.getBillingStatus(), client.getBillingPlans()]);
789
+ return { status, plans };
790
+ }
791
+ };
792
+ var entityActions = {
793
+ get_cap_table: async (args, client) => client.getCapTable(requiredString(args, "entity_id")),
794
+ list_documents: async (args, client) => client.getEntityDocuments(requiredString(args, "entity_id")),
795
+ list_safe_notes: async (args, client) => client.getSafeNotes(requiredString(args, "entity_id")),
796
+ create: async (args, client) => {
797
+ const entityType = args.entity_type;
798
+ let jurisdiction = args.jurisdiction || "";
799
+ if (!jurisdiction || jurisdiction.length === 2) {
800
+ jurisdiction = entityType === "llc" ? "US-WY" : "US-DE";
834
801
  }
802
+ return client.createPendingEntity({
803
+ entity_type: entityType,
804
+ legal_name: args.entity_name,
805
+ jurisdiction
806
+ });
835
807
  },
836
- {
837
- "type": "function",
838
- "function": {
839
- "name": "track_deadline",
840
- "description": "Track a compliance deadline",
841
- "parameters": {
842
- "type": "object",
843
- "properties": {
844
- "entity_id": {
845
- "type": "string"
846
- },
847
- "deadline_type": {
848
- "type": "string"
849
- },
850
- "due_date": {
851
- "type": "string"
852
- },
853
- "description": {
854
- "type": "string"
855
- },
856
- "recurrence": {
857
- "type": "string"
858
- }
859
- },
860
- "required": [
861
- "entity_id",
862
- "deadline_type",
863
- "due_date",
864
- "description"
865
- ]
866
- }
808
+ add_founder: async (args, client) => {
809
+ const entityId = requiredString(args, "entity_id");
810
+ let ownershipPct = args.ownership_pct;
811
+ if (typeof ownershipPct === "number" && ownershipPct > 1) {
812
+ ownershipPct = ownershipPct / 100;
867
813
  }
814
+ return client.addFounder(entityId, {
815
+ name: args.name,
816
+ email: args.email,
817
+ role: args.role,
818
+ ownership_pct: ownershipPct,
819
+ officer_title: args.officer_title,
820
+ is_incorporator: args.is_incorporator
821
+ });
868
822
  },
869
- {
870
- "type": "function",
871
- "function": {
872
- "name": "classify_contractor",
873
- "description": "Classify contractor risk",
874
- "parameters": {
875
- "type": "object",
876
- "properties": {
877
- "entity_id": {
878
- "type": "string"
879
- },
880
- "contractor_name": {
881
- "type": "string"
882
- },
883
- "state": {
884
- "type": "string"
885
- },
886
- "hours_per_week": {
887
- "type": "integer"
888
- },
889
- "exclusive_client": {
890
- "type": "boolean"
891
- },
892
- "duration_months": {
893
- "type": "integer"
894
- },
895
- "provides_tools": {
896
- "type": "boolean"
897
- }
898
- },
899
- "required": [
900
- "entity_id",
901
- "contractor_name",
902
- "state",
903
- "hours_per_week"
904
- ]
905
- }
823
+ finalize: async (args, client, ctx) => {
824
+ const entityId = requiredString(args, "entity_id");
825
+ const result = await client.finalizeFormation(entityId);
826
+ if (entityId && ctx.onEntityFormed) {
827
+ ctx.onEntityFormed(entityId);
906
828
  }
829
+ return result;
907
830
  },
908
- {
909
- "type": "function",
910
- "function": {
911
- "name": "reconcile_ledger",
912
- "description": "Reconcile an entity's ledger",
913
- "parameters": {
914
- "type": "object",
915
- "properties": {
916
- "entity_id": {
917
- "type": "string"
918
- },
919
- "start_date": {
920
- "type": "string"
921
- },
922
- "end_date": {
923
- "type": "string"
924
- }
925
- },
926
- "required": [
927
- "entity_id",
928
- "start_date",
929
- "end_date"
930
- ]
831
+ form: async (args, client, ctx) => {
832
+ const entityType = args.entity_type;
833
+ let jurisdiction = args.jurisdiction || "";
834
+ if (!jurisdiction || jurisdiction.length === 2) {
835
+ jurisdiction = entityType === "llc" ? "US-WY" : "US-DE";
836
+ }
837
+ const members = args.members ?? [];
838
+ if (!members.length) return { error: "Members are required." };
839
+ for (const m of members) {
840
+ if (!m.investor_type) m.investor_type = "natural_person";
841
+ if (typeof m.ownership_pct === "number" && m.ownership_pct > 1) {
842
+ m.ownership_pct = m.ownership_pct / 100;
931
843
  }
932
844
  }
933
- },
934
- {
935
- "type": "function",
936
- "function": {
937
- "name": "convene_meeting",
938
- "description": "Convene a governance meeting",
939
- "parameters": {
940
- "type": "object",
941
- "properties": {
942
- "entity_id": {
943
- "type": "string"
944
- },
945
- "meeting_id": {
946
- "type": "string"
947
- },
948
- "present_seat_ids": {
949
- "type": "array",
950
- "items": {
951
- "type": "string"
952
- }
953
- }
954
- },
955
- "required": [
956
- "entity_id",
957
- "meeting_id",
958
- "present_seat_ids"
959
- ]
960
- }
961
- }
962
- },
963
- {
964
- "type": "function",
965
- "function": {
966
- "name": "cast_vote",
967
- "description": "Cast a vote on an agenda item",
968
- "parameters": {
969
- "type": "object",
970
- "properties": {
971
- "entity_id": {
972
- "type": "string"
973
- },
974
- "meeting_id": {
975
- "type": "string"
976
- },
977
- "agenda_item_id": {
978
- "type": "string"
979
- },
980
- "voter_id": {
981
- "type": "string"
982
- },
983
- "vote_value": {
984
- "type": "string",
985
- "description": "for, against, abstain, or recusal"
986
- }
987
- },
988
- "required": [
989
- "entity_id",
990
- "meeting_id",
991
- "agenda_item_id",
992
- "voter_id",
993
- "vote_value"
994
- ]
995
- }
996
- }
997
- },
998
- {
999
- "type": "function",
1000
- "function": {
1001
- "name": "schedule_meeting",
1002
- "description": "Schedule a board or member meeting",
1003
- "parameters": {
1004
- "type": "object",
1005
- "properties": {
1006
- "entity_id": {
1007
- "type": "string"
1008
- },
1009
- "body_id": {
1010
- "type": "string"
1011
- },
1012
- "meeting_type": {
1013
- "type": "string"
1014
- },
1015
- "title": {
1016
- "type": "string"
1017
- },
1018
- "scheduled_date": {
1019
- "type": "string"
1020
- },
1021
- "agenda_item_titles": {
1022
- "type": "array",
1023
- "items": {
1024
- "type": "string"
1025
- }
1026
- }
1027
- },
1028
- "required": [
1029
- "entity_id",
1030
- "body_id",
1031
- "meeting_type",
1032
- "title"
1033
- ]
1034
- }
1035
- }
1036
- },
1037
- {
1038
- "type": "function",
1039
- "function": {
1040
- "name": "get_signer_link",
1041
- "description": "Generate a signing link for a human obligation",
1042
- "parameters": {
1043
- "type": "object",
1044
- "properties": {
1045
- "obligation_id": {
1046
- "type": "string"
1047
- }
1048
- },
1049
- "required": [
1050
- "obligation_id"
1051
- ]
1052
- }
845
+ const result = await client.createFormationWithCapTable({
846
+ entity_type: entityType,
847
+ legal_name: args.entity_name,
848
+ jurisdiction,
849
+ members,
850
+ workspace_id: client.workspaceId,
851
+ fiscal_year_end: args.fiscal_year_end,
852
+ s_corp_election: args.s_corp_election,
853
+ transfer_restrictions: args.transfer_restrictions,
854
+ right_of_first_refusal: args.right_of_first_refusal,
855
+ company_address: args.company_address
856
+ });
857
+ const entityId = result.entity_id;
858
+ if (entityId && ctx.onEntityFormed) {
859
+ ctx.onEntityFormed(entityId);
1053
860
  }
861
+ return result;
1054
862
  },
1055
- {
1056
- "type": "function",
1057
- "function": {
1058
- "name": "get_document_link",
1059
- "description": "Get a download link for a document",
1060
- "parameters": {
1061
- "type": "object",
1062
- "properties": {
1063
- "document_id": {
1064
- "type": "string"
1065
- }
1066
- },
1067
- "required": [
1068
- "document_id"
1069
- ]
1070
- }
1071
- }
863
+ convert: async (args, client) => {
864
+ const body = { target_type: args.target_type ?? args.to_type ?? args.new_entity_type };
865
+ if (args.new_jurisdiction) body.new_jurisdiction = args.new_jurisdiction;
866
+ return client.convertEntity(requiredString(args, "entity_id"), body);
1072
867
  },
1073
- {
1074
- "type": "function",
1075
- "function": {
1076
- "name": "convert_entity",
1077
- "description": "Convert entity type",
1078
- "parameters": {
1079
- "type": "object",
1080
- "properties": {
1081
- "entity_id": {
1082
- "type": "string"
1083
- },
1084
- "new_entity_type": {
1085
- "type": "string"
1086
- },
1087
- "new_jurisdiction": {
1088
- "type": "string"
1089
- }
1090
- },
1091
- "required": [
1092
- "entity_id",
1093
- "new_entity_type"
1094
- ]
1095
- }
1096
- }
1097
- },
1098
- {
1099
- "type": "function",
1100
- "function": {
1101
- "name": "dissolve_entity",
1102
- "description": "Dissolve an entity",
1103
- "parameters": {
1104
- "type": "object",
1105
- "properties": {
1106
- "entity_id": {
1107
- "type": "string"
1108
- },
1109
- "reason": {
1110
- "type": "string"
1111
- },
1112
- "effective_date": {
1113
- "type": "string"
1114
- }
1115
- },
1116
- "required": [
1117
- "entity_id",
1118
- "reason"
1119
- ]
1120
- }
1121
- }
868
+ dissolve: async (args, client) => client.dissolveEntity(requiredString(args, "entity_id"), args)
869
+ };
870
+ var equityActions = {
871
+ start_round: async (args, client) => client.startEquityRound(args),
872
+ add_security: async (args, client) => {
873
+ const roundId = requiredString(args, "round_id");
874
+ return client.addRoundSecurity(roundId, args);
1122
875
  },
1123
- {
1124
- "type": "function",
1125
- "function": {
1126
- "name": "add_agent_skill",
1127
- "description": "Add a skill to an agent",
1128
- "parameters": {
1129
- "type": "object",
1130
- "properties": {
1131
- "agent_id": {
1132
- "type": "string"
1133
- },
1134
- "skill_name": {
1135
- "type": "string"
1136
- },
1137
- "description": {
1138
- "type": "string"
1139
- },
1140
- "instructions": {
1141
- "type": "string"
1142
- }
1143
- },
1144
- "required": [
1145
- "agent_id",
1146
- "skill_name",
1147
- "description"
1148
- ]
1149
- }
1150
- }
876
+ issue_round: async (args, client) => {
877
+ const roundId = requiredString(args, "round_id");
878
+ return client.issueRound(roundId, args);
1151
879
  },
1152
- {
1153
- "type": "function",
1154
- "function": {
1155
- "name": "get_checklist",
1156
- "description": "Get the user's onboarding checklist",
1157
- "parameters": {
1158
- "type": "object",
1159
- "properties": {},
1160
- "required": []
1161
- }
880
+ issue: async (args, client) => {
881
+ const entityId = requiredString(args, "entity_id");
882
+ const capTable = await client.getCapTable(entityId);
883
+ const issuerLegalEntityId = capTable.issuer_legal_entity_id;
884
+ if (!issuerLegalEntityId) return { error: "No issuer legal entity found. Has this entity been formed with a cap table?" };
885
+ const instruments = capTable.instruments;
886
+ if (!instruments?.length) return { error: "No instruments found on cap table." };
887
+ let instrumentId = args.instrument_id;
888
+ if (!instrumentId) {
889
+ const grantType = (args.grant_type ?? "").toLowerCase();
890
+ const match = instruments.find(
891
+ (i) => i.kind.toLowerCase().includes(grantType) || i.symbol.toLowerCase().includes(grantType)
892
+ ) ?? instruments.find((i) => i.kind.toLowerCase().includes("common"));
893
+ instrumentId = (match ?? instruments[0]).instrument_id;
1162
894
  }
895
+ const round = await client.startEquityRound({
896
+ entity_id: entityId,
897
+ name: `${args.grant_type ?? "equity"} grant \u2014 ${args.recipient_name ?? "unknown"}`,
898
+ issuer_legal_entity_id: issuerLegalEntityId
899
+ });
900
+ const roundId = round.round_id ?? round.equity_round_id;
901
+ const securityData = {
902
+ entity_id: entityId,
903
+ instrument_id: instrumentId,
904
+ quantity: args.shares ?? args.quantity,
905
+ recipient_name: args.recipient_name,
906
+ grant_type: args.grant_type
907
+ };
908
+ if (args.email) securityData.email = args.email;
909
+ await client.addRoundSecurity(roundId, securityData);
910
+ return client.issueRound(roundId, { entity_id: entityId });
1163
911
  },
1164
- {
1165
- "type": "function",
1166
- "function": {
1167
- "name": "update_checklist",
1168
- "description": "Update the user's onboarding checklist",
1169
- "parameters": {
1170
- "type": "object",
1171
- "properties": {
1172
- "checklist": {
1173
- "type": "string"
1174
- }
1175
- },
1176
- "required": [
1177
- "checklist"
1178
- ]
1179
- }
1180
- }
912
+ issue_safe: async (args, client) => {
913
+ const entityId = requiredString(args, "entity_id");
914
+ const capTable = await client.getCapTable(entityId);
915
+ const issuerLegalEntityId = capTable.issuer_legal_entity_id;
916
+ if (!issuerLegalEntityId) return { error: "No issuer legal entity found." };
917
+ const instruments = capTable.instruments;
918
+ const safeInstrument = instruments?.find((i) => i.kind.toLowerCase() === "safe");
919
+ if (!safeInstrument) return { error: "No SAFE instrument found on cap table." };
920
+ const principalCents = args.principal_amount_cents ?? args.amount_cents ?? 0;
921
+ const round = await client.startEquityRound({
922
+ entity_id: entityId,
923
+ name: `SAFE \u2014 ${args.investor_name ?? "investor"}`,
924
+ issuer_legal_entity_id: issuerLegalEntityId
925
+ });
926
+ const roundId = round.round_id ?? round.equity_round_id;
927
+ const securityData = {
928
+ entity_id: entityId,
929
+ instrument_id: safeInstrument.instrument_id,
930
+ quantity: principalCents || 1,
931
+ recipient_name: args.investor_name,
932
+ principal_cents: principalCents,
933
+ grant_type: args.safe_type ?? "post_money"
934
+ };
935
+ if (args.email) securityData.email = args.email;
936
+ if (args.valuation_cap_cents) securityData.valuation_cap_cents = args.valuation_cap_cents;
937
+ await client.addRoundSecurity(roundId, securityData);
938
+ return client.issueRound(roundId, { entity_id: entityId });
1181
939
  },
1182
- {
1183
- "type": "function",
1184
- "function": {
1185
- "name": "get_signing_link",
1186
- "description": "Get a signing link for a document",
1187
- "parameters": {
1188
- "type": "object",
1189
- "properties": {
1190
- "document_id": {
1191
- "type": "string"
1192
- }
1193
- },
1194
- "required": [
1195
- "document_id"
1196
- ]
1197
- }
940
+ transfer: async (args, client) => {
941
+ if (args.skip_governance_review !== true) {
942
+ return {
943
+ error: "Transfer blocked: governance review required. Use the transfer workflow (create_transfer_workflow \u2192 submit-review \u2192 record-board-approval \u2192 execute) for governed transfers. To bypass governance and record a direct transfer, pass skip_governance_review: true."
944
+ };
1198
945
  }
946
+ return client.transferShares(args);
1199
947
  },
1200
- {
1201
- "type": "function",
1202
- "function": {
1203
- "name": "create_agent",
1204
- "description": "Create a new agent",
1205
- "parameters": {
1206
- "type": "object",
1207
- "properties": {
1208
- "name": {
1209
- "type": "string"
1210
- },
1211
- "system_prompt": {
1212
- "type": "string"
1213
- },
1214
- "model": {
1215
- "type": "string"
1216
- }
1217
- },
1218
- "required": [
1219
- "name",
1220
- "system_prompt"
1221
- ]
1222
- }
948
+ distribution: async (args, client) => client.calculateDistribution(args)
949
+ };
950
+ var valuationActions = {
951
+ create: async (args, client) => client.createValuation(args),
952
+ submit: async (args, client) => client.submitValuationForApproval(
953
+ requiredString(args, "valuation_id"),
954
+ requiredString(args, "entity_id")
955
+ ),
956
+ approve: async (args, client) => client.approveValuation(
957
+ requiredString(args, "valuation_id"),
958
+ requiredString(args, "entity_id"),
959
+ args.resolution_id
960
+ )
961
+ };
962
+ var meetingActions = {
963
+ schedule: async (args, client) => {
964
+ const body = {
965
+ entity_id: requiredString(args, "entity_id"),
966
+ body_id: requiredString(args, "body_id"),
967
+ meeting_type: requiredString(args, "meeting_type"),
968
+ title: requiredString(args, "title")
969
+ };
970
+ const scheduledDate = args.scheduled_date ?? args.proposed_date;
971
+ if (typeof scheduledDate === "string" && scheduledDate.trim().length > 0) {
972
+ body.scheduled_date = scheduledDate;
1223
973
  }
974
+ const agendaItems = args.agenda_item_titles ?? args.agenda_items;
975
+ if (Array.isArray(agendaItems)) body.agenda_item_titles = agendaItems;
976
+ return client.scheduleMeeting(body);
1224
977
  },
1225
- {
1226
- "type": "function",
1227
- "function": {
1228
- "name": "send_agent_message",
1229
- "description": "Send a message to an agent",
1230
- "parameters": {
1231
- "type": "object",
1232
- "properties": {
1233
- "agent_id": {
1234
- "type": "string"
1235
- },
1236
- "body": {
1237
- "type": "string"
1238
- }
1239
- },
1240
- "required": [
1241
- "agent_id",
1242
- "body"
1243
- ]
1244
- }
978
+ notice: async (args, client) => client.sendNotice(
979
+ requiredString(args, "meeting_id"),
980
+ requiredString(args, "entity_id")
981
+ ),
982
+ convene: async (args, client) => client.conveneMeeting(
983
+ requiredString(args, "meeting_id"),
984
+ requiredString(args, "entity_id"),
985
+ {
986
+ present_seat_ids: Array.isArray(args.present_seat_ids) ? args.present_seat_ids : []
1245
987
  }
1246
- },
1247
- {
1248
- "type": "function",
1249
- "function": {
1250
- "name": "update_agent",
1251
- "description": "Update an agent",
1252
- "parameters": {
1253
- "type": "object",
1254
- "properties": {
1255
- "agent_id": {
1256
- "type": "string"
1257
- },
1258
- "status": {
1259
- "type": "string"
1260
- }
1261
- },
1262
- "required": [
1263
- "agent_id"
1264
- ]
1265
- }
988
+ ),
989
+ vote: async (args, client) => client.castVote(
990
+ requiredString(args, "entity_id"),
991
+ requiredString(args, "meeting_id"),
992
+ requiredString(args, "agenda_item_id"),
993
+ {
994
+ voter_id: requiredString(args, "voter_id"),
995
+ vote_value: requiredString(args, "vote_value")
1266
996
  }
1267
- }
1268
- ];
1269
-
1270
- // src/tools.ts
1271
- function requiredString(args, key) {
1272
- const value = args[key];
1273
- if (typeof value !== "string" || value.trim().length === 0) {
1274
- throw new Error(`Missing required field: ${key}`);
1275
- }
1276
- return value;
1277
- }
1278
- var TOOL_HANDLERS = {
1279
- get_workspace_status: async (_args, client) => client.getStatus(),
1280
- list_obligations: async (args, client) => client.getObligations(args.tier),
1281
- list_entities: async (_args, client) => client.listEntities(),
1282
- get_cap_table: async (args, client) => client.getCapTable(args.entity_id),
1283
- list_documents: async (args, client) => client.getEntityDocuments(args.entity_id),
1284
- list_safe_notes: async (args, client) => client.getSafeNotes(args.entity_id),
1285
- list_agents: async (_args, client) => client.listAgents(),
1286
- get_billing_status: async (_args, client) => {
1287
- const [status, plans] = await Promise.all([client.getBillingStatus(), client.getBillingPlans()]);
1288
- return { status, plans };
997
+ ),
998
+ resolve: async (args, client) => {
999
+ const data = {
1000
+ resolution_text: requiredString(args, "resolution_text")
1001
+ };
1002
+ if (typeof args.effective_date === "string") data.effective_date = args.effective_date;
1003
+ return client.computeResolution(
1004
+ requiredString(args, "meeting_id"),
1005
+ requiredString(args, "agenda_item_id"),
1006
+ requiredString(args, "entity_id"),
1007
+ data
1008
+ );
1289
1009
  },
1290
- form_entity: async (args, client, ctx) => {
1291
- const entityType = args.entity_type;
1292
- let jurisdiction = args.jurisdiction || "";
1293
- if (!jurisdiction || jurisdiction.length === 2) {
1294
- jurisdiction = entityType === "llc" ? "US-WY" : "US-DE";
1295
- }
1296
- const members = args.members ?? [];
1297
- if (!members.length) return { error: "Members are required." };
1298
- for (const m of members) {
1299
- if (!m.investor_type) m.investor_type = "natural_person";
1300
- if (typeof m.ownership_pct === "number" && m.ownership_pct > 1) {
1301
- m.ownership_pct = m.ownership_pct / 100;
1302
- }
1010
+ finalize_item: async (args, client) => client.finalizeAgendaItem(
1011
+ requiredString(args, "meeting_id"),
1012
+ requiredString(args, "agenda_item_id"),
1013
+ {
1014
+ entity_id: requiredString(args, "entity_id"),
1015
+ status: requiredString(args, "status")
1303
1016
  }
1304
- const result = await client.createFormation({
1305
- entity_type: entityType,
1306
- legal_name: args.entity_name,
1307
- jurisdiction,
1308
- members,
1309
- workspace_id: client.workspaceId
1310
- });
1311
- const entityId = result.entity_id;
1312
- if (entityId && ctx.onEntityFormed) {
1313
- ctx.onEntityFormed(entityId);
1017
+ ),
1018
+ adjourn: async (args, client) => client.adjournMeeting(
1019
+ requiredString(args, "meeting_id"),
1020
+ requiredString(args, "entity_id")
1021
+ ),
1022
+ cancel: async (args, client) => client.cancelMeeting(
1023
+ requiredString(args, "meeting_id"),
1024
+ requiredString(args, "entity_id")
1025
+ ),
1026
+ consent: async (args, client) => client.writtenConsent({
1027
+ entity_id: requiredString(args, "entity_id"),
1028
+ body_id: requiredString(args, "body_id"),
1029
+ title: requiredString(args, "title"),
1030
+ description: args.description ?? ""
1031
+ }),
1032
+ attach_document: async (args, client) => client.attachResolutionDocument(
1033
+ requiredString(args, "meeting_id"),
1034
+ requiredString(args, "resolution_id"),
1035
+ {
1036
+ entity_id: requiredString(args, "entity_id"),
1037
+ document_id: requiredString(args, "document_id")
1314
1038
  }
1315
- return result;
1316
- },
1317
- issue_equity: async (args, client) => client.issueEquity(args),
1318
- issue_safe: async (args, client) => client.issueSafe(args),
1039
+ ),
1040
+ list_items: async (args, client) => client.listAgendaItems(
1041
+ requiredString(args, "meeting_id"),
1042
+ requiredString(args, "entity_id")
1043
+ ),
1044
+ list_votes: async (args, client) => client.listVotes(
1045
+ requiredString(args, "meeting_id"),
1046
+ requiredString(args, "agenda_item_id"),
1047
+ requiredString(args, "entity_id")
1048
+ )
1049
+ };
1050
+ var financeActions = {
1319
1051
  create_invoice: async (args, client) => {
1320
1052
  if (!("amount_cents" in args) && Array.isArray(args.line_items)) {
1321
1053
  args.amount_cents = args.line_items.reduce((sum, item) => sum + (item.amount_cents ?? 0), 0);
@@ -1330,12 +1062,29 @@ var TOOL_HANDLERS = {
1330
1062
  submit_payment: async (args, client) => client.submitPayment(args),
1331
1063
  open_bank_account: async (args, client) => {
1332
1064
  const body = { entity_id: args.entity_id };
1333
- if (args.institution_name) body.institution_name = args.institution_name;
1065
+ body.bank_name = args.bank_name ?? args.institution_name ?? "Mercury";
1334
1066
  return client.openBankAccount(body);
1335
1067
  },
1336
- generate_contract: async (args, client) => client.generateContract(args),
1337
- file_tax_document: async (args, client) => client.fileTaxDocument(args),
1338
- get_signer_link: async (args, client) => {
1068
+ reconcile: async (args, client) => client.reconcileLedger(args)
1069
+ };
1070
+ var complianceActions = {
1071
+ file_tax: async (args, client) => client.fileTaxDocument(args),
1072
+ track_deadline: async (args, client) => client.trackDeadline(args),
1073
+ classify_contractor: async (args, client) => client.classifyContractor(args),
1074
+ generate_contract: async (args, client) => {
1075
+ const data = {
1076
+ entity_id: requiredString(args, "entity_id"),
1077
+ template_type: requiredString(args, "template_type"),
1078
+ counterparty_name: args.counterparty_name ?? args.counterparty ?? "",
1079
+ effective_date: args.effective_date ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)
1080
+ };
1081
+ if (args.parameters) data.parameters = args.parameters;
1082
+ return client.generateContract(data);
1083
+ }
1084
+ };
1085
+ var documentActions = {
1086
+ signing_link: async (args, client) => client.getSigningLink(args.document_id),
1087
+ signer_link: async (args, client) => {
1339
1088
  const result = await client.getSignerToken(args.obligation_id);
1340
1089
  const token = result.token ?? "";
1341
1090
  const obligationId = args.obligation_id;
@@ -1347,42 +1096,7 @@ var TOOL_HANDLERS = {
1347
1096
  message: "Share this link with the signer. Link expires in 15 minutes."
1348
1097
  };
1349
1098
  },
1350
- schedule_meeting: async (args, client) => {
1351
- const body = {
1352
- entity_id: requiredString(args, "entity_id"),
1353
- body_id: requiredString(args, "body_id"),
1354
- meeting_type: requiredString(args, "meeting_type"),
1355
- title: requiredString(args, "title")
1356
- };
1357
- const scheduledDate = args.scheduled_date ?? args.proposed_date;
1358
- if (typeof scheduledDate === "string" && scheduledDate.trim().length > 0) {
1359
- body.scheduled_date = scheduledDate;
1360
- }
1361
- const agendaItems = args.agenda_item_titles ?? args.agenda_items;
1362
- if (Array.isArray(agendaItems)) body.agenda_item_titles = agendaItems;
1363
- return client.scheduleMeeting(body);
1364
- },
1365
- cast_vote: async (args, client) => client.castVote(
1366
- requiredString(args, "entity_id"),
1367
- requiredString(args, "meeting_id"),
1368
- requiredString(args, "agenda_item_id"),
1369
- {
1370
- voter_id: requiredString(args, "voter_id"),
1371
- vote_value: requiredString(args, "vote_value")
1372
- }
1373
- ),
1374
- update_checklist: async (args, _client, ctx) => {
1375
- const path = join(ctx.dataDir, "checklist.md");
1376
- mkdirSync(ctx.dataDir, { recursive: true });
1377
- writeFileSync(path, args.checklist);
1378
- return { status: "updated", checklist: args.checklist };
1379
- },
1380
- get_checklist: async (_args, _client, ctx) => {
1381
- const path = join(ctx.dataDir, "checklist.md");
1382
- if (existsSync(path)) return { checklist: readFileSync(path, "utf-8") };
1383
- return { checklist: null, message: "No checklist yet." };
1384
- },
1385
- get_document_link: async (args, client) => {
1099
+ download_link: async (args, client) => {
1386
1100
  const docId = args.document_id;
1387
1101
  try {
1388
1102
  const resp = await fetch(`${client.apiUrl}/v1/documents/${docId}/request-copy`, {
@@ -1403,45 +1117,81 @@ var TOOL_HANDLERS = {
1403
1117
  };
1404
1118
  }
1405
1119
  },
1406
- get_signing_link: async (args, client) => client.getSigningLink(args.document_id),
1407
- convert_entity: async (args, client) => client.convertEntity(args.entity_id, args),
1408
- dissolve_entity: async (args, client) => client.dissolveEntity(args.entity_id, args),
1409
- transfer_shares: async (args, client) => client.transferShares(args),
1410
- calculate_distribution: async (args, client) => client.calculateDistribution(args),
1411
- classify_contractor: async (args, client) => client.classifyContractor(args),
1412
- reconcile_ledger: async (args, client) => client.reconcileLedger(args),
1413
- track_deadline: async (args, client) => client.trackDeadline(args),
1414
- convene_meeting: async (args, client) => client.conveneMeeting(
1415
- requiredString(args, "meeting_id"),
1416
- requiredString(args, "entity_id"),
1417
- {
1418
- present_seat_ids: Array.isArray(args.present_seat_ids) ? args.present_seat_ids : []
1419
- }
1420
- ),
1421
- create_agent: async (args, client) => client.createAgent(args),
1422
- send_agent_message: async (args, client) => client.sendAgentMessage(args.agent_id, args.body),
1423
- update_agent: async (args, client) => client.updateAgent(args.agent_id, args),
1424
- add_agent_skill: async (args, client) => client.addAgentSkill(args.agent_id, args)
1120
+ preview_pdf: async (args, client) => {
1121
+ const entityId = args.entity_id;
1122
+ const documentId = args.document_id;
1123
+ const qs = new URLSearchParams({ entity_id: entityId, document_id: documentId }).toString();
1124
+ return {
1125
+ entity_id: entityId,
1126
+ document_id: documentId,
1127
+ download_url: `${client.apiUrl}/v1/documents/preview/pdf?${qs}`,
1128
+ note: "Use your API key to authenticate the download."
1129
+ };
1130
+ }
1131
+ };
1132
+ var checklistActions = {
1133
+ get: async (_args, _client, ctx) => {
1134
+ const path = join(ctx.dataDir, "checklist.md");
1135
+ if (existsSync(path)) return { checklist: readFileSync(path, "utf-8") };
1136
+ return { checklist: null, message: "No checklist yet." };
1137
+ },
1138
+ update: async (args, _client, ctx) => {
1139
+ const path = join(ctx.dataDir, "checklist.md");
1140
+ mkdirSync(ctx.dataDir, { recursive: true });
1141
+ writeFileSync(path, args.checklist);
1142
+ return { status: "updated", checklist: args.checklist };
1143
+ }
1144
+ };
1145
+ var agentActions = {
1146
+ list: async (_args, client) => client.listAgents(),
1147
+ create: async (args, client) => client.createAgent(args),
1148
+ message: async (args, client) => client.sendAgentMessage(args.agent_id, args.message ?? args.body),
1149
+ update: async (args, client) => client.updateAgent(args.agent_id, args),
1150
+ add_skill: async (args, client) => client.addAgentSkill(args.agent_id, args)
1151
+ };
1152
+ var TOOL_DISPATCH = {
1153
+ workspace: workspaceActions,
1154
+ entity: entityActions,
1155
+ equity: equityActions,
1156
+ valuation: valuationActions,
1157
+ meeting: meetingActions,
1158
+ finance: financeActions,
1159
+ compliance: complianceActions,
1160
+ document: documentActions,
1161
+ checklist: checklistActions,
1162
+ agent: agentActions
1425
1163
  };
1426
1164
  var TOOL_DEFINITIONS = GENERATED_TOOL_DEFINITIONS;
1427
- var READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
1428
- "get_workspace_status",
1429
- "list_entities",
1430
- "get_cap_table",
1431
- "list_documents",
1432
- "list_safe_notes",
1433
- "list_agents",
1434
- "get_checklist",
1435
- "get_signing_link",
1436
- "list_obligations",
1437
- "get_billing_status"
1165
+ var READ_ONLY_ACTIONS = /* @__PURE__ */ new Set([
1166
+ "workspace:status",
1167
+ "workspace:list_entities",
1168
+ "workspace:obligations",
1169
+ "workspace:billing",
1170
+ "entity:get_cap_table",
1171
+ "entity:list_documents",
1172
+ "entity:list_safe_notes",
1173
+ "document:signing_link",
1174
+ "document:signer_link",
1175
+ "document:download_link",
1176
+ "document:preview_pdf",
1177
+ "checklist:get",
1178
+ "meeting:list_items",
1179
+ "meeting:list_votes",
1180
+ "agent:list"
1438
1181
  ]);
1439
- function isWriteTool(name) {
1440
- return !READ_ONLY_TOOLS.has(name);
1182
+ function isWriteTool(name, args) {
1183
+ if (args && typeof args.action === "string") {
1184
+ return !READ_ONLY_ACTIONS.has(`${name}:${args.action}`);
1185
+ }
1186
+ return true;
1441
1187
  }
1442
1188
  async function executeTool(name, args, client, ctx) {
1443
- const handler = TOOL_HANDLERS[name];
1444
- if (!handler) return JSON.stringify({ error: `Unknown tool: ${name}` });
1189
+ const dispatch = TOOL_DISPATCH[name];
1190
+ if (!dispatch) return JSON.stringify({ error: `Unknown tool: ${name}` });
1191
+ const action = args.action;
1192
+ if (!action) return JSON.stringify({ error: `Missing required field: action` });
1193
+ const handler = dispatch[action];
1194
+ if (!handler) return JSON.stringify({ error: `Unknown action "${action}" for tool "${name}"` });
1445
1195
  try {
1446
1196
  const result = await handler(args, client, ctx);
1447
1197
  return JSON.stringify(result, null, 0);
@@ -1468,40 +1218,83 @@ function describeToolCall(name, args) {
1468
1218
  a._amount ??= "?";
1469
1219
  a.institution_name ??= "Mercury";
1470
1220
  a.payment_method ??= "ach";
1221
+ const action = a.action;
1222
+ const key = action ? `${name}:${action}` : name;
1471
1223
  const fmts = {
1472
- form_entity: 'Form a new {entity_type} named "{entity_name}" in {jurisdiction}',
1473
- convert_entity: "Convert entity to {new_entity_type}",
1474
- dissolve_entity: "Dissolve entity \u2014 {dissolution_reason}",
1475
- issue_equity: "Issue {shares} {grant_type} shares to {recipient_name}",
1476
- transfer_shares: "Transfer {shares} shares to {to_recipient_name}",
1477
- issue_safe: "Issue SAFE note to {investor_name} for {_amount}",
1478
- calculate_distribution: "Calculate {distribution_type} distribution of {_amount}",
1479
- create_invoice: "Create invoice for {customer_name} \u2014 {_amount}",
1480
- run_payroll: "Run payroll for {pay_period_start} to {pay_period_end}",
1481
- submit_payment: "Submit {_amount} payment to {recipient} via {payment_method}",
1482
- open_bank_account: "Open bank account at {institution_name}",
1483
- reconcile_ledger: "Reconcile ledger from {start_date} to {end_date}",
1484
- generate_contract: "Generate {template_type} contract for {counterparty_name}",
1485
- file_tax_document: "File {document_type} for tax year {tax_year}",
1486
- track_deadline: "Track {deadline_type} deadline \u2014 {description}",
1487
- classify_contractor: "Classify contractor {contractor_name} in {state}",
1488
- convene_meeting: "Convene {meeting_type} meeting",
1489
- cast_vote: "Cast {vote} vote",
1490
- schedule_meeting: "Schedule {meeting_type} meeting: {title}",
1491
- update_checklist: "Update workspace checklist",
1492
- create_agent: 'Create agent "{name}"',
1493
- send_agent_message: "Send message to agent",
1494
- update_agent: "Update agent configuration",
1495
- add_agent_skill: 'Add skill "{skill_name}" to agent'
1224
+ // workspace
1225
+ "workspace:status": "Get workspace status",
1226
+ "workspace:list_entities": "List all entities",
1227
+ "workspace:obligations": "List obligations",
1228
+ "workspace:billing": "Get billing status",
1229
+ // entity
1230
+ "entity:get_cap_table": "Get cap table",
1231
+ "entity:list_documents": "List documents",
1232
+ "entity:list_safe_notes": "List SAFE notes",
1233
+ "entity:create": 'Create pending {entity_type} named "{entity_name}"',
1234
+ "entity:add_founder": 'Add founder "{name}" ({role}, {ownership_pct}%)',
1235
+ "entity:finalize": "Finalize formation and generate documents + cap table",
1236
+ "entity:form": 'Form a new {entity_type} named "{entity_name}" in {jurisdiction}',
1237
+ "entity:convert": "Convert entity to {new_entity_type}",
1238
+ "entity:dissolve": "Dissolve entity \u2014 {reason}",
1239
+ // equity
1240
+ "equity:start_round": 'Start equity round "{name}"',
1241
+ "equity:add_security": "Add {quantity} shares to {recipient_name} in round",
1242
+ "equity:issue_round": "Issue all securities and close the round",
1243
+ "equity:issue": "Issue {shares} {grant_type} shares to {recipient_name}",
1244
+ "equity:issue_safe": "Issue SAFE note to {investor_name} for {_amount}",
1245
+ "equity:transfer": "Direct transfer {shares} shares (bypass governance)",
1246
+ "equity:distribution": "Calculate {distribution_type} distribution of {_amount}",
1247
+ // valuation
1248
+ "valuation:create": "Create {valuation_type} valuation effective {effective_date}",
1249
+ "valuation:submit": "Submit valuation for board approval",
1250
+ "valuation:approve": "Approve valuation",
1251
+ // meeting
1252
+ "meeting:schedule": 'Schedule {meeting_type} meeting: "{title}"',
1253
+ "meeting:notice": "Send notice for meeting",
1254
+ "meeting:convene": "Convene meeting",
1255
+ "meeting:vote": "Cast {vote_value} vote",
1256
+ "meeting:resolve": "Compute resolution for agenda item",
1257
+ "meeting:finalize_item": "Finalize agenda item to {status}",
1258
+ "meeting:adjourn": "Adjourn meeting",
1259
+ "meeting:cancel": "Cancel meeting",
1260
+ "meeting:consent": 'Create written consent: "{title}"',
1261
+ "meeting:attach_document": "Attach document to resolution",
1262
+ "meeting:list_items": "List agenda items for meeting",
1263
+ "meeting:list_votes": "List votes on agenda item",
1264
+ // finance
1265
+ "finance:create_invoice": "Create invoice for {customer_name} \u2014 {_amount}",
1266
+ "finance:run_payroll": "Run payroll for {pay_period_start} to {pay_period_end}",
1267
+ "finance:submit_payment": "Submit {_amount} payment to {recipient} via {payment_method}",
1268
+ "finance:open_bank_account": "Open bank account at {institution_name}",
1269
+ "finance:reconcile": "Reconcile ledger from {start_date} to {end_date}",
1270
+ // compliance
1271
+ "compliance:file_tax": "File {document_type} for tax year {tax_year}",
1272
+ "compliance:track_deadline": "Track {deadline_type} deadline \u2014 {description}",
1273
+ "compliance:classify_contractor": "Classify contractor {contractor_name} in {state}",
1274
+ "compliance:generate_contract": "Generate {template_type} contract for {counterparty_name}",
1275
+ // document
1276
+ "document:signing_link": "Get signing link for document",
1277
+ "document:signer_link": "Generate signer link for obligation",
1278
+ "document:download_link": "Get download link for document",
1279
+ "document:preview_pdf": "Preview document PDF for {document_id}",
1280
+ // checklist
1281
+ "checklist:get": "Get workspace checklist",
1282
+ "checklist:update": "Update workspace checklist",
1283
+ // agent
1284
+ "agent:list": "List agents",
1285
+ "agent:create": 'Create agent "{name}"',
1286
+ "agent:message": "Send message to agent",
1287
+ "agent:update": "Update agent configuration",
1288
+ "agent:add_skill": 'Add skill "{skill_name}" to agent'
1496
1289
  };
1497
- const fmt = fmts[name];
1290
+ const fmt = fmts[key];
1498
1291
  if (fmt) {
1499
1292
  try {
1500
1293
  return fmt.replace(/\{(\w+)\}/g, (_, k) => String(a[k] ?? "?"));
1501
1294
  } catch {
1502
1295
  }
1503
1296
  }
1504
- return name.replace(/_/g, " ");
1297
+ return action ? `${name} \u2192 ${action}` : name.replace(/_/g, " ");
1505
1298
  }
1506
1299
 
1507
1300
  // src/system-prompt.ts
@@ -1510,34 +1303,26 @@ var SYSTEM_PROMPT_BASE = `You are a corporate governance assistant for TheCorpor
1510
1303
  ## Context
1511
1304
  {context}
1512
1305
 
1513
- ## Capabilities
1514
- You can perform the full range of corporate operations:
1515
-
1516
- **Read operations:**
1517
- - View workspace status, entities, cap tables, documents
1518
- - List SAFE notes, equity grants, agents
1519
- - Check deadlines and compliance status
1306
+ ## Tools
1307
+ You have 10 tools, each with an \`action\` parameter that selects the operation:
1520
1308
 
1521
- **Write operations:**
1522
- - Form new LLCs and corporations in any US jurisdiction
1523
- - Issue equity (common, preferred, options, units)
1524
- - Issue SAFE notes to investors
1525
- - Transfer shares between holders
1526
- - Convert entities (LLC <> Corporation)
1527
- - Create invoices, run payroll, submit payments
1528
- - Open bank accounts, reconcile ledgers
1529
- - Generate contracts (NDAs, employment offers, consulting agreements)
1530
- - File tax documents (1099-NEC, K-1, 941, W-2, estimated tax)
1531
- - Generate signing links for documents (human-only signing)
1532
- - Track compliance deadlines
1533
- - Classify contractor risk (employee vs 1099)
1534
- - Convene governance meetings and cast votes
1535
- - Dissolve entities with full wind-down workflow
1309
+ | Tool | Actions |
1310
+ |------|---------|
1311
+ | **workspace** | status, list_entities, obligations, billing |
1312
+ | **entity** | get_cap_table, list_documents, list_safe_notes, form, create, add_founder, finalize, convert, dissolve |
1313
+ | **equity** | start_round, add_security, issue_round, issue, issue_safe, transfer, distribution |
1314
+ | **valuation** | create, submit, approve |
1315
+ | **meeting** | schedule, notice, convene, vote, resolve, finalize_item, adjourn, cancel, consent, attach_document, list_items, list_votes |
1316
+ | **finance** | create_invoice, run_payroll, submit_payment, open_bank_account, reconcile |
1317
+ | **compliance** | file_tax, track_deadline, classify_contractor, generate_contract |
1318
+ | **document** | signing_link, signer_link, download_link |
1319
+ | **checklist** | get, update |
1320
+ | **agent** | list, create, message, update, add_skill |
1536
1321
 
1537
1322
  ## Rules
1538
1323
  - All monetary values are in integer cents ($1,000 = 100000).
1539
1324
  - Be concise and helpful.
1540
- - **You MUST confirm with the user before calling ANY write tool.** Describe what you are about to do and wait for explicit approval. Never execute tools speculatively or "on behalf of" the user without their go-ahead.
1325
+ - **You MUST confirm with the user before calling ANY write action.** Describe what you are about to do and wait for explicit approval. Never execute tools speculatively or "on behalf of" the user without their go-ahead.
1541
1326
  - Don't ask for info available in platform config \u2014 use the correct values automatically.
1542
1327
  - If only one option exists for a field, use it without asking.
1543
1328
  - Don't make up data \u2014 only present what the tools return.
@@ -1551,29 +1336,70 @@ You can perform the full range of corporate operations:
1551
1336
  - Agent tools require a paid plan.
1552
1337
 
1553
1338
  ## Entity Formation Rules
1554
- - When forming an entity, you MUST ask about all founding members and their ownership allocations BEFORE calling the form_entity tool.
1339
+ - **Prefer the staged formation flow** over \`entity action=form\`:
1340
+ 1. \`entity action=create\` \u2014 type + name \u2192 returns \`entity_id\`
1341
+ 2. \`entity action=add_founder\` \u2014 add each founder one at a time (name, email, role, ownership_pct)
1342
+ 3. \`entity action=finalize\` \u2014 generates documents + cap table
1343
+ - When using \`entity action=form\` (legacy), you MUST ask about all founding members and their ownership allocations BEFORE calling it.
1555
1344
  - For LLCs, ownership percentages must total 100%.
1556
1345
 
1346
+ ## Equity Round Rules
1347
+ - **Prefer the staged round flow** for issuing equity to multiple holders:
1348
+ 1. \`equity action=start_round\` \u2014 entity_id + name + issuer_legal_entity_id \u2192 returns \`round_id\`
1349
+ 2. \`equity action=add_security\` \u2014 add each holder's shares one at a time (round_id, instrument_id, quantity, recipient_name, plus holder_id or email)
1350
+ 3. \`equity action=issue_round\` \u2014 creates positions for all pending securities, closes the round, and auto-creates a board meeting agenda item for approval (or adds to an existing pending meeting)
1351
+ 4. Complete the board meeting lifecycle (notice \u2192 convene \u2192 vote \u2192 resolve \u2192 finalize \u2192 adjourn) to formally approve the round
1352
+ - The entity must already have a cap table with holders and instruments set up.
1353
+ - Use \`entity action=get_cap_table\` to look up holder IDs, instrument IDs, and the issuer legal entity ID before starting.
1354
+ - \`equity action=add_security\` can resolve recipients by \`holder_id\`, \`email\`, or auto-create from \`recipient_name\`.
1355
+
1356
+ ## Share Transfer Rules
1357
+ - **Prefer the transfer workflow** for share transfers \u2014 it includes bylaws review, ROFR, board approval, document generation, and signatures.
1358
+ - \`equity action=transfer\` is a direct bypass that skips all governance. It requires \`skip_governance_review: true\` to confirm the caller intentionally wants to skip the workflow. Only use it for corrective entries or when the user explicitly requests skipping governance.
1359
+
1360
+ ## Valuation Rules
1361
+ - To create and approve a 409A valuation:
1362
+ 1. \`valuation action=create\` \u2014 type=four_oh_nine_a + effective_date + methodology + fmv_per_share_cents \u2192 valuation_id (Draft)
1363
+ 2. \`valuation action=submit\` \u2014 Draft \u2192 PendingApproval; auto-creates board meeting agenda item (or adds to existing pending meeting)
1364
+ 3. Complete the board meeting lifecycle (notice \u2192 convene \u2192 vote \u2192 resolve \u2192 finalize \u2192 adjourn)
1365
+ 4. \`valuation action=approve\` \u2014 PendingApproval \u2192 Approved; pass resolution_id from the board vote
1366
+ - 409A valuations auto-expire after 365 days from effective_date
1367
+ - When a new 409A is approved, any previous approved 409A is auto-superseded
1368
+
1369
+ ## Governance Meeting Rules
1370
+ - Full meeting lifecycle:
1371
+ 1. \`meeting action=schedule\` \u2014 entity_id + body_id + meeting_type + title + agenda_item_titles \u2192 meeting_id
1372
+ 2. \`meeting action=notice\` \u2014 Draft \u2192 Noticed
1373
+ 3. \`meeting action=convene\` \u2014 present_seat_ids \u2192 quorum check \u2192 Noticed \u2192 Convened
1374
+ 4. \`meeting action=vote\` \u2014 vote on each agenda item (requires Convened + quorum met)
1375
+ 5. \`meeting action=resolve\` \u2014 tally votes \u2192 create Resolution
1376
+ 6. \`meeting action=finalize_item\` \u2014 mark item as Voted (requires resolution), Discussed, Tabled, or Withdrawn
1377
+ 7. \`meeting action=adjourn\` \u2014 Convened \u2192 Adjourned
1378
+ - For written consent (no physical meeting): use \`meeting action=consent\` \u2014 auto-convened, skip notice/convene
1379
+ - Use \`meeting action=list_items\` to get agenda_item_ids after scheduling
1380
+ - Use \`entity action=get_cap_table\` or governance read tools to look up body_id and seat holder IDs
1381
+ - \`meeting action=cancel\` works from Draft or Noticed status only
1382
+
1557
1383
  ## Document Signing Rules
1558
1384
  - You CANNOT sign documents on behalf of users. Signing is a human action.
1559
- - Use \`get_signing_link\` to generate a signing URL for a document.
1385
+ - Use \`document action=signing_link\` to generate a signing URL for a document.
1560
1386
  - Present the signing link so users can open it and sign themselves.
1561
1387
  - NEVER attempt to sign, execute, or complete signature actions automatically.
1562
- - The \`get_signing_link\` tool does NOT sign anything \u2014 it only returns a URL.
1388
+ - The \`document action=signing_link\` tool does NOT sign anything \u2014 it only returns a URL.
1563
1389
 
1564
1390
  ## User Journey
1565
1391
  After completing any action, ALWAYS present the logical next step(s) as a
1566
1392
  numbered list. The user should never wonder "what now?" \u2014 guide them forward.
1567
1393
 
1568
- After entity formation:
1569
- 1. The \`form_entity\` response includes a \`documents\` array with document IDs. These documents are created immediately \u2014 they are NEVER "still being generated" or delayed.
1570
- 2. Immediately call \`get_signing_link\` for each document ID in the response to get signing URLs.
1394
+ After entity formation (staged or legacy):
1395
+ 1. The \`entity action=finalize\` (or \`entity action=form\`) response includes a \`document_ids\` array. These documents are created immediately \u2014 they are NEVER "still being generated" or delayed.
1396
+ 2. Immediately call \`document action=signing_link\` for each document ID in the response to get signing URLs.
1571
1397
  3. Present the signing links to the user right away. Do NOT tell the user to "check back later" or that documents are "being prepared" \u2014 they already exist.
1572
1398
  4. Then: "Documents signed! Next: apply for an EIN, open a bank account, or issue equity."
1573
1399
 
1574
1400
  After document generation:
1575
1401
  1. Present signing links immediately \u2014 don't wait for the user to ask.
1576
- 2. Use the document IDs from the tool response \u2014 do NOT call \`list_documents\` to re-fetch them.
1402
+ 2. Use the document IDs from the tool response \u2014 do NOT call \`entity action=list_documents\` to re-fetch them.
1577
1403
 
1578
1404
  After signing:
1579
1405
  1. "Documents are signed! Next: file for EIN, open a bank account, or add team members."
@@ -1587,9 +1413,9 @@ General pattern:
1587
1413
  - If there are signing obligations, proactively generate and present the signing links.
1588
1414
  - Never just say "done" \u2014 always show what comes next.
1589
1415
 
1590
- After major actions, use update_checklist to track progress. Use markdown checkbox
1591
- format (- [x] / - [ ]). Call get_checklist first to see current state, then
1592
- update_checklist with checked-off items. This helps users see where they are.
1416
+ After major actions, use \`checklist action=update\` to track progress. Use markdown checkbox
1417
+ format (- [x] / - [ ]). Call \`checklist action=get\` first to see current state, then
1418
+ update with checked-off items. This helps users see where they are.
1593
1419
 
1594
1420
  {extra_sections}`;
1595
1421
  function formatConfigSection(cfgData) {
@@ -1656,22 +1482,14 @@ var TOOL_REGISTRY = {};
1656
1482
  for (const td of GENERATED_TOOL_DEFINITIONS) {
1657
1483
  TOOL_REGISTRY[td.function.name] = td.function;
1658
1484
  }
1659
- var READ_ONLY_TOOLS2 = /* @__PURE__ */ new Set([
1660
- "get_workspace_status",
1661
- "list_entities",
1662
- "get_cap_table",
1663
- "list_documents",
1664
- "list_safe_notes",
1665
- "list_agents",
1666
- "get_checklist",
1667
- "get_signing_link",
1668
- "list_obligations",
1669
- "get_billing_status"
1485
+ var READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
1486
+ "workspace",
1487
+ "checklist"
1670
1488
  ]);
1671
1489
  export {
1672
1490
  CorpAPIClient,
1673
1491
  GENERATED_TOOL_DEFINITIONS,
1674
- READ_ONLY_TOOLS2 as READ_ONLY_TOOLS,
1492
+ READ_ONLY_TOOLS,
1675
1493
  SYSTEM_PROMPT_BASE,
1676
1494
  SessionExpiredError,
1677
1495
  TOOL_DEFINITIONS,