@aexhq/sdk 0.38.1 → 0.39.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.
package/README.md CHANGED
@@ -10,7 +10,7 @@ The package ships:
10
10
 
11
11
  - `Aex` for sessions, one-shot runs, inspect, download, cancel, and delete.
12
12
  - `sessions` / `openSession()` for durable, resumable agent sessions.
13
- - Typed run primitives: `Models`, `Providers`, `Sizes`, `Tool` / `Tools` (skill-tools), `AgentsMd`, `File`, `McpServer`, and `Secret`.
13
+ - Typed run primitives: `Models`, `Providers`, `Sizes`, `Skill`, `Tool` / `Tools`, `AgentsMd`, `File`, `McpServer`, and `Secret`.
14
14
  - A bundled `aex` CLI with the same run, status, events, outputs, download, cancel, delete, and whoami operations.
15
15
 
16
16
  ## Install
@@ -1,7 +1,7 @@
1
1
  export * from "./provider-support.js";
2
2
  export * from "./models.js";
3
3
  export * from "./status.js";
4
- export { AEX_RESERVED_ENV_PREFIX, BUILTIN_TOOL_NAMES, BuiltinTools, DEFAULT_BUILTIN_TOOLS, DEFAULT_OUTPUT_MODE, DEFAULT_RUN_PROVIDER, ENV_VARS_MAX_ENTRIES, ENV_VARS_MAX_TOTAL_BYTES, ENV_VARS_MAX_VALUE_BYTES, OUTPUT_MODES, PLATFORM_PACKAGE_ECOSYSTEMS, Providers, RUN_PROVIDERS, SECRETS_KEY, SECRET_ENV_NAME_PATTERN, SECRET_HANDLE_PATTERN, crossValidateSecretEnvAndValues, packageInstallString, parseInlineSecrets, parseRunLimits, parseRunProvider, parseRunSubmissionRequest, parseRunWebhook, parseSubmission, resolveBuiltinToolNames } from "./submission.js";
4
+ export { AEX_RESERVED_ENV_PREFIX, BUILTIN_TOOL_NAMES, BuiltinTools, DEFAULT_BUILTIN_TOOLS, DEFAULT_OUTPUT_MODE, DEFAULT_RUN_PROVIDER, ENV_VARS_MAX_ENTRIES, ENV_VARS_MAX_TOTAL_BYTES, ENV_VARS_MAX_VALUE_BYTES, OUTPUT_MODES, PLATFORM_PACKAGE_ECOSYSTEMS, Providers, RUN_PROVIDERS, SECRETS_KEY, SECRET_ENV_NAME_PATTERN, SECRET_HANDLE_PATTERN, SKILLS_MAX, SKILLS_TOOL_DEFINITION, SKILLS_TOOL_NAME, crossValidateSecretEnvAndValues, packageInstallString, parseInlineSecrets, parseRunLimits, parseRunProvider, parseRunSubmissionRequest, parseRunWebhook, parseSkills, parseSubmission, resolveBuiltinToolNames } from "./submission.js";
5
5
  export type { BuiltinToolName, JsonPrimitive, JsonValue, OutputMode, ParseRunSubmissionOptions, PlatformEnvironment, PlatformEnvironmentInput, PlatformInlineSecrets, PlatformInjectionConfig, PlatformMcpServerSecret, PlatformNetworking, PlatformOutputCaptureConfig, PlatformPackage, PlatformPackageEcosystem, PlatformPackageInput, PlatformRunSubmissionInput, PlatformRunSubmissionRequest, PlatformSecretEnvEntry, PlatformSubmission, RunLimits, RunMachine, RunProvider, RunWebhookSpec } from "./submission.js";
6
6
  export * from "./runtime-sizes.js";
7
7
  export * from "./runner-event.js";
@@ -1,7 +1,7 @@
1
1
  export * from "./provider-support.js";
2
2
  export * from "./models.js";
3
3
  export * from "./status.js";
