edgegate-mcp 0.7.0 → 0.8.0

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.
@@ -0,0 +1,125 @@
1
+ import { z } from "zod";
2
+ import { EdgeGateError } from "../client.js";
3
+ export const getByoAuditInputSchema = z.object({
4
+ workspace_id: z.string().uuid(),
5
+ artifact_id: z
6
+ .string()
7
+ .uuid()
8
+ .optional()
9
+ .describe("Filter to events referencing this artifact."),
10
+ run_id: z
11
+ .string()
12
+ .uuid()
13
+ .optional()
14
+ .describe("Filter to events from this run."),
15
+ since: z
16
+ .string()
17
+ .datetime()
18
+ .optional()
19
+ .describe("ISO-8601 timestamp; only include events newer than this."),
20
+ cursor: z
21
+ .number()
22
+ .int()
23
+ .optional()
24
+ .describe("Opaque cursor returned by a previous call. Pass it back verbatim to " +
25
+ "fetch the next page; omit on the first call."),
26
+ limit: z
27
+ .number()
28
+ .int()
29
+ .min(1)
30
+ .max(500)
31
+ .optional()
32
+ .describe("Page size (1–500, default 100)."),
33
+ });
34
+ export async function getByoAuditHandler(client, input) {
35
+ try {
36
+ const page = await client.getByoAudit(input.workspace_id, {
37
+ artifact_id: input.artifact_id,
38
+ run_id: input.run_id,
39
+ since: input.since,
40
+ cursor: input.cursor,
41
+ limit: input.limit,
42
+ });
43
+ return renderAuditPage(page);
44
+ }
45
+ catch (err) {
46
+ if (err instanceof EdgeGateError) {
47
+ if (err.status === 402) {
48
+ return {
49
+ isError: true,
50
+ content: [
51
+ {
52
+ type: "text",
53
+ text: `BYO storage requires the Enterprise plan. ` +
54
+ `Contact sales: https://edgegate.frozo.ai/enterprise.`,
55
+ },
56
+ ],
57
+ };
58
+ }
59
+ return {
60
+ isError: true,
61
+ content: [
62
+ { type: "text", text: `EdgeGate returned ${err.status}: ${err.detail}` },
63
+ ],
64
+ };
65
+ }
66
+ throw err;
67
+ }
68
+ }
69
+ function truncate(value, max) {
70
+ if (value.length <= max)
71
+ return value;
72
+ return `${value.slice(0, max - 1)}…`;
73
+ }
74
+ function fmt(entry) {
75
+ const cells = [
76
+ entry.ts,
77
+ entry.event_type,
78
+ entry.outcome,
79
+ entry.error_code ?? "—",
80
+ truncate(entry.aws_request_id, 36),
81
+ truncate(entry.s3_key ?? "—", 48),
82
+ entry.bytes_read?.toLocaleString() ?? "—",
83
+ entry.run_id ? truncate(entry.run_id, 8) : "—",
84
+ ];
85
+ return `| ${cells.join(" | ")} |`;
86
+ }
87
+ function renderAuditPage(page) {
88
+ if (page.entries.length === 0) {
89
+ return {
90
+ content: [
91
+ {
92
+ type: "text",
93
+ text: [
94
+ `No BYO storage audit events match these filters.`,
95
+ ``,
96
+ `If you expected results, check that:`,
97
+ `- The workspace actually has BYO storage enabled (Enterprise plan).`,
98
+ `- The \`run_id\` / \`artifact_id\` / \`since\` filters aren't too narrow.`,
99
+ `- A run that consumed BYO artifacts has actually executed (verify probes ` +
100
+ `also appear here, every 6 hours).`,
101
+ ].join("\n"),
102
+ },
103
+ ],
104
+ };
105
+ }
106
+ const header = `| ts | event_type | outcome | error_code | aws_request_id | s3_key | bytes_read | run_id |`;
107
+ const sep = `|---|---|---|---|---|---|---|---|`;
108
+ const rows = page.entries.map(fmt).join("\n");
109
+ const lines = [
110
+ `BYO storage audit — ${page.entries.length} event(s)`,
111
+ ``,
112
+ header,
113
+ sep,
114
+ rows,
115
+ ``,
116
+ page.next_cursor === null
117
+ ? `End of log.`
118
+ : `Call again with \`cursor: ${page.next_cursor}\` to fetch the next page.`,
119
+ ``,
120
+ `Cross-reference \`aws_request_id\` against your own CloudTrail to confirm ` +
121
+ `EdgeGate's view of each S3 call matches yours.`,
122
+ ];
123
+ return { content: [{ type: "text", text: lines.join("\n") }] };
124
+ }
125
+ //# sourceMappingURL=get_byo_audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get_byo_audit.js","sourceRoot":"","sources":["../../src/tools/get_byo_audit.ts"],"names":[],"mappings":"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"}
@@ -5,8 +5,8 @@ export declare const getReportInputSchema: z.ZodObject<{
5
5
  workspace_id: z.ZodString;
6
6
  limit: z.ZodDefault<z.ZodNumber>;
7
7
  }, "strip", z.ZodTypeAny, {
8
- workspace_id: string;
9
8
  limit: number;
9
+ workspace_id: string;
10
10
  }, {
11
11
  workspace_id: string;
12
12
  limit?: number | undefined;
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+ import { EdgeGateClient } from "../client.js";
3
+ import type { ToolResult } from "./setup_workspace.js";
4
+ export declare const registerByoArtifactInputSchema: z.ZodObject<{
5
+ workspace_id: z.ZodString;
6
+ s3_uri: z.ZodString;
7
+ expected_sha256: z.ZodOptional<z.ZodString>;
8
+ expected_size: z.ZodOptional<z.ZodNumber>;
9
+ kind: z.ZodOptional<z.ZodString>;
10
+ original_filename: z.ZodOptional<z.ZodString>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ workspace_id: string;
13
+ s3_uri: string;
14
+ expected_sha256?: string | undefined;
15
+ expected_size?: number | undefined;
16
+ kind?: string | undefined;
17
+ original_filename?: string | undefined;
18
+ }, {
19
+ workspace_id: string;
20
+ s3_uri: string;
21
+ expected_sha256?: string | undefined;
22
+ expected_size?: number | undefined;
23
+ kind?: string | undefined;
24
+ original_filename?: string | undefined;
25
+ }>;
26
+ export type RegisterByoArtifactInput = z.infer<typeof registerByoArtifactInputSchema>;
27
+ export declare function registerByoArtifactHandler(client: EdgeGateClient, input: RegisterByoArtifactInput): Promise<ToolResult>;
@@ -0,0 +1,122 @@
1
+ import { z } from "zod";
2
+ import { EdgeGateError } from "../client.js";
3
+ export const registerByoArtifactInputSchema = z.object({
4
+ workspace_id: z.string().uuid(),
5
+ s3_uri: z
6
+ .string()
7
+ .regex(/^s3:\/\/[a-z0-9][a-z0-9\-.]{1,253}\/.+$/)
8
+ .describe("Full S3 URI of the object in your registered bucket, e.g. " +
9
+ "s3://my-bucket/models/mobilenet-v2.onnx. Must live in the same " +
10
+ "bucket the grant was registered with."),
11
+ expected_sha256: z
12
+ .string()
13
+ .regex(/^[a-f0-9]{64}$/)
14
+ .optional()
15
+ .describe("Optional SHA-256 of the object (hex). If supplied, downstream cells " +
16
+ "will fail with BYO_INTEGRITY_MISMATCH when the actual bytes don't " +
17
+ "match — a strong guarantee that you ran what you thought you ran."),
18
+ expected_size: z
19
+ .number()
20
+ .int()
21
+ .positive()
22
+ .optional()
23
+ .describe("Optional size in bytes. EdgeGate cross-checks against the HeadObject " +
24
+ "response and rejects the registration if they disagree — protects " +
25
+ "against stale pointers when an object was overwritten in S3."),
26
+ kind: z
27
+ .string()
28
+ .optional()
29
+ .describe("Artifact kind. Defaults to 'model'."),
30
+ original_filename: z
31
+ .string()
32
+ .optional()
33
+ .describe("Optional display filename for run reports."),
34
+ });
35
+ export async function registerByoArtifactHandler(client, input) {
36
+ try {
37
+ const artifact = await client.registerByoArtifact(input.workspace_id, {
38
+ s3_uri: input.s3_uri,
39
+ expected_sha256: input.expected_sha256,
40
+ expected_size: input.expected_size,
41
+ kind: input.kind,
42
+ original_filename: input.original_filename,
43
+ });
44
+ return renderArtifact(artifact);
45
+ }
46
+ catch (err) {
47
+ if (err instanceof EdgeGateError) {
48
+ if (err.status === 402) {
49
+ return {
50
+ isError: true,
51
+ content: [
52
+ {
53
+ type: "text",
54
+ text: `BYO storage requires the Enterprise plan. ` +
55
+ `Contact sales: https://edgegate.frozo.ai/enterprise.`,
56
+ },
57
+ ],
58
+ };
59
+ }
60
+ if (err.status === 400) {
61
+ return {
62
+ isError: true,
63
+ content: [
64
+ {
65
+ type: "text",
66
+ text: [
67
+ `EdgeGate rejected the BYO artifact registration:`,
68
+ ``,
69
+ `\`${err.detail}\``,
70
+ ``,
71
+ `Most common causes:`,
72
+ `- **No active grant** — register one with \`edgegate_register_byo_bucket\` first.`,
73
+ `- **Bucket mismatch** — the s3_uri's bucket is not the one this workspace ` +
74
+ `registered. Cross-bucket pointers are not allowed.`,
75
+ `- **BYO_OBJECT_NOT_FOUND** — the s3_uri's key doesn't exist in the bucket. ` +
76
+ `Double-check the path; HeadObject is case-sensitive.`,
77
+ `- **BYO_OBJECT_ACCESS_DENIED** — the IAM role lacks \`s3:GetObject\` ` +
78
+ `on this specific key (a bucket-policy or resource-condition denial).`,
79
+ `- **Size mismatch** — the \`expected_size\` you supplied doesn't match the ` +
80
+ `actual object. Drop it (or update it) and retry.`,
81
+ ].join("\n"),
82
+ },
83
+ ],
84
+ };
85
+ }
86
+ return {
87
+ isError: true,
88
+ content: [
89
+ { type: "text", text: `EdgeGate returned ${err.status}: ${err.detail}` },
90
+ ],
91
+ };
92
+ }
93
+ throw err;
94
+ }
95
+ }
96
+ function renderArtifact(artifact) {
97
+ return {
98
+ content: [
99
+ {
100
+ type: "text",
101
+ text: [
102
+ `Registered BYO artifact — bytes never left your AWS account.`,
103
+ ``,
104
+ `- artifact_id: \`${artifact.id}\``,
105
+ `- storage: \`${artifact.storage_url}\``,
106
+ `- kind: ${artifact.kind}`,
107
+ `- size: ${artifact.size_bytes.toLocaleString()} bytes`,
108
+ `- sha256: \`${artifact.sha256}\``,
109
+ artifact.original_filename
110
+ ? `- filename: \`${artifact.original_filename}\``
111
+ : `- filename: (none)`,
112
+ ``,
113
+ `Pass this \`artifact_id\` to \`edgegate_create_pipeline\` (in \`model_matrix\`) ` +
114
+ `or \`edgegate_run_gate\` (as \`model_artifact_id\`) to run it. ` +
115
+ `When a cell needs the model, EdgeGate's worker will AssumeRole into your ` +
116
+ `account and GetObject directly from S3.`,
117
+ ].join("\n"),
118
+ },
119
+ ],
120
+ };
121
+ }
122
+ //# sourceMappingURL=register_byo_artifact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register_byo_artifact.js","sourceRoot":"","sources":["../../src/tools/register_byo_artifact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { z } from "zod";
2
+ import { EdgeGateClient } from "../client.js";
3
+ import type { ToolResult } from "./setup_workspace.js";
4
+ export declare const registerByoBucketInputSchema: z.ZodObject<{
5
+ workspace_id: z.ZodString;
6
+ role_arn: z.ZodString;
7
+ bucket: z.ZodString;
8
+ region: z.ZodString;
9
+ kms_key_id: z.ZodOptional<z.ZodString>;
10
+ }, "strip", z.ZodTypeAny, {
11
+ workspace_id: string;
12
+ role_arn: string;
13
+ bucket: string;
14
+ region: string;
15
+ kms_key_id?: string | undefined;
16
+ }, {
17
+ workspace_id: string;
18
+ role_arn: string;
19
+ bucket: string;
20
+ region: string;
21
+ kms_key_id?: string | undefined;
22
+ }>;
23
+ export type RegisterByoBucketInput = z.infer<typeof registerByoBucketInputSchema>;
24
+ export declare function registerByoBucketHandler(client: EdgeGateClient, input: RegisterByoBucketInput): Promise<ToolResult>;
@@ -0,0 +1,143 @@
1
+ import { z } from "zod";
2
+ import { EdgeGateError } from "../client.js";
3
+ export const registerByoBucketInputSchema = z.object({
4
+ workspace_id: z.string().uuid(),
5
+ role_arn: z
6
+ .string()
7
+ .regex(/^arn:aws:iam::\d{12}:role\/.+$/)
8
+ .describe("ARN of the IAM role EdgeGate's workers will assume to read your bucket. " +
9
+ "Created by the EdgeGate CloudFormation launch stack (or your equivalent " +
10
+ "Terraform module). Format: arn:aws:iam::<account-id>:role/<name>."),
11
+ bucket: z
12
+ .string()
13
+ .min(3)
14
+ .max(255)
15
+ .regex(/^[a-z0-9][a-z0-9\-.]{1,253}$/)
16
+ .describe("S3 bucket name (not the URI — just the bucket name)."),
17
+ region: z
18
+ .string()
19
+ .min(4)
20
+ .max(64)
21
+ .describe("AWS region the bucket lives in, e.g. us-east-1."),
22
+ kms_key_id: z
23
+ .string()
24
+ .max(2048)
25
+ .optional()
26
+ .describe("Optional KMS key ARN if the bucket uses SSE-KMS. The IAM role must " +
27
+ "have kms:Decrypt on this key."),
28
+ });
29
+ export async function registerByoBucketHandler(client, input) {
30
+ try {
31
+ const grant = await client.registerByoGrant(input.workspace_id, {
32
+ role_arn: input.role_arn,
33
+ bucket: input.bucket,
34
+ region: input.region,
35
+ kms_key_id: input.kms_key_id,
36
+ });
37
+ return successText(grant);
38
+ }
39
+ catch (err) {
40
+ if (err instanceof EdgeGateError) {
41
+ if (err.status === 402) {
42
+ return {
43
+ isError: true,
44
+ content: [
45
+ {
46
+ type: "text",
47
+ text: [
48
+ `BYO storage requires the **Enterprise plan**.`,
49
+ ``,
50
+ `Reach out to sales at https://edgegate.frozo.ai/enterprise ` +
51
+ `to enable BYO storage on this workspace. ` +
52
+ `Once enabled, re-run \`edgegate_register_byo_bucket\` with the ` +
53
+ `same role + bucket details.`,
54
+ ].join("\n"),
55
+ },
56
+ ],
57
+ };
58
+ }
59
+ if (err.status === 409) {
60
+ // Do NOT auto-rotate — the existing grant may belong to a different
61
+ // role_arn the customer doesn't want overwritten by accident.
62
+ return {
63
+ isError: true,
64
+ content: [
65
+ {
66
+ type: "text",
67
+ text: [
68
+ `This workspace already has a BYO storage grant registered.`,
69
+ ``,
70
+ `Two safe paths forward:`,
71
+ `1. Inspect the existing grant with \`edgegate_check_byo_bucket\` ` +
72
+ `to confirm it's the one you intended.`,
73
+ `2. If you want to replace it: \`edgegate_disconnect_byo_bucket\` ` +
74
+ `first (will 409 if artifacts still reference it), then re-run ` +
75
+ `\`edgegate_register_byo_bucket\` with the new role/bucket.`,
76
+ ``,
77
+ `External-ID rotation (without replacing the grant) is available ` +
78
+ `via the dashboard at ` +
79
+ `https://edgegate.frozo.ai/workspace/${input.workspace_id}/settings#byo-storage.`,
80
+ ].join("\n"),
81
+ },
82
+ ],
83
+ };
84
+ }
85
+ return {
86
+ isError: true,
87
+ content: [
88
+ {
89
+ type: "text",
90
+ text: `EdgeGate returned ${err.status}: ${err.detail}`,
91
+ },
92
+ ],
93
+ };
94
+ }
95
+ throw err;
96
+ }
97
+ }
98
+ function roleArnTail(roleArn) {
99
+ // arn:aws:iam::123456789012:role/edgegate-byo-storage-prod
100
+ // Render the trailing role name + last 4 of the account id so the user can
101
+ // confirm at a glance that they registered the right role.
102
+ const parts = roleArn.split(":");
103
+ if (parts.length < 6)
104
+ return roleArn;
105
+ const account = parts[4];
106
+ const roleName = parts.slice(5).join(":").replace(/^role\//, "");
107
+ const acctTail = account.length > 4 ? `…${account.slice(-4)}` : account;
108
+ return `${roleName} (acct ${acctTail})`;
109
+ }
110
+ function successText(grant) {
111
+ return {
112
+ content: [
113
+ {
114
+ type: "text",
115
+ text: [
116
+ `Registered BYO storage grant for this workspace.`,
117
+ ``,
118
+ `- role: \`${roleArnTail(grant.role_arn)}\``,
119
+ `- bucket: \`${grant.bucket}\` (${grant.region})`,
120
+ grant.kms_key_id
121
+ ? `- kms key: \`${grant.kms_key_id}\``
122
+ : `- kms key: (none — SSE-S3 or no encryption)`,
123
+ `- status: **${grant.status}**`,
124
+ `- external_id: \`${grant.external_id}\``,
125
+ ``,
126
+ `**Action required if you haven't already:** add this External ID to ` +
127
+ `your IAM role's trust policy under \`Condition.StringEquals.sts:ExternalId\`. ` +
128
+ `Without it, AssumeRole will fail with BYO_ASSUME_ROLE_FAILED.`,
129
+ ``,
130
+ grant.status === "active"
131
+ ? `The readiness probe just passed. You can register your first artifact ` +
132
+ `with \`edgegate_register_byo_artifact\`.`
133
+ : grant.last_verify_error
134
+ ? `The readiness probe FAILED: \`${grant.last_verify_error}\`. Fix the ` +
135
+ `IAM/bucket/KMS configuration, then re-probe with ` +
136
+ `\`edgegate_check_byo_bucket\`.`
137
+ : `Probe outcome pending — run \`edgegate_check_byo_bucket\` to verify.`,
138
+ ].join("\n"),
139
+ },
140
+ ],
141
+ };
142
+ }
143
+ //# sourceMappingURL=register_byo_bucket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register_byo_bucket.js","sourceRoot":"","sources":["../../src/tools/register_byo_bucket.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -269,3 +269,88 @@ export interface PromptPackCreateBody {
269
269
  version: string;
270
270
  content: PromptPackContent;
271
271
  }
272
+ /**
273
+ * Workspace's customer-owned S3 bucket grant. Returned by every grant
274
+ * endpoint (register / get / verify / rotate-external-id).
275
+ *
276
+ * `external_id` is shown in EVERY response — it's the value the customer
277
+ * has to paste into their IAM role trust policy's `sts:ExternalId`
278
+ * condition. We don't treat it like a secret because the trust policy
279
+ * already pins our AWS account as the only principal that can use it.
280
+ *
281
+ * `status` semantics: "active" = last probe passed; "failed" = last probe
282
+ * raised (with `last_verify_error` populated); "revoked" = grant was
283
+ * explicitly deleted (404 on /grants thereafter).
284
+ */
285
+ export interface ByoGrant {
286
+ id: UUID;
287
+ workspace_id: UUID;
288
+ role_arn: string;
289
+ external_id: UUID;
290
+ bucket: string;
291
+ region: string;
292
+ kms_key_id: string | null;
293
+ status: "active" | "revoked" | "failed";
294
+ last_verified_at: string | null;
295
+ last_verify_error: string | null;
296
+ created_at: string;
297
+ updated_at: string;
298
+ }
299
+ /**
300
+ * Request body for POST /v1/workspaces/{ws}/artifacts/byo.
301
+ * Registers an existing S3 URI in the customer's grant-registered bucket
302
+ * as an Artifact pointer. EdgeGate does NOT upload bytes — it HeadObjects
303
+ * the URI to confirm existence + capture size/etag.
304
+ */
305
+ export interface ByoArtifactRegisterRequest {
306
+ s3_uri: string;
307
+ expected_sha256?: string;
308
+ expected_size?: number;
309
+ kind?: string;
310
+ original_filename?: string;
311
+ }
312
+ /**
313
+ * One row from the workspace's append-only `byo_storage_audit` table.
314
+ * `aws_request_id` is the join key for cross-referencing the customer's
315
+ * own CloudTrail. Nullable fields are by design for events that don't
316
+ * produce them (verify_probe has no run_id/artifact_id, etc.).
317
+ */
318
+ export interface ByoAuditEntry {
319
+ id: number;
320
+ event_type: string;
321
+ aws_request_id: string;
322
+ role_arn: string;
323
+ bucket: string;
324
+ s3_key: string | null;
325
+ bytes_read: number | null;
326
+ worker_hostname: string | null;
327
+ outcome: string;
328
+ error_code: string | null;
329
+ artifact_id: UUID | null;
330
+ run_id: UUID | null;
331
+ ts: string;
332
+ }
333
+ /**
334
+ * Paginated audit-log page. `next_cursor === null` means the response
335
+ * contained the last page. Pass the value back as the `cursor` query
336
+ * param to fetch the next page.
337
+ */
338
+ export interface ByoAuditPage {
339
+ entries: ByoAuditEntry[];
340
+ next_cursor: number | null;
341
+ }
342
+ /**
343
+ * Returned by POST /artifacts and POST /artifacts/byo. Mirrors the
344
+ * backend `ArtifactResponse` schema. `storage_url` for BYO artifacts is
345
+ * `byo-s3://{bucket}/{key}` rather than the managed `s3://...` form.
346
+ */
347
+ export interface ArtifactResponse {
348
+ id: UUID;
349
+ kind: string;
350
+ sha256: string;
351
+ size_bytes: number;
352
+ original_filename: string | null;
353
+ storage_url: string;
354
+ created_at: string;
355
+ expires_at: string | null;
356
+ }
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.7.0";
2
- export declare const USER_AGENT = "edgegate-mcp/0.7.0";
1
+ export declare const VERSION = "0.8.0";
2
+ export declare const USER_AGENT = "edgegate-mcp/0.8.0";
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
- export const VERSION = "0.7.0";
1
+ export const VERSION = "0.8.0";
2
2
  export const USER_AGENT = `edgegate-mcp/${VERSION}`;
3
3
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edgegate-mcp",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "MCP server for EdgeGate — set up edge-AI regression gates from Claude Code, Cursor, or Claude Desktop.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edgegate",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Edge-AI regression gates from Claude Code — set up CI, run benchmarks, compare runs, export reports, and fetch audit bundles from any prompt.",
5
5
  "author": "Frozo / EdgeGate",
6
6
  "homepage": "https://edgegate.frozo.ai",
@@ -29,6 +29,7 @@
29
29
  "skills/edgegate-connect-huggingface.md",
30
30
  "skills/edgegate-connect-qaihub.md",
31
31
  "skills/edgegate-workspace-setup.md",
32
- "skills/edgegate-members.md"
32
+ "skills/edgegate-members.md",
33
+ "skills/edgegate-byo-storage.md"
33
34
  ]
34
35
  }