@muxoai/platform 1.4.1 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/.agents/plugins/marketplace.json +1 -1
  2. package/.claude-plugin/marketplace.json +2 -2
  3. package/README.md +1 -1
  4. package/dist/cli.js +6 -3
  5. package/dist/composio-catalog.d.ts +177 -1
  6. package/dist/composio-catalog.js +1427 -7
  7. package/dist/config.d.ts +6 -0
  8. package/dist/config.js +11 -1
  9. package/dist/engine.d.ts +18 -1
  10. package/dist/engine.js +259 -35
  11. package/dist/mcp-schema.d.ts +162 -1
  12. package/dist/mcp-schema.js +1523 -40
  13. package/dist/mcp.d.ts +2 -2
  14. package/dist/mcp.js +412 -23
  15. package/dist/policy.d.ts +108 -1
  16. package/dist/policy.js +406 -1
  17. package/dist/providers/composio-instant.js +38 -3
  18. package/dist/providers/composio-sdk.d.ts +59 -2
  19. package/dist/providers/composio-sdk.js +273 -59
  20. package/dist/providers/stripe-projects.d.ts +4 -0
  21. package/dist/providers/stripe-projects.js +548 -126
  22. package/dist/server.js +531 -61
  23. package/dist/store.js +2 -0
  24. package/dist/types.d.ts +15 -0
  25. package/dist/ui/console-html.d.ts +31 -1
  26. package/dist/ui/console-html.js +922 -368
  27. package/dist/ui/design-tokens.js +1 -1
  28. package/dist/version.d.ts +1 -1
  29. package/dist/version.js +1 -1
  30. package/package.json +3 -2
  31. package/plugins/muxo/.claude-plugin/plugin.json +2 -2
  32. package/plugins/muxo/.codex-plugin/plugin.json +15 -8
  33. package/plugins/muxo/.cursor-plugin/plugin.json +30 -0
  34. package/plugins/muxo/hooks/session-start.sh +15 -3
  35. package/plugins/muxo/hooks/user-prompt-submit.sh +14 -1
  36. package/plugins/muxo/mcp.json +0 -10
  37. package/plugins/muxo/plugin.json +4 -4
  38. package/plugins/muxo/skills/muxo/SKILL.md +25 -16
  39. package/plugins/muxo/skills/muxo/references/cli.md +5 -1
  40. package/plugins/muxo/skills/muxo/references/mcp.md +11 -6
  41. package/plugins/muxo/skills/muxo-activity-summary/SKILL.md +81 -0
  42. package/plugins/muxo/skills/setup/SKILL.md +1 -1
  43. package/src/catalogues/stripe-projects-catalog.json +140 -0