4
- export { AEX_RESERVED_ENV_PREFIX, BUILTIN_TOOL_NAMES, BuiltinTools, DEFAULT_BUILTIN_TOOLS, DEFAULT_OUTPUT_MODE, DEFAULT_RUN_PROVIDER, ENV_VARS_MAX_ENTRIES, ENV_VARS_MAX_TOTAL_BYTES, ENV_VARS_MAX_VALUE_BYTES, OUTPUT_MODES, PLATFORM_PACKAGE_ECOSYSTEMS, Providers, RUN_PROVIDERS, SECRETS_KEY, SECRET_ENV_NAME_PATTERN, SECRET_HANDLE_PATTERN, crossValidateSecretEnvAndValues, packageInstallString, parseInlineSecrets, parseRunLimits, parseRunProvider, parseRunSubmissionRequest, parseRunWebhook, parseSubmission, resolveBuiltinToolNames } from "./submission.js";
4
+ export { AEX_RESERVED_ENV_PREFIX, BUILTIN_TOOL_NAMES, BuiltinTools, DEFAULT_BUILTIN_TOOLS, DEFAULT_OUTPUT_MODE, DEFAULT_RUN_PROVIDER, ENV_VARS_MAX_ENTRIES, ENV_VARS_MAX_TOTAL_BYTES, ENV_VARS_MAX_VALUE_BYTES, OUTPUT_MODES, PLATFORM_PACKAGE_ECOSYSTEMS, Providers, RUN_PROVIDERS, SECRETS_KEY, SECRET_ENV_NAME_PATTERN, SECRET_HANDLE_PATTERN, SKILLS_MAX, SKILLS_TOOL_DEFINITION, SKILLS_TOOL_NAME, crossValidateSecretEnvAndValues, packageInstallString, parseInlineSecrets, parseRunLimits, parseRunProvider, parseRunSubmissionRequest, parseRunWebhook, parseSkills, parseSubmission, resolveBuiltinToolNames } from "./submission.js";
5
5
  export * from "./runtime-sizes.js";
6
6
  export * from "./runner-event.js";
7
7
  export * from "./event-envelope.js";
@@ -1,6 +1,6 @@
1
1
  import type { HttpClient } from "./http.js";
2
2
  import type { RunUnit } from "./run-unit.js";
3
- import type { AgentsMdRecord, BillingCheckoutRequest, BillingHostedSession, BillingLedgerPage, BillingLedgerQuery, BillingPortalRequest, BillingSummary, FileRecord, Output, OutputLink, OutputLinkOptions, OutputFileDownload, OutputFileSelector, OutputFileType, OutputQuery, OutputText, ReadOutputTextOptions, Run, RunEvent, RunListPage, RunListQuery, Session, SessionCreateRequest, SessionEvent, SessionListPage, SessionListQuery, SessionMessageAccepted, SessionMessageRequest, SessionMessagesPage, SessionMessagesQuery, SessionStateChangeAccepted, RunWebhookDelivery, SecretRecord, SecretReveal, WebhookSigningSecret, WhoAmI } from "./runtime-types.js";
3
+ import type { AgentsMdRecord, BillingCheckoutRequest, BillingHostedSession, BillingLedgerPage, BillingLedgerQuery, BillingPortalRequest, BillingSummary, FileRecord, Output, OutputLink, OutputLinkOptions, OutputFileDownload, OutputFileSelector, OutputFileType, OutputQuery, OutputText, ReadOutputTextOptions, Run, RunEvent, RunListPage, RunListQuery, Session, SessionCreateRequest, SessionEvent, SessionListPage, SessionListQuery, SessionMessageAccepted, SessionMessageRequest, SessionMessagesPage, SessionMessagesQuery, SessionStateChangeAccepted, RunWebhookDelivery, SecretRecord, SecretReveal, SkillRecord, WebhookSigningSecret, WhoAmI } from "./runtime-types.js";
4
4
  import type { PlatformRunSubmissionInput } from "./submission.js";
5
5
  /**
6
6
  * The single source of truth for SDK<->BFF transport. The SDK class
@@ -197,6 +197,26 @@ export declare function rotateSecret(http: HttpClient, args: {
197
197
  readonly value: string;
198
198
  }): Promise<SecretRecord>;
199
199
  export declare function deleteSecret(http: HttpClient, name: string): Promise<void>;
200
+ /** Result of an `upsertSkill`: the stored record + whether the bytes changed. */
201
+ export interface SkillUpsertResult {
202
+ readonly skill: SkillRecord;
203
+ readonly updated: boolean;
204
+ }
205
+ /**
206
+ * Upsert a workspace skill by name — `PUT /skills/{name}`. The bundle bytes must
207
+ * already exist in the asset store (staged via presign/finalize before this
208
+ * call); the body carries only the metadata. Identical `contentHash` is a no-op
209
+ * (`updated:false`).
210
+ */
211
+ export declare function upsertSkill(http: HttpClient, args: {
212
+ readonly name: string;
213
+ readonly contentHash: string;
214
+ readonly description: string;
215
+ readonly sizeBytes: number;
216
+ }): Promise<SkillUpsertResult>;
217
+ export declare function listSkills(http: HttpClient): Promise<readonly SkillRecord[]>;
218
+ export declare function getSkill(http: HttpClient, name: string): Promise<SkillRecord>;
219
+ export declare function deleteSkill(http: HttpClient, name: string): Promise<void>;
200
220
  export interface AssetUploadResult {
201
221
  readonly assetId: string;
202
222
  readonly contentHash: string;
@@ -902,6 +902,49 @@ function unwrapSecret(result) {
902
902
  }
903
903
  return result;
904
904
  }
905
+ /**
906
+ * Upsert a workspace skill by name — `PUT /skills/{name}`. The bundle bytes must
907
+ * already exist in the asset store (staged via presign/finalize before this
908
+ * call); the body carries only the metadata. Identical `contentHash` is a no-op
909
+ * (`updated:false`).
910
+ */
911
+ export async function upsertSkill(http, args) {
912
+ const result = await http.request(`/api/skills/${encodeURIComponent(args.name)}`, {
913
+ method: "PUT",
914
+ body: JSON.stringify({
915
+ contentHash: args.contentHash,
916
+ description: args.description,
917
+ sizeBytes: args.sizeBytes
918
+ })
919
+ });
920
+ if (result && typeof result === "object" && "skill" in result) {
921
+ const wrapped = result;
922
+ return { skill: wrapped.skill, updated: wrapped.updated === true };
923
+ }
924
+ return { skill: result, updated: true };
925
+ }
926
+ export async function listSkills(http) {
927
+ const result = await http.request("/api/skills");
928
+ if (Array.isArray(result)) {
929
+ return result;
930
+ }
931
+ return result.skills;
932
+ }
933
+ export async function getSkill(http, name) {
934
+ const result = await http.request(`/api/skills/${encodeURIComponent(name)}`);
935
+ return unwrapSkill(result);
936
+ }
937
+ export async function deleteSkill(http, name) {
938
+ await http.request(`/api/skills/${encodeURIComponent(name)}`, {
939
+ method: "DELETE"
940
+ });
941
+ }
942
+ function unwrapSkill(result) {
943
+ if (result && typeof result === "object" && "skill" in result) {
944
+ return result.skill;
945
+ }
946
+ return result;
947
+ }
905
948
  function hasRun(value) {
906
949
  return Boolean(value && typeof value === "object" && "run" in value);
907
950
  }
@@ -3,11 +3,16 @@
3
3
  *
4
4
  * Public composition concepts:
5
5
  *