package/dist/config.d.ts CHANGED
@@ -5,7 +5,13 @@ export interface MuxoConfig {
5
5
  baseUrl: string;
6
6
  dbPath: string;
7
7
  composioApiKey: string;
8
+ composioInstantApiKey: string;
8
9
  composioBaseUrl: string;
10
+ composioWebhookSecret: string;
11
+ composioWebhookSubscriptionId: string;
12
+ composioProjectId: string;
13
+ composioOrgId: string;
14
+ composioUserId: string;
9
15
  stripeSecretKey: string;
10
16
  stripePublishableKey: string;
11
17
  stripeApiBaseUrl: string;
package/dist/config.js CHANGED
@@ -65,8 +65,18 @@ export function getConfig() {
65
65
  dbPath: process.env.MUXO_DB_PATH || path.join(dataDir, "muxo.db"),
66
66
  composioApiKey: process.env.MUXO_EXTERNAL_MODE === "1"
67
67
  ? ""
68
- : process.env.COMPOSIO_API_KEY || "",
68
+ : process.env.COMPOSIO_API_KEY || process.env.COMPOSIO_INSTANT_API_KEY || "",
69
+ composioInstantApiKey: process.env.MUXO_EXTERNAL_MODE === "1"
70
+ ? ""
71
+ : process.env.COMPOSIO_INSTANT_API_KEY || process.env.COMPOSIO_API_KEY || "",
69
72
  composioBaseUrl: process.env.COMPOSIO_BASE_URL || "https://backend.composio.dev/api/v3",
73
+ composioWebhookSecret: process.env.MUXO_EXTERNAL_MODE === "1"
74
+ ? ""
75
+ : process.env.COMPOSIO_WEBHOOK_SECRET || "",
76
+ composioWebhookSubscriptionId: process.env.COMPOSIO_WEBHOOK_SUBSCRIPTION_ID || "",
77
+ composioProjectId: process.env.COMPOSIO_PROJECT_ID || "",
78
+ composioOrgId: process.env.COMPOSIO_ORG_ID || "",
79
+ composioUserId: process.env.COMPOSIO_USER_ID || "",
70
80
  stripeSecretKey: process.env.MUXO_EXTERNAL_MODE === "1"
71
81
  ? ""
72
82
  : process.env.STRIPE_SECRET_KEY || "",
package/dist/engine.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { MuxoConfig } from "./config.js";
2
2
  import { type DurableWorkflow } from "./durable-workflow.js";
3
3
  import { type NaturalLanguageResolution } from "./nl.js";
4
- import { describePolicyInPlainEnglish, type GuardrailCompileOptions, type ParsedNaturalLanguageGuardrail } from "./policy.js";
4
+ import { describePolicyInPlainEnglish, type GuardrailCompileOptions, type LlmPolicyAndGovernanceBrief, type ParsedNaturalLanguageGuardrail, type PolicySimulationResult } from "./policy.js";
5
5
  import { ComposioInstantAdapter } from "./providers/composio-instant.js";
6
6
  import { ComposioSdkAdapter } from "./providers/composio-sdk.js";
7
7
  import { MicrosoftGovernanceAdapter } from "./providers/microsoft-governance.js";
@@ -66,6 +66,7 @@ export declare class MuxoEngine {
66
66
  provider?: string;
67
67
  syncLive?: boolean;
68
68
  }): Promise<Record<string, unknown>>;
69
+ getHostedSiteHtml(slug: string, filePath?: string): string | null;
69
70
  startConnection(ctx: ExecutionContext, params: {
70
71
  provider: string;
71
72
  lane?: ProviderLane;
@@ -287,8 +288,22 @@ export declare class MuxoEngine {
287
288
  trustScore: ReturnType<MicrosoftGovernanceAdapter["getWorkspaceTrustScore"]>;
288
289
  policy: Workspace["policy"];
289
290
  plainEnglish: ReturnType<typeof describePolicyInPlainEnglish>;
291
+ llmPolicyBrief: LlmPolicyAndGovernanceBrief;
290
292
  explanation: HumanFriendlyExplanation;
291
293
  };
294
+ resetWorkspaceGuardrails(ctx: ExecutionContext): {
295
+ ok: true;
296
+ action: "reset_guardrails";
297
+ workspace: Workspace;
298
+ policy: Workspace["policy"];
299
+ plainEnglish: ReturnType<typeof describePolicyInPlainEnglish>;
300
+ llmPolicyBrief: LlmPolicyAndGovernanceBrief;
301
+ explanation: HumanFriendlyExplanation;
302
+ };
303
+ checkToolPolicy(ctx: ExecutionContext, params: {
304
+ toolSlug: string;
305
+ input?: Record<string, unknown>;
306
+ }): Promise<PolicySimulationResult>;
292
307
  setKillSwitch(ctx: ExecutionContext, active: boolean, reason?: string): Workspace;
293
308
  scanForContextPoisoning(workspaceId: string, text: string): {
294
309
  poisoned: boolean;
@@ -301,6 +316,7 @@ export declare class MuxoEngine {
301
316
  workspaceId: string;
302
317
  policy: Workspace["policy"];
303
318
  plainEnglish: ReturnType<typeof describePolicyInPlainEnglish>;
319
+ llmPolicyBrief: LlmPolicyAndGovernanceBrief;
304
320
  activeDefaults: ActiveMemoryDefaults;
305
321
  activeGuardrails: string[];
306
322
  };
@@ -309,6 +325,7 @@ export declare class MuxoEngine {
309
325
  workspace: Workspace;
310
326
  guardrail: ParsedNaturalLanguageGuardrail;
311
327
  plainEnglish: ReturnType<typeof describePolicyInPlainEnglish>;
328
+ llmPolicyBrief: LlmPolicyAndGovernanceBrief;
312
329
  memoryRecord?: WorkspaceMemoryRecord;
313
330
  }>;
314
331
  doNaturalLanguage(ctx: ExecutionContext, params: {
package/dist/engine.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import crypto from "node:crypto";
2
- import { APPROVED_PLAN_STATUSES, approvalRequiredError, buildApprovalUrl, clampWaitSeconds, looksLikeToolSlug, unknownToolError, } from "./mcp-schema.js";
2
+ import { isStripeProjectsExclusiveProvider, normalizeStripeProjectsProviderSlug, wrapMuxoConnectUrl, } from "./composio-catalog.js";
3
+ import { APPROVED_PLAN_STATUSES, approvalRequiredError, buildApprovalHumanHandoff, buildApprovalUrl, buildOAuthHumanHandoff, clampWaitSeconds, looksLikeToolSlug, unknownToolError, } from "./mcp-schema.js";
3
4
  import { completeCloudProvisioningWorkflow, createCloudProvisioningWorkflow, normalizeWorkflowTarget, workflowNotFoundError, } from "./durable-workflow.js";
4
5
  import { buildMemoryKnowledgeGraph } from "./memory-graph.js";
5
6
  import { resolveNaturalLanguageIntent, } from "./nl.js";
6
- import { compileNaturalLanguageGuardrailWithLlm, describePolicyInPlainEnglish, formatHumanFriendlyExplanation, parseNaturalLanguageGuardrail, } from "./policy.js";
7
+ import { DEFAULT_WORKSPACE_POLICY, buildLlmPolicyAndGovernanceBrief, compileNaturalLanguageGuardrailWithLlm, describePolicyInPlainEnglish, formatHumanFriendlyExplanation, parseNaturalLanguageGuardrail, simulatePolicyEvaluation, } from "./policy.js";
7
8
  import { ComposioInstantAdapter } from "./providers/composio-instant.js";
8
9
  import { ComposioSdkAdapter } from "./providers/composio-sdk.js";
9
10
  import { MicrosoftGovernanceAdapter } from "./providers/microsoft-governance.js";
@@ -73,6 +74,24 @@ export class MuxoEngine {
73
74
  const connections = this.store.listConnections(ws.id);
74
75
  const supplierSettlementSummary = this.store.getSupplierSettlementSummary(ws.id);
75
76
  const plainEnglishPolicy = describePolicyInPlainEnglish(ws.policy);
77
+ const localMemories = this.store.listMemoryRecords(ws.id, 25);
78
+ const activeFacts = this.store.listTemporalFacts(ws.id, {
79
+ includeHistorical: false,
80
+ limit: 30,
81
+ });
82
+ const inferred = extractActiveMemoryDefaults({
83
+ memories: localMemories,
84
+ temporalFacts: activeFacts,
85
+ });
86
+ const trustScore = this.governance.getWorkspaceTrustScore(ws.id);
87
+ const govStatus = this.governance.getStatus(ws);
88
+ const llmPolicyBrief = buildLlmPolicyAndGovernanceBrief(ws.policy, {
89
+ workspaceName: ws.name,
90
+ workspaceSlug: ws.slug,
91
+ activeDefaults: inferred.activeDefaults,
92
+ trustScore: { overall: trustScore.overall, tier: trustScore.tier },
93
+ agentDid: govStatus.agentDid,
94
+ });
76
95
  return {
77
96
  organization: {
78
97
  id: ws.id,
@@ -88,12 +107,16 @@ export class MuxoEngine {
88
107
  supplierSettlementSummary,
89
108
  policy: ws.policy,
90
109
  plainEnglishPolicy,
110
+ llmPolicyBrief,
111
+ activeDefaults: inferred.activeDefaults,
91
112
  explanation: plainEnglishPolicy.explanation,
92
113
  activeConnectionsCount: connections.filter((c) => c.status === "active").length,
93
114
  provisionedResourcesCount: resources.filter((r) => r.status === "active").length,
94
115
  projectsEnvironment: ws.projectsEnvName,
95
116
  createdAt: ws.createdAt,
96
117
  },
118
+ llmPolicyBrief,
119
+ activeDefaults: inferred.activeDefaults,
97
120
  };
98
121
  }
99
122
  // 3. search_tools
@@ -101,7 +124,16 @@ export class MuxoEngine {
101
124
  const limit = Math.min(100, Math.max(1, Number(params.limit || 25)));
102
125
  const lane = params.lane || "all";
103
126
  const query = params.query?.trim();
127
+ const queryTokens = (query || "")
128
+ .toLowerCase()
129
+ .split(/[\s,._/-]+/)
130
+ .filter(Boolean);
131
+ const prefersStripeProjects = queryTokens.some((tok) => isStripeProjectsExclusiveProvider(tok) ||
132
+ /^(provision|deploy|deployment|publish|host|hosting|static|landing|database|postgres|sqlite|redis)$/.test(tok));
104
133
  const results = [];
134
+ if (lane === "all" && prefersStripeProjects) {
135
+ results.push(...this.stripeProjects.searchTools(query, limit));
136
+ }
105
137
  if (lane === "all" || lane === "composio_instant") {
106
138
  results.push(...this.composioInstant.searchTools(query, limit));
107
139
  }
@@ -109,8 +141,10 @@ export class MuxoEngine {
109
141
  const sdkTools = await this.composioSdk.searchTools(query, limit);
110
142
  results.push(...sdkTools);
111
143
  }
112
- if (lane === "all" || lane === "stripe_projects") {
144
+ if (lane === "stripe_projects" || (lane === "all" && !prefersStripeProjects)) {
113
145
  results.push(...this.stripeProjects.searchTools(query, limit));
146
+ }
147
+ if (lane === "all" || lane === "stripe_projects") {
114
148
  const billingTools = this.stripeBilling.listTools().filter((t) => {
115
149
  if (!query)
116
150
  return true;
@@ -131,7 +165,7 @@ export class MuxoEngine {
131
165
  async listAllCatalogTools() {
132
166
  const instant = this.composioInstant.searchTools(undefined, 100);
133
167
  const sdk = await this.composioSdk.searchTools(undefined, 100);
134
- const proj = this.stripeProjects.searchTools(undefined, 100);
168
+ const proj = this.stripeProjects.getTools();
135
169
  const billing = this.stripeBilling.listTools();
136
170
  return [...instant, ...billing, ...sdk, ...proj];
137
171
  }
@@ -162,6 +196,9 @@ export class MuxoEngine {
162
196
  const composioByok = this.store.getByokKey(ctx.workspace.id, "composio");
163
197
  const liveComposio = await this.composioSdk.listLiveConnections(ctx.workspace.id, composioByok);
164
198
  for (const c of liveComposio) {
199
+ if (isStripeProjectsExclusiveProvider(c.providerSlug)) {
200
+ continue;
201
+ }
165
202
  this.store.upsertConnection({
166
203
  workspaceId: ctx.workspace.id,
167
204
  lane: "composio_sdk",
@@ -191,15 +228,63 @@ export class MuxoEngine {
191
228
  // Keep cached connections if CLI is busy
192
229
  }
193
230
  }
194
- let connections = this.store.listConnections(ctx.workspace.id);
231
+ let connections = this.store.listConnections(ctx.workspace.id).map((c) => {
232
+ if (isStripeProjectsExclusiveProvider(c.providerSlug)) {
233
+ return {
234
+ ...c,
235
+ lane: "stripe_projects",
236
+ status: "active",
237
+ redirectUrl: null,
238
+ };
239
+ }
240
+ return c.lane === "composio_sdk" && c.redirectUrl
241
+ ? {
242
+ ...c,
243
+ redirectUrl: wrapMuxoConnectUrl(c.redirectUrl, this.config.baseUrl, {
244
+ workspaceId: c.workspaceId,
245
+ providerSlug: c.providerSlug,
246
+ externalAccountId: c.externalAccountId,
247
+ }),
248
+ }
249
+ : c;
250
+ });
195
251
  if (params?.provider) {
196
- const target = params.provider.toLowerCase();
197
- connections = connections.filter((c) => c.providerSlug.toLowerCase() === target ||
198
- c.providerName.toLowerCase().includes(target));
252
+ const target = normalizeStripeProjectsProviderSlug(params.provider) || params.provider.toLowerCase();
253
+ if (isStripeProjectsExclusiveProvider(target)) {
254
+ const activeRecord = this.store.upsertConnection({
255
+ workspaceId: ctx.workspace.id,
256
+ lane: "stripe_projects",
257
+ providerSlug: target,
258
+ providerName: target.charAt(0).toUpperCase() + target.slice(1),
259
+ status: "active",
260
+ externalAccountId: `sp_conn_${target}`,
261
+ redirectUrl: null,
262
+ metadata: {
263
+ managedBy: "stripe_projects",
264
+ requiresOAuth: false,
265
+ },
266
+ });
267
+ connections = [activeRecord];
268
+ }
269
+ else {
270
+ connections = connections.filter((c) => c.providerSlug.toLowerCase() === target ||
271
+ c.providerName.toLowerCase().includes(target));
272
+ }
199
273
  }
274
+ const targetConn = connections[0] || null;
275
+ const isActive = targetConn
276
+ ? targetConn.status === "active"
277
+ : connections.some((c) => c.status === "active");
200
278
  return {
279
+ ok: true,
201
280
  workspaceId: ctx.workspace.id,
202
281
  instantWalletStatus: "active",
282
+ connected: isActive,
283
+ ready: isActive,
284
+ timedOut: false,
285
+ status: targetConn?.status || "not_connected",
286
+ redirectUrl: isActive ? null : targetConn?.redirectUrl || null,
287
+ connection: targetConn,
203
288
  connections,
204
289
  summary: {
205
290
  total: connections.length,
@@ -209,11 +294,18 @@ export class MuxoEngine {
209
294
  },
210
295
  };
211
296
  }
297
+ getHostedSiteHtml(slug, filePath) {
298
+ return this.stripeProjects.getHostedSiteHtml(slug, filePath);
299
+ }
212
300
  // 6. start_connection
213
301
  async startConnection(ctx, params) {
214
302
  const rawProvider = params.provider.trim().toLowerCase();
215
- const isProjectsLane = params.lane === "stripe_projects" || rawProvider.startsWith("resource.");
216
- const cleanSlug = rawProvider.replace(/^(app\.|resource\.)/, "");
303
+ const cleanSlug = normalizeStripeProjectsProviderSlug(rawProvider) ||
304
+ rawProvider.replace(/^(app\.|resource\.|projects\.)/, "");
305
+ const isProjectsLane = params.lane === "stripe_projects" ||
306
+ rawProvider.startsWith("resource.") ||
307
+ rawProvider.startsWith("projects.") ||
308
+ isStripeProjectsExclusiveProvider(cleanSlug);
217
309
  if (isProjectsLane) {
218
310
  const stripeByok = this.store.getByokKey(ctx.workspace.id, "stripe");
219
311
  const linked = await this.stripeProjects.linkProvider(cleanSlug, stripeByok);
@@ -258,10 +350,9 @@ export class MuxoEngine {
258
350
  }
259
351
  // 6b. wait_for_connection (OAuth handoff polling & recovery, like COMPOSIO_WAIT_FOR_CONNECTIONS)
260
352
  async waitForConnection(ctx, params) {
261
- const cleanSlug = params.provider
262
- .trim()
263
- .toLowerCase()
264
- .replace(/^(app\.|resource\.)/, "");
353
+ const rawProvider = params.provider.trim().toLowerCase();
354
+ const cleanSlug = normalizeStripeProjectsProviderSlug(rawProvider) ||
355
+ rawProvider.replace(/^(app\.|resource\.|projects\.)/, "");
265
356
  if (!cleanSlug) {
266
357
  throw new Error("provider is required to wait for a connection (e.g. 'github').");
267
358
  }
@@ -283,6 +374,22 @@ export class MuxoEngine {
283
374
  elapsedMs: Date.now() - startedAt,
284
375
  message,
285
376
  });
377
+ if (isStripeProjectsExclusiveProvider(cleanSlug)) {
378
+ const activeRecord = this.store.upsertConnection({
379
+ workspaceId: ctx.workspace.id,
380
+ lane: "stripe_projects",
381
+ providerSlug: cleanSlug,
382
+ providerName: cleanSlug.charAt(0).toUpperCase() + cleanSlug.slice(1),
383
+ status: "active",
384
+ externalAccountId: `sp_conn_${cleanSlug}`,
385
+ redirectUrl: null,
386
+ metadata: {
387
+ managedBy: "stripe_projects",
388
+ requiresOAuth: false,
389
+ },
390
+ });
391
+ return connectedResult(activeRecord, `${activeRecord.providerName} is managed via Stripe Projects Cloud Infrastructure and is active immediately (no OAuth required).`);
392
+ }
286
393
  let current = this.store
287
394
  .listConnections(ctx.workspace.id)
288
395
  .find((c) => c.providerSlug.toLowerCase() === cleanSlug);
@@ -341,6 +448,16 @@ export class MuxoEngine {
341
448
  if (!current) {
342
449
  current = await this.startConnection(ctx, { provider: cleanSlug });
343
450
  }
451
+ else if (current.redirectUrl) {
452
+ current = {
453
+ ...current,
454
+ redirectUrl: wrapMuxoConnectUrl(current.redirectUrl, this.config.baseUrl, {
455
+ workspaceId: ctx.workspace.id,
456
+ providerSlug: cleanSlug,
457
+ externalAccountId: current.externalAccountId,
458
+ }),
459
+ };
460
+ }
344
461
  return {
345
462
  ok: true,
346
463
  connected: false,
@@ -527,14 +644,21 @@ export class MuxoEngine {
527
644
  // Keep existing connection state if offline
528
645
  }
529
646
  if (!existingConn || existingConn.status !== "active") {
647
+ const wrappedRedirectUrl = existingConn?.redirectUrl
648
+ ? wrapMuxoConnectUrl(existingConn.redirectUrl, this.config.baseUrl, {
649
+ workspaceId: ws.id,
650
+ providerSlug: tool.providerSlug,
651
+ externalAccountId: existingConn.externalAccountId,
652
+ })
653
+ : null;
530
654
  authHandoff = {
531
655
  required: true,
532
656
  provider: tool.providerSlug,
533
657
  status: existingConn?.status || "pending",
534
- redirectUrl: existingConn?.redirectUrl || null,
658
+ redirectUrl: wrappedRedirectUrl,
535
659
  externalAccountId: existingConn?.externalAccountId || null,
536
- instructions: existingConn?.redirectUrl
537
- ? `Ask the user to authorize ${tool.providerName} at ${existingConn.redirectUrl}, then call wait_for_connection({ provider: "${tool.providerSlug}" }) before executing ${plan.id}.`
660
+ instructions: wrappedRedirectUrl
661
+ ? `Ask the user to authorize ${tool.providerName} at ${wrappedRedirectUrl}, then call wait_for_connection({ provider: "${tool.providerSlug}" }) before executing ${plan.id}.`
538
662
  : `Call start_connection({ provider: "${tool.providerSlug}" }) to authorize ${tool.providerName} before executing ${plan.id}.`,
539
663
  };
540
664
  }
@@ -606,25 +730,15 @@ export class MuxoEngine {
606
730
  });
607
731
  }
608
732
  buildApprovalHandoff(plan) {
609
- const url = `${this.config.baseUrl}/approve/${encodeURIComponent(plan.id)}`;
610
- return {
611
- kind: "approval",
612
- url,
613
- ctaLabel: "Review & approve",
614
- headline: `Muxo needs your approval to run ${plan.toolSlug}`,
615
- instructions: `Open ${url} to review and approve this ${plan.riskLevel}-risk action with one click (or run \`muxo approve ${plan.id}\`). Nothing runs until you approve.`,
616
- planId: plan.id,
617
- };
733
+ return buildApprovalHumanHandoff(this.config.baseUrl, plan);
618
734
  }
619
735
  buildOAuthHandoff(handoff, providerName) {
620
- return {
621
- kind: "oauth",
622
- url: handoff.redirectUrl,
623
- ctaLabel: `Connect ${providerName}`,
624
- headline: `Connect ${providerName} to continue`,
736
+ return buildOAuthHumanHandoff({
737
+ providerSlug: handoff.provider,
738
+ providerName,
739
+ redirectUrl: handoff.redirectUrl,
625
740
  instructions: handoff.instructions,
626
- provider: handoff.provider,
627
- };
741
+ });
628
742
  }
629
743
  buildPlanLlmGuidance(plan, authHandoff) {
630
744
  const executeTool = `execute_${plan.riskLevel}`;
@@ -767,6 +881,7 @@ export class MuxoEngine {
767
881
  }
768
882
  const enriched = {
769
883
  ...ctx,
884
+ enabled: true,
770
885
  staticFacts,
771
886
  dynamicContext,
772
887
  recalledMemories: recalled,
@@ -833,6 +948,13 @@ export class MuxoEngine {
833
948
  technical: contextTechnical,
834
949
  policy: ws.policy,
835
950
  });
951
+ const llmPolicyBrief = buildLlmPolicyAndGovernanceBrief(ws.policy, {
952
+ workspaceName: ws.name,
953
+ workspaceSlug: ws.slug,
954
+ activeDefaults: memoryContext.activeDefaults || {},
955
+ trustScore: { overall: trustScore.overall, tier: trustScore.tier },
956
+ agentDid: governanceStatus.agentDid,
957
+ });
836
958
  const llmSystemPrompt = [
837
959
  `# Muxo Governed Workspace Context (${ws.name} / ${ws.slug})`,
838
960
  `- **Language Preference**: ${ws.policy.languageMode || "hybrid"}${ws.policy.customInstructions?.length ? ` (Custom Instructions: ${ws.policy.customInstructions.join("; ")})` : ""}`,
@@ -840,6 +962,7 @@ export class MuxoEngine {
840
962
  `- **Learned Memory Defaults (Auto-Fill)**: ${defaultsList.length > 0 ? defaultsList.join(", ") : "none"}`,
841
963
  `- **Credits & Quota**: ${ws.creditsBalance} credits ($${(ws.creditsBalance * 0.01).toFixed(2)}) available, ${actionsRemaining} monthly actions remaining`,
842
964
  `- **Active Cloud Resources**: ${activeResources.length > 0 ? activeResources.map((r) => `${r.resourceName} (${r.serviceSlug})`).join(", ") : "none"}`,
965
+ llmPolicyBrief.llmSystemDirective,
843
966
  memoryContext.formattedPromptContext,
844
967
  ].join("\n");
845
968
  return {
@@ -848,6 +971,7 @@ export class MuxoEngine {
848
971
  projectsEnvironment: ws.projectsEnvName,
849
972
  policy: ws.policy,
850
973
  plainEnglishPolicy,
974
+ llmPolicyBrief,
851
975
  languageMode: ws.policy.languageMode || "hybrid",
852
976
  customInstructions: ws.policy.customInstructions || [],
853
977
  activeDefaults: (memoryContext.activeDefaults ||
@@ -1060,7 +1184,10 @@ export class MuxoEngine {
1060
1184
  // 10-15. execute_<risk_level>
1061
1185
  async executePlanForRisk(ctx, planId, expectedRisk) {
1062
1186
  const plan = this.getPlan(ctx, planId);
1063
- if (plan.riskLevel !== expectedRisk) {
1187
+ const isProjectsWriteCompatible = plan.lane === "stripe_projects" &&
1188
+ plan.riskLevel === "provisioning" &&
1189
+ expectedRisk === "write";
1190
+ if (plan.riskLevel !== expectedRisk && !isProjectsWriteCompatible) {
1064
1191
  throw new Error(`Risk lane mismatch: Plan '${plan.id}' has risk level '${plan.riskLevel}', so it must be executed with 'execute_${plan.riskLevel}' instead of 'execute_${expectedRisk}'.`);
1065
1192
  }
1066
1193
  if (plan.runId) {
@@ -1107,7 +1234,16 @@ export class MuxoEngine {
1107
1234
  }
1108
1235
  let activeConnId = null;
1109
1236
  if (plan.lane === "composio_sdk" && tool.requiresAuth) {
1110
- let connections = this.store.listConnections(ctx.workspace.id);
1237
+ let connections = this.store.listConnections(ctx.workspace.id).map((c) => c.lane === "composio_sdk" && c.redirectUrl
1238
+ ? {
1239
+ ...c,
1240
+ redirectUrl: wrapMuxoConnectUrl(c.redirectUrl, this.config.baseUrl, {
1241
+ workspaceId: c.workspaceId,
1242
+ providerSlug: c.providerSlug,
1243
+ externalAccountId: c.externalAccountId,
1244
+ }),
1245
+ }
1246
+ : c);
1111
1247
  let activeConn = connections.find((c) => c.lane === "composio_sdk" &&
1112
1248
  c.providerSlug === tool.providerSlug &&
1113
1249
  c.status === "active");
@@ -1581,6 +1717,22 @@ export class MuxoEngine {
1581
1717
  const governance = this.governance.getStatus(ws);
1582
1718
  const trustScore = this.governance.getWorkspaceTrustScore(ws.id);
1583
1719
  const plainEnglish = describePolicyInPlainEnglish(ws.policy);
1720
+ const localMemories = this.store.listMemoryRecords(ws.id, 25);
1721
+ const activeFacts = this.store.listTemporalFacts(ws.id, {
1722
+ includeHistorical: false,
1723
+ limit: 30,
1724
+ });
1725
+ const inferred = extractActiveMemoryDefaults({
1726
+ memories: localMemories,
1727
+ temporalFacts: activeFacts,
1728
+ });
1729
+ const llmPolicyBrief = buildLlmPolicyAndGovernanceBrief(ws.policy, {
1730
+ workspaceName: ws.name,
1731
+ workspaceSlug: ws.slug,
1732
+ activeDefaults: inferred.activeDefaults,
1733
+ trustScore: { overall: trustScore.overall, tier: trustScore.tier },
1734
+ agentDid: governance.agentDid,
1735
+ });
1584
1736
  const killSwitch = {
1585
1737
  active: Boolean(ws.policy.killSwitchActive),
1586
1738
  reason: ws.policy.killSwitchReason || null,
@@ -1603,9 +1755,70 @@ export class MuxoEngine {
1603
1755
  trustScore,
1604
1756
  policy: ws.policy,
1605
1757
  plainEnglish,
1758
+ llmPolicyBrief,
1606
1759
  explanation,
1607
1760
  };
1608
1761
  }
1762
+ resetWorkspaceGuardrails(ctx) {
1763
+ const ws = this.store.getWorkspace(ctx.workspace.id);
1764
+ const updated = this.store.updateWorkspacePolicy(ws.id, {
1765
+ ...DEFAULT_WORKSPACE_POLICY,
1766
+ parameterRules: [],
1767
+ customInstructions: [],
1768
+ naturalLanguageRules: [],
1769
+ blockedToolSlugs: [],
1770
+ });
1771
+ this.governance.resumeKillSwitch(ws.id);
1772
+ const plainEnglish = describePolicyInPlainEnglish(updated.policy);
1773
+ const llmPolicyBrief = buildLlmPolicyAndGovernanceBrief(updated.policy, {
1774
+ workspaceName: updated.name,
1775
+ workspaceSlug: updated.slug,
1776
+ });
1777
+ return {
1778
+ ok: true,
1779
+ action: "reset_guardrails",
1780
+ workspace: updated,
1781
+ policy: updated.policy,
1782
+ plainEnglish,
1783
+ llmPolicyBrief,
1784
+ explanation: plainEnglish.explanation,
1785
+ };
1786
+ }
1787
+ async checkToolPolicy(ctx, params) {
1788
+ const ws = this.store.getWorkspace(ctx.workspace.id);
1789
+ const localMemories = this.store.listMemoryRecords(ws.id, 25);
1790
+ const activeFacts = this.store.listTemporalFacts(ws.id, {
1791
+ includeHistorical: false,
1792
+ limit: 30,
1793
+ });
1794
+ const inferred = extractActiveMemoryDefaults({
1795
+ memories: localMemories,
1796
+ temporalFacts: activeFacts,
1797
+ });
1798
+ let riskLevel;
1799
+ let creditCost;
1800
+ let lane;
1801
+ let resolvedSlug = String(params.toolSlug || "instant.web.search").trim();
1802
+ try {
1803
+ const tool = await this.inspectTool(resolvedSlug);
1804
+ resolvedSlug = tool.slug;
1805
+ riskLevel = tool.riskLevel;
1806
+ creditCost = tool.creditCost;
1807
+ lane = tool.lane;
1808
+ }
1809
+ catch {
1810
+ // Fallback to slug prefix heuristics in simulatePolicyEvaluation
1811
+ }
1812
+ return simulatePolicyEvaluation({
1813
+ policy: ws.policy,
1814
+ toolSlug: resolvedSlug,
1815
+ riskLevel,
1816
+ creditCost,
1817
+ lane,
1818
+ input: params.input || {},
1819
+ activeDefaults: inferred.activeDefaults,
1820
+ });
1821
+ }
1609
1822
  setKillSwitch(ctx, active, reason) {
1610
1823
  const ws = this.store.getWorkspace(ctx.workspace.id);
1611
1824
  const updated = this.store.updateWorkspacePolicy(ws.id, {
@@ -1656,10 +1869,16 @@ export class MuxoEngine {
1656
1869
  memories: localMemories,
1657
1870
  temporalFacts: activeFacts,
1658
1871
  });
1872
+ const llmPolicyBrief = buildLlmPolicyAndGovernanceBrief(ws.policy, {
1873
+ workspaceName: ws.name,
1874
+ workspaceSlug: ws.slug,
1875
+ activeDefaults: inferred.activeDefaults,
1876
+ });
1659
1877
  return {
1660
1878
  workspaceId: ws.id,
1661
1879
  policy: ws.policy,
1662
1880
  plainEnglish,
1881
+ llmPolicyBrief,
1663
1882
  activeDefaults: inferred.activeDefaults,
1664
1883
  activeGuardrails: Array.from(new Set([
1665
1884
  ...(ws.policy.naturalLanguageRules || []),
@@ -1701,11 +1920,16 @@ export class MuxoEngine {
1701
1920
  // Non-blocking if memory scan/storage fails
1702
1921
  }
1703
1922
  const plainEnglish = describePolicyInPlainEnglish(updated.policy);
1923
+ const llmPolicyBrief = buildLlmPolicyAndGovernanceBrief(updated.policy, {
1924
+ workspaceName: updated.name,
1925
+ workspaceSlug: updated.slug,
1926
+ });
1704
1927
  return {
1705
1928
  ok: true,
1706
1929
  workspace: updated,
1707
1930
  guardrail: parsed,
1708
1931
  plainEnglish,
1932
+ llmPolicyBrief,
1709
1933
  memoryRecord,
1710
1934
  };
1711
1935
  }