6
- * - `SkillToolRef` is the wire-level reference to a skill, re-expressed as a
7
- * synthetic no-arg "load-tool" the model calls to pull in the skill's
8
- * `SKILL.md` body. It carries the uploaded bundle's `assetId` (produced by
9
- * the SDK upload path) plus the tool `name` + `description`, and travels in
10
- * `submission.tools`.
6
+ * - `SkillRef` is the PUBLIC wire-level reference to a workspace skill: just
7
+ * `{ kind:"skill", name }`. The binding is BY NAME and mutable — the run
8
+ * resolves the name to the workspace skill's current bytes at submit time.
9
+ * It travels in `submission.skills` (NOT `submission.tools`).
10
+ *
11
+ * - `ResolvedSkillRef` is the BFF-produced, boot-record-only resolution of a
12
+ * `SkillRef`: `{ kind:"skill", assetId, name, description }`. It never
13
+ * appears on the public ingress wire — the resolver fills it before
14
+ * persisting the boot record so the in-container re-parse can read the
15
+ * skill's asset + description without a DB round-trip.
11
16
  *
12
17
  * - `McpServerRef` is the non-secret part of an MCP server declaration:
13
18
  * `name` and `url`. Bearer / cookie / per-request headers travel in
@@ -52,6 +57,13 @@ export declare const SKILL_NAME_PATTERN: RegExp;
52
57
  * because SessionDO reserves that separator for MCP namespace routing.
53
58
  */
54
59
  export declare const TOOL_NAME_PATTERN: RegExp;
60
+ /**
61
+ * Names reserved by the skills subsystem and therefore usable as neither a
62
+ * skill name nor a custom tool name. `skills` is the injected meta-tool (see
63
+ * {@link SKILLS_TOOL_NAME} in `submission.ts`); `skill` is its singular. Both
64
+ * the SDK factories and the BFF `parseSkills` / `parseTools` reject these.
65
+ */
66
+ export declare const SKILL_RESERVED_NAMES: ReadonlySet<string>;
55
67
  /**
56
68
  * Hard caps applied at upload time. The SDK enforces these before
57
69
  * computing the zip hash so a clearly-too-big bundle never wastes
@@ -82,12 +94,25 @@ export declare const SKILL_BUNDLE_LIMITS: {
82
94
  readonly defaultDirMode: 493;
83
95
  };
84
96
  /**
85
- * A skill re-expressed as a TOOL. The model calls this no-arg load-tool to pull
86
- * the skill's `SKILL.md` body into context; the bundle's files are eagerly
87
- * staged to `/workspace/skills/<name>/`. It travels in `submission.tools`
88
- * alongside builtin names and custom {@link ToolRef}s.
97
+ * The PUBLIC wire reference to a workspace skill by NAME, no bytes, no hash.
98
+ * This is what the SDK sends in `submission.skills` and what the idempotency
99
+ * hash covers. The run resolves the name to the workspace skill's CURRENT bytes
100
+ * at submit time (a re-upload under the same name changes what later runs see).
101
+ */
102
+ export interface SkillRef {
103
+ readonly kind: "skill";
104
+ readonly name: string;
105
+ }
106
+ /**
107
+ * BFF-produced, BOOT-RECORD-ONLY resolution of a {@link SkillRef}. The submit-time
108
+ * resolver looks the name up in the workspace skill registry and fills in the
109
+ * current `assetId` + `description`; this is written to the boot record's trusted
110
+ * `submission.resolvedSkills` so the in-container re-parse and the manifest /
111
+ * materialize layers can stage the bundle without a DB round-trip. It NEVER
112
+ * appears on the public ingress wire (rejected by `parseSubmission` unless the
113
+ * caller is a trusted re-parse).
89
114
  */
90
- export interface SkillToolRef {
115
+ export interface ResolvedSkillRef {
91
116
  readonly kind: "skill";
92
117
  readonly assetId: string;
93
118
  readonly name: string;
@@ -3,11 +3,16 @@
3
3
  *
4
4
  * Public composition concepts:
5
5
  *
6
- * - `SkillToolRef` is the wire-level reference to a skill, re-expressed as a
7
- * synthetic no-arg "load-tool" the model calls to pull in the skill's
8
- * `SKILL.md` body. It carries the uploaded bundle's `assetId` (produced by
9
- * the SDK upload path) plus the tool `name` + `description`, and travels in
10
- * `submission.tools`.
6
+ * - `SkillRef` is the PUBLIC wire-level reference to a workspace skill: just
7
+ * `{ kind:"skill", name }`. The binding is BY NAME and mutable — the run
8
+ * resolves the name to the workspace skill's current bytes at submit time.
9
+ * It travels in `submission.skills` (NOT `submission.tools`).
10
+ *
11
+ * - `ResolvedSkillRef` is the BFF-produced, boot-record-only resolution of a
12
+ * `SkillRef`: `{ kind:"skill", assetId, name, description }`. It never
13
+ * appears on the public ingress wire — the resolver fills it before
14
+ * persisting the boot record so the in-container re-parse can read the
15
+ * skill's asset + description without a DB round-trip.
11
16
  *
12
17
  * - `McpServerRef` is the non-secret part of an MCP server declaration:
13
18
  * `name` and `url`. Bearer / cookie / per-request headers travel in
@@ -53,6 +58,13 @@ export const SKILL_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,127}$/;
53
58
  * because SessionDO reserves that separator for MCP namespace routing.
54
59
  */
55
60
  export const TOOL_NAME_PATTERN = SKILL_NAME_PATTERN;
61
+ /**
62
+ * Names reserved by the skills subsystem and therefore usable as neither a
63
+ * skill name nor a custom tool name. `skills` is the injected meta-tool (see
64
+ * {@link SKILLS_TOOL_NAME} in `submission.ts`); `skill` is its singular. Both
65
+ * the SDK factories and the BFF `parseSkills` / `parseTools` reject these.
66
+ */
67
+ export const SKILL_RESERVED_NAMES = new Set(["skills", "skill"]);
56
68
  // ---------------------------------------------------------------------------
57
69
  // Skill bundle limits (uploaded bundles)
58
70
  // ---------------------------------------------------------------------------
@@ -508,6 +508,28 @@ export interface FileRecord {
508
508
  readonly finalizedAt?: string | null;
509
509
  readonly [key: string]: unknown;
510
510
  }
511
+ /**
512
+ * Wire-level metadata record for a workspace skill as returned by the BFF.
513
+ *
514
+ * Workspace skills are named, mutable, by-name-bound bundles: `skill.upload()`
515
+ * upserts one under a stable `name`; a run references it by that name and the
516
+ * platform resolves it to the CURRENT bytes at submit time. This record is
517
+ * METADATA ONLY — the bytes live in the content-addressed asset store keyed by
518
+ * `contentHash`. `version` bumps each time the bytes change under the name.
519
+ */
520
+ export interface SkillRecord {
521
+ readonly id?: string;
522
+ readonly kind?: "skill";
523
+ readonly name: string;
524
+ readonly contentHash: string;
525
+ readonly description: string;
526
+ readonly sizeBytes?: number | null;
527
+ readonly version?: number;
528
+ readonly createdAt?: string;
529
+ readonly updatedAt?: string;
530
+ readonly deletedAt?: string | null;
531
+ readonly [key: string]: unknown;
532
+ }
511
533
  /**
512
534
  * Wire-level record for a workspace secret as returned by the BFF.
513
535
  *
@@ -1,4 +1,4 @@
1
- import type { AgentsMdRef, FileRef, McpServerRef, SkillToolRef, ToolRef } from "./run-config.js";
1
+ import type { AgentsMdRef, FileRef, McpServerRef, ResolvedSkillRef, SkillRef, ToolRef } from "./run-config.js";
2
2
  import { type RuntimeSize } from "./runtime-sizes.js";
3
3
  import { type RunModel } from "./models.js";
4
4
  import { type RuntimeSecurityProfileName } from "./runtime-security-profile.js";
@@ -207,10 +207,9 @@ export declare function optionalPositiveNumber(input: unknown, field: string): n
207
207
  * only the non-secret half; bearer headers travel in
208
208
  * `secrets.mcpServers` keyed by `name`.
209
209
  *
210
- * `tools` is the union of builtin tool names, custom `ToolRef` bundles, and
211
- * skill-tools (`{ kind:"skill", }`); parsing splits them into `tools`,
212
- * `builtinTools`, and `skillTools`. Skill bundles are content-addressed asset
213
- * refs snapshotted into the run-owned prefix before dispatch.
210
+ * `tools` is the union of builtin tool names and custom `ToolRef` bundles;
211
+ * parsing splits them into `tools` and `builtinTools`. Skills are a SEPARATE
212
+ * first-class input on `skills` (by-name refs), NOT part of `tools`.
214
213
  */
215
214
  export interface PlatformSubmission {
216
215
  readonly model: RunModel;
@@ -218,13 +217,21 @@ export interface PlatformSubmission {
218
217
  readonly prompt: readonly string[];
219
218
  readonly tools?: readonly ToolRef[];
220
219
  /**
221
- * Skill-tools: skills re-expressed as synthetic no-arg load-tools. Derived
222
- * from the `tools` union at parse time (the `{ kind:"skill", }` members),
223
- * like {@link builtinTools}. Each becomes a model-visible tool whose call
224
- * returns the skill's `SKILL.md` body; the bundle is eagerly staged to
225
- * `/workspace/skills/<name>/`.
220
+ * Workspace skills referenced BY NAME (`{ kind:"skill", name }`). This is the
221
+ * public ingress shape the SDK sends and the ONLY skill field the idempotency
222
+ * hash covers. The platform resolves each name to the workspace skill's
223
+ * current bytes at submit time; a re-upload under the same name changes what
224
+ * later runs see (the name-only ref, and therefore the hash, is unchanged).
226
225
  */
227
- readonly skillTools?: readonly SkillToolRef[];
226
+ readonly skills?: readonly SkillRef[];
227
+ /**
228
+ * BOOT-RECORD-ONLY, trusted resolution of {@link skills}. The BFF resolver
229
+ * fills this (name → current `assetId` + `description`) before persisting the
230
+ * boot record; the in-container re-parse and manifest/materialize layers read
231
+ * it. Rejected on public ingress (only accepted under a trusted re-parse) and
232
+ * NOT part of the idempotency hash — it is derived, like sealed secrets.
233
+ */
234
+ readonly resolvedSkills?: readonly ResolvedSkillRef[];
228
235
  readonly agentsMd: readonly AgentsMdRef[];
229
236
  readonly files: readonly FileRef[];
230
237
  readonly mcpServers: readonly McpServerRef[];
@@ -418,6 +425,13 @@ export type PlatformRunSubmissionInput = Omit<PlatformRunSubmissionRequest, "wor
418
425
  readonly timeout?: string;
419
426
  };
420
427
  export interface ParseRunSubmissionOptions {
428
+ /**
429
+ * Set by the in-container re-parse of the boot record (`aws-compose.ts`) to
430
+ * accept trusted-only fields the BFF resolver wrote after ingress — currently
431
+ * `submission.resolvedSkills`. On the public ingress path this stays `false`
432
+ * so a caller can never inject a resolved skill (asset + description).
433
+ */
434
+ readonly trustedReparse?: boolean;
421
435
  }
422
436
  export declare function parseRunSubmissionRequest(input: unknown, options?: ParseRunSubmissionOptions): PlatformRunSubmissionRequest;
423
437
  /**
@@ -483,7 +497,9 @@ export declare function parseRunProvider(input: unknown): RunProvider;
483
497
  export declare function enforceCredentialSecretPolicy(secrets: PlatformInlineSecrets, provider: RunProvider, opts?: {
484
498
  readonly inheritsFromParent?: boolean;
485
499
  }): void;
486
- export declare function parseSubmission(input: unknown): PlatformSubmission;
500
+ export declare function parseSubmission(input: unknown, options?: {
501
+ readonly trustedReparse?: boolean;
502
+ }): PlatformSubmission;
487
503
  /** Assistant-output granularity values. Buffered is the platform default. */
488
504
  export declare const OUTPUT_MODES: readonly ["buffered", "stream"];
489
505
  export type OutputMode = (typeof OUTPUT_MODES)[number];
@@ -535,6 +551,42 @@ export declare const BuiltinTools: {
535
551
  * It is the complete closed builtin set.
536
552
  */
537
553
  export declare const DEFAULT_BUILTIN_TOOLS: readonly BuiltinToolName[];
554
+ /**
555
+ * Fixed name of the single skills meta-tool. Deliberately NOT a member of
556
+ * {@link BUILTIN_TOOL_NAMES} (that closed set is the customer-cherry-pickable
557
+ * toggle surface, pinned equal to `HANDS_TOOLS`) — the skills tool is IMPLIED by
558
+ * a run having ≥1 skill, not chosen, and is injected platform-side. Kept in
559
+ * lockstep with {@link SKILL_RESERVED_NAMES} so it can never be shadowed by a
560
+ * custom tool or skill of the same name.
561
+ */
562
+ export declare const SKILLS_TOOL_NAME = "skills";
563
+ /**
564
+ * The single default `skills` meta-tool (list/load) the platform injects when a
565
+ * run references ≥1 workspace skill. Shared by the platform tool composer and
566
+ * kept adjacent to the reserved-name guard so the model-visible contract and the
567
+ * name reservation stay in one place. It replaces the former N per-skill no-arg
568
+ * load-tools with one arg-taking dispatcher.
569
+ */
570
+ export declare const SKILLS_TOOL_DEFINITION: {
571
+ readonly name: "skills";
572
+ readonly description: string;
573
+ readonly input_schema: {
574
+ readonly type: "object";
575
+ readonly properties: {
576
+ readonly action: {
577
+ readonly type: "string";
578
+ readonly enum: readonly ["list", "load"];
579
+ readonly description: "'list' all skills, or 'load' one by name.";
580
+ };
581
+ readonly name: {
582
+ readonly type: "string";
583
+ readonly description: "Skill name to load (required when action='load').";
584
+ };
585
+ };
586
+ readonly required: readonly ["action"];
587
+ readonly additionalProperties: false;
588
+ };
589
+ };
538
590
  /**
539
591
  * Resolve the set of builtin tool NAMES a submission injects, deduplicated and
540
592
  * in {@link BUILTIN_TOOL_NAMES} order.
@@ -548,3 +600,17 @@ export declare const DEFAULT_BUILTIN_TOOLS: readonly BuiltinToolName[];
548
600
  * union is validated ⊆ the closed set so an invalid name can never leak through.
549
601
  */
550
602
  export declare function resolveBuiltinToolNames(includeBuiltinTools: boolean | undefined, toolRefs?: readonly string[]): readonly BuiltinToolName[];
603
+ /**
604
+ * Upper bound on the number of workspace skills a single run may reference.
605
+ * A run's skill list is a discovery surface, not a bulk-mount channel; 64 is
606
+ * generous headroom over any realistic per-run set while capping the meta-tool
607
+ * `list` payload and the submit-time resolution fan-out.
608
+ */
609
+ export declare const SKILLS_MAX = 64;
610
+ /**
611
+ * Parse `submission.skills`: an array of PUBLIC by-name skill refs
612
+ * (`{ kind:"skill", name }`). Validates each `name` against
613
+ * {@link SKILL_NAME_PATTERN}, rejects the `__` MCP separator and the reserved
614
+ * skills names, dedups by name, and bounds the list at {@link SKILLS_MAX}.
615
+ */
616
+ export declare function parseSkills(input: unknown): readonly SkillRef[